aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorDavid Sterba <dsterba@suse.cz>2014-04-15 10:41:44 -0400
committerChris Mason <clm@fb.com>2014-06-09 20:20:31 -0400
commit521e0546c970c3d845076f243828fa7abd71edfc (patch)
treee203f19e76c97629173c097e051946e2aeb6ce4a /fs
parent944a4515b27302ac42d5964b7400c72f4d692782 (diff)
btrfs: protect snapshots from deleting during send
The patch "Btrfs: fix protection between send and root deletion" (18f687d538449373c37c) does not actually prevent to delete the snapshot and just takes care during background cleaning, but this seems rather user unfriendly, this patch implements the idea presented in http://www.spinics.net/lists/linux-btrfs/msg30813.html - add an internal root_item flag to denote a dead root - check if the send_in_progress is set and refuse to delete, otherwise set the flag and proceed - check the flag in send similar to the btrfs_root_readonly checks, for all involved roots The root lookup in send via btrfs_read_fs_root_no_name will check if the root is really dead or not. If it is, ENOENT, aborted send. If it's alive, it's protected by send_in_progress, send can continue. CC: Miao Xie <miaox@cn.fujitsu.com> CC: Wang Shilong <wangsl.fnst@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.cz> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/ctree.h11
-rw-r--r--fs/btrfs/ioctl.c30
-rw-r--r--fs/btrfs/send.c14
3 files changed, 53 insertions, 2 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index e6f899dc5e47..f4a439e1a43f 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -756,6 +756,12 @@ struct btrfs_dir_item {
756 756
757#define BTRFS_ROOT_SUBVOL_RDONLY (1ULL << 0) 757#define BTRFS_ROOT_SUBVOL_RDONLY (1ULL << 0)
758 758
759/*
760 * Internal in-memory flag that a subvolume has been marked for deletion but
761 * still visible as a directory
762 */
763#define BTRFS_ROOT_SUBVOL_DEAD (1ULL << 48)
764
759struct btrfs_root_item { 765struct btrfs_root_item {
760 struct btrfs_inode_item inode; 766 struct btrfs_inode_item inode;
761 __le64 generation; 767 __le64 generation;
@@ -2791,6 +2797,11 @@ static inline bool btrfs_root_readonly(struct btrfs_root *root)
2791 return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_RDONLY)) != 0; 2797 return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_RDONLY)) != 0;
2792} 2798}
2793 2799
2800static inline bool btrfs_root_dead(struct btrfs_root *root)
2801{
2802 return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_DEAD)) != 0;
2803}
2804
2794/* struct btrfs_root_backup */ 2805/* struct btrfs_root_backup */
2795BTRFS_SETGET_STACK_FUNCS(backup_tree_root, struct btrfs_root_backup, 2806BTRFS_SETGET_STACK_FUNCS(backup_tree_root, struct btrfs_root_backup,
2796 tree_root, 64); 2807 tree_root, 64);
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 2db12fc3f748..2db3fe12f50d 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2219,6 +2219,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
2219 struct btrfs_ioctl_vol_args *vol_args; 2219 struct btrfs_ioctl_vol_args *vol_args;
2220 struct btrfs_trans_handle *trans; 2220 struct btrfs_trans_handle *trans;
2221 struct btrfs_block_rsv block_rsv; 2221 struct btrfs_block_rsv block_rsv;
2222 u64 root_flags;
2222 u64 qgroup_reserved; 2223 u64 qgroup_reserved;
2223 int namelen; 2224 int namelen;
2224 int ret; 2225 int ret;
@@ -2240,6 +2241,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
2240 if (err) 2241 if (err)
2241 goto out; 2242 goto out;
2242 2243
2244
2243 err = mutex_lock_killable_nested(&dir->i_mutex, I_MUTEX_PARENT); 2245 err = mutex_lock_killable_nested(&dir->i_mutex, I_MUTEX_PARENT);
2244 if (err == -EINTR) 2246 if (err == -EINTR)
2245 goto out_drop_write; 2247 goto out_drop_write;
@@ -2301,6 +2303,27 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
2301 } 2303 }
2302 2304
2303 mutex_lock(&inode->i_mutex); 2305 mutex_lock(&inode->i_mutex);
2306
2307 /*
2308 * Don't allow to delete a subvolume with send in progress. This is
2309 * inside the i_mutex so the error handling that has to drop the bit
2310 * again is not run concurrently.
2311 */
2312 spin_lock(&dest->root_item_lock);
2313 root_flags = btrfs_root_flags(&root->root_item);
2314 if (root->send_in_progress == 0) {
2315 btrfs_set_root_flags(&root->root_item,
2316 root_flags | BTRFS_ROOT_SUBVOL_DEAD);
2317 spin_unlock(&dest->root_item_lock);
2318 } else {
2319 spin_unlock(&dest->root_item_lock);
2320 btrfs_warn(root->fs_info,
2321 "Attempt to delete subvolume %llu during send",
2322 root->root_key.objectid);
2323 err = -EPERM;
2324 goto out_dput;
2325 }
2326
2304 err = d_invalidate(dentry); 2327 err = d_invalidate(dentry);
2305 if (err) 2328 if (err)
2306 goto out_unlock; 2329 goto out_unlock;
@@ -2389,6 +2412,13 @@ out_release:
2389out_up_write: 2412out_up_write:
2390 up_write(&root->fs_info->subvol_sem); 2413 up_write(&root->fs_info->subvol_sem);
2391out_unlock: 2414out_unlock:
2415 if (err) {
2416 spin_lock(&dest->root_item_lock);
2417 root_flags = btrfs_root_flags(&root->root_item);
2418 btrfs_set_root_flags(&root->root_item,
2419 root_flags & ~BTRFS_ROOT_SUBVOL_DEAD);
2420 spin_unlock(&dest->root_item_lock);
2421 }
2392 mutex_unlock(&inode->i_mutex); 2422 mutex_unlock(&inode->i_mutex);
2393 if (!err) { 2423 if (!err) {
2394 shrink_dcache_sb(root->fs_info->sb); 2424 shrink_dcache_sb(root->fs_info->sb);
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 484aacac2c89..c76400dda4df 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -5518,7 +5518,7 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
5518 5518
5519 /* 5519 /*
5520 * The subvolume must remain read-only during send, protect against 5520 * The subvolume must remain read-only during send, protect against
5521 * making it RW. 5521 * making it RW. This also protects against deletion.
5522 */ 5522 */
5523 spin_lock(&send_root->root_item_lock); 5523 spin_lock(&send_root->root_item_lock);
5524 send_root->send_in_progress++; 5524 send_root->send_in_progress++;
@@ -5578,6 +5578,15 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
5578 } 5578 }
5579 5579
5580 sctx->send_root = send_root; 5580 sctx->send_root = send_root;
5581 /*
5582 * Unlikely but possible, if the subvolume is marked for deletion but
5583 * is slow to remove the directory entry, send can still be started
5584 */
5585 if (btrfs_root_dead(sctx->send_root)) {
5586 ret = -EPERM;
5587 goto out;
5588 }
5589
5581 sctx->clone_roots_cnt = arg->clone_sources_count; 5590 sctx->clone_roots_cnt = arg->clone_sources_count;
5582 5591
5583 sctx->send_max_size = BTRFS_SEND_BUF_SIZE; 5592 sctx->send_max_size = BTRFS_SEND_BUF_SIZE;
@@ -5667,7 +5676,8 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
5667 5676
5668 spin_lock(&sctx->parent_root->root_item_lock); 5677 spin_lock(&sctx->parent_root->root_item_lock);
5669 sctx->parent_root->send_in_progress++; 5678 sctx->parent_root->send_in_progress++;
5670 if (!btrfs_root_readonly(sctx->parent_root)) { 5679 if (!btrfs_root_readonly(sctx->parent_root) ||
5680 btrfs_root_dead(sctx->parent_root)) {
5671 spin_unlock(&sctx->parent_root->root_item_lock); 5681 spin_unlock(&sctx->parent_root->root_item_lock);
5672 srcu_read_unlock(&fs_info->subvol_srcu, index); 5682 srcu_read_unlock(&fs_info->subvol_srcu, index);
5673 ret = -EPERM; 5683 ret = -EPERM;