1 From 3324d0547861b16cf436d54abba7052e0c8aa9de Mon Sep 17 00:00:00 2001
2 From: Omar Sandoval <osandov@fb.com>
3 Date: Thu, 4 Jan 2024 11:48:47 -0800
4 Subject: btrfs: avoid copying BTRFS_ROOT_SUBVOL_DEAD flag to snapshot of subvolume being deleted
6 From: Omar Sandoval <osandov@fb.com>
8 commit 3324d0547861b16cf436d54abba7052e0c8aa9de upstream.
10 Sweet Tea spotted a race between subvolume deletion and snapshotting
11 that can result in the root item for the snapshot having the
12 BTRFS_ROOT_SUBVOL_DEAD flag set. The race is:
15 ----------------------------------------------|----------
16 btrfs_delete_subvolume |
17 btrfs_set_root_flags(BTRFS_ROOT_SUBVOL_DEAD)|
19 | down_read(subvol_sem)
22 | create_pending_snapshot
23 | copy root item from source
24 down_write(subvol_sem) |
26 This flag is only checked in send and swap activate, which this would
27 cause to fail mysteriously.
29 create_snapshot() now checks the root refs to reject a deleted
30 subvolume, so we can fix this by locking subvol_sem earlier so that the
31 BTRFS_ROOT_SUBVOL_DEAD flag and the root refs are updated atomically.
33 CC: stable@vger.kernel.org # 4.14+
34 Reported-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
35 Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
36 Reviewed-by: Anand Jain <anand.jain@oracle.com>
37 Signed-off-by: Omar Sandoval <osandov@fb.com>
38 Reviewed-by: David Sterba <dsterba@suse.com>
39 Signed-off-by: David Sterba <dsterba@suse.com>
40 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
42 fs/btrfs/inode.c | 22 +++++++++++++---------
43 1 file changed, 13 insertions(+), 9 deletions(-)
45 --- a/fs/btrfs/inode.c
46 +++ b/fs/btrfs/inode.c
47 @@ -4501,6 +4501,8 @@ int btrfs_delete_subvolume(struct inode
51 + down_write(&fs_info->subvol_sem);
54 * Don't allow to delete a subvolume with send in progress. This is
55 * inside the inode lock so the error handling that has to drop the bit
56 @@ -4512,25 +4514,25 @@ int btrfs_delete_subvolume(struct inode
58 "attempt to delete subvolume %llu during send",
59 dest->root_key.objectid);
64 if (atomic_read(&dest->nr_swapfiles)) {
65 spin_unlock(&dest->root_item_lock);
67 "attempt to delete subvolume %llu with active swapfile",
68 root->root_key.objectid);
73 root_flags = btrfs_root_flags(&dest->root_item);
74 btrfs_set_root_flags(&dest->root_item,
75 root_flags | BTRFS_ROOT_SUBVOL_DEAD);
76 spin_unlock(&dest->root_item_lock);
78 - down_write(&fs_info->subvol_sem);
80 ret = may_destroy_subvol(dest);
85 btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP);
87 @@ -4540,7 +4542,7 @@ int btrfs_delete_subvolume(struct inode
89 ret = btrfs_subvolume_reserve_metadata(root, &block_rsv, 5, true);
94 trans = btrfs_start_transaction(root, 0);
96 @@ -4606,15 +4608,17 @@ out_end_trans:
97 inode->i_flags |= S_DEAD;
99 btrfs_subvolume_release_metadata(root, &block_rsv);
101 - up_write(&fs_info->subvol_sem);
104 spin_lock(&dest->root_item_lock);
105 root_flags = btrfs_root_flags(&dest->root_item);
106 btrfs_set_root_flags(&dest->root_item,
107 root_flags & ~BTRFS_ROOT_SUBVOL_DEAD);
108 spin_unlock(&dest->root_item_lock);
112 + up_write(&fs_info->subvol_sem);
114 d_invalidate(dentry);
115 btrfs_prune_dentries(dest);
116 ASSERT(dest->send_in_progress == 0);