Skip to content

Commit 887366f

Browse files
Kaiwen Hugregkh
authored andcommitted
btrfs: prevent subvol with swapfile from being deleted
commit 60021bd upstream. A subvolume with an active swapfile must not be deleted otherwise it would not be possible to deactivate it. After the subvolume is deleted, we cannot swapoff the swapfile in this deleted subvolume because the path is unreachable. The swapfile is still active and holding references, the filesystem cannot be unmounted. The test looks like this: mkfs.btrfs -f $dev > /dev/null mount $dev $mnt btrfs sub create $mnt/subvol touch $mnt/subvol/swapfile chmod 600 $mnt/subvol/swapfile chattr +C $mnt/subvol/swapfile dd if=/dev/zero of=$mnt/subvol/swapfile bs=1K count=4096 mkswap $mnt/subvol/swapfile swapon $mnt/subvol/swapfile btrfs sub delete $mnt/subvol swapoff $mnt/subvol/swapfile # failed: No such file or directory swapoff --all unmount $mnt # target is busy. To prevent above issue, we simply check that whether the subvolume contains any active swapfile, and stop the deleting process. This behavior is like snapshot ioctl dealing with a swapfile. CC: [email protected] # 5.4+ Reviewed-by: Robbie Ko <[email protected]> Reviewed-by: Qu Wenruo <[email protected]> Reviewed-by: Filipe Manana <[email protected]> Signed-off-by: Kaiwen Hu <[email protected]> Signed-off-by: David Sterba <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 4b98799 commit 887366f

File tree

1 file changed

+22
-0
lines changed

1 file changed

+22
-0
lines changed

fs/btrfs/inode.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4450,6 +4450,13 @@ int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry)
44504450
dest->root_key.objectid);
44514451
return -EPERM;
44524452
}
4453+
if (atomic_read(&dest->nr_swapfiles)) {
4454+
spin_unlock(&dest->root_item_lock);
4455+
btrfs_warn(fs_info,
4456+
"attempt to delete subvolume %llu with active swapfile",
4457+
root->root_key.objectid);
4458+
return -EPERM;
4459+
}
44534460
root_flags = btrfs_root_flags(&dest->root_item);
44544461
btrfs_set_root_flags(&dest->root_item,
44554462
root_flags | BTRFS_ROOT_SUBVOL_DEAD);
@@ -10721,8 +10728,23 @@ static int btrfs_swap_activate(struct swap_info_struct *sis, struct file *file,
1072110728
* set. We use this counter to prevent snapshots. We must increment it
1072210729
* before walking the extents because we don't want a concurrent
1072310730
* snapshot to run after we've already checked the extents.
10731+
*
10732+
* It is possible that subvolume is marked for deletion but still not
10733+
* removed yet. To prevent this race, we check the root status before
10734+
* activating the swapfile.
1072410735
*/
10736+
spin_lock(&root->root_item_lock);
10737+
if (btrfs_root_dead(root)) {
10738+
spin_unlock(&root->root_item_lock);
10739+
10740+
btrfs_exclop_finish(fs_info);
10741+
btrfs_warn(fs_info,
10742+
"cannot activate swapfile because subvolume %llu is being deleted",
10743+
root->root_key.objectid);
10744+
return -EPERM;
10745+
}
1072510746
atomic_inc(&root->nr_swapfiles);
10747+
spin_unlock(&root->root_item_lock);
1072610748

1072710749
isize = ALIGN_DOWN(inode->i_size, fs_info->sectorsize);
1072810750

0 commit comments

Comments
 (0)