aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/send.c
diff options
context:
space:
mode:
authorDavid Sterba <dsterba@suse.cz>2013-12-16 11:34:17 -0500
committerChris Mason <clm@fb.com>2014-01-28 16:20:01 -0500
commit2c68653787f91c62f8891209dc1f617088c822e4 (patch)
tree4f17ea8a804b6174de028c85aa3037c6ec6d28de /fs/btrfs/send.c
parenta8d89f5ba0e17622cde8f5ac48ef745a9fb1e13b (diff)
btrfs: Check read-only status of roots during send
All the subvolues that are involved in send must be read-only during the whole operation. The ioctl SUBVOL_SETFLAGS could be used to change the status to read-write and the result of send stream is undefined if the data change unexpectedly. Fix that by adding a refcount for all involved roots and verify that there's no send in progress during SUBVOL_SETFLAGS ioctl call that does read-only -> read-write transition. We need refcounts because there are no restrictions on number of send parallel operations currently run on a single subvolume, be it source, parent or one of the multiple clone sources. Kernel is silent when the RO checks fail and returns EPERM. The same set of checks is done already in userspace before send starts. Signed-off-by: David Sterba <dsterba@suse.cz> Signed-off-by: Josef Bacik <jbacik@fb.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs/btrfs/send.c')
-rw-r--r--fs/btrfs/send.c54
1 files changed, 54 insertions, 0 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index e98c9bc003c8..572e8c758712 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -4769,6 +4769,7 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
4769 struct send_ctx *sctx = NULL; 4769 struct send_ctx *sctx = NULL;
4770 u32 i; 4770 u32 i;
4771 u64 *clone_sources_tmp = NULL; 4771 u64 *clone_sources_tmp = NULL;
4772 int clone_sources_to_rollback = 0;
4772 4773
4773 if (!capable(CAP_SYS_ADMIN)) 4774 if (!capable(CAP_SYS_ADMIN))
4774 return -EPERM; 4775 return -EPERM;
@@ -4777,6 +4778,14 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
4777 fs_info = send_root->fs_info; 4778 fs_info = send_root->fs_info;
4778 4779
4779 /* 4780 /*
4781 * The subvolume must remain read-only during send, protect against
4782 * making it RW.
4783 */
4784 spin_lock(&send_root->root_item_lock);
4785 send_root->send_in_progress++;
4786 spin_unlock(&send_root->root_item_lock);
4787
4788 /*
4780 * This is done when we lookup the root, it should already be complete 4789 * This is done when we lookup the root, it should already be complete
4781 * by the time we get here. 4790 * by the time we get here.
4782 */ 4791 */
@@ -4811,6 +4820,15 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
4811 up_read(&send_root->fs_info->extent_commit_sem); 4820 up_read(&send_root->fs_info->extent_commit_sem);
4812 } 4821 }
4813 4822
4823 /*
4824 * Userspace tools do the checks and warn the user if it's
4825 * not RO.
4826 */
4827 if (!btrfs_root_readonly(send_root)) {
4828 ret = -EPERM;
4829 goto out;
4830 }
4831
4814 arg = memdup_user(arg_, sizeof(*arg)); 4832 arg = memdup_user(arg_, sizeof(*arg));
4815 if (IS_ERR(arg)) { 4833 if (IS_ERR(arg)) {
4816 ret = PTR_ERR(arg); 4834 ret = PTR_ERR(arg);
@@ -4897,6 +4915,15 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
4897 ret = PTR_ERR(clone_root); 4915 ret = PTR_ERR(clone_root);
4898 goto out; 4916 goto out;
4899 } 4917 }
4918 clone_sources_to_rollback = i + 1;
4919 spin_lock(&clone_root->root_item_lock);
4920 clone_root->send_in_progress++;
4921 if (!btrfs_root_readonly(clone_root)) {
4922 spin_unlock(&clone_root->root_item_lock);
4923 ret = -EPERM;
4924 goto out;
4925 }
4926 spin_unlock(&clone_root->root_item_lock);
4900 sctx->clone_roots[i].root = clone_root; 4927 sctx->clone_roots[i].root = clone_root;
4901 } 4928 }
4902 vfree(clone_sources_tmp); 4929 vfree(clone_sources_tmp);
@@ -4912,6 +4939,14 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
4912 ret = PTR_ERR(sctx->parent_root); 4939 ret = PTR_ERR(sctx->parent_root);
4913 goto out; 4940 goto out;
4914 } 4941 }
4942 spin_lock(&sctx->parent_root->root_item_lock);
4943 sctx->parent_root->send_in_progress++;
4944 if (!btrfs_root_readonly(sctx->parent_root)) {
4945 spin_unlock(&sctx->parent_root->root_item_lock);
4946 ret = -EPERM;
4947 goto out;
4948 }
4949 spin_unlock(&sctx->parent_root->root_item_lock);
4915 } 4950 }
4916 4951
4917 /* 4952 /*
@@ -4940,6 +4975,25 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
4940 } 4975 }
4941 4976
4942out: 4977out:
4978 for (i = 0; sctx && i < clone_sources_to_rollback; i++) {
4979 struct btrfs_root *r = sctx->clone_roots[i].root;
4980
4981 spin_lock(&r->root_item_lock);
4982 r->send_in_progress--;
4983 spin_unlock(&r->root_item_lock);
4984 }
4985 if (sctx && !IS_ERR_OR_NULL(sctx->parent_root)) {
4986 struct btrfs_root *r = sctx->parent_root;
4987
4988 spin_lock(&r->root_item_lock);
4989 r->send_in_progress--;
4990 spin_unlock(&r->root_item_lock);
4991 }
4992
4993 spin_lock(&send_root->root_item_lock);
4994 send_root->send_in_progress--;
4995 spin_unlock(&send_root->root_item_lock);
4996
4943 kfree(arg); 4997 kfree(arg);
4944 vfree(clone_sources_tmp); 4998 vfree(clone_sources_tmp);
4945 4999