aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ioctl.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/ioctl.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/ioctl.c')
-rw-r--r--fs/btrfs/ioctl.c22
1 files changed, 19 insertions, 3 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 89c2f6169b92..c0dc05467ce8 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -1706,12 +1706,28 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file,
1706 goto out_drop_sem; 1706 goto out_drop_sem;
1707 1707
1708 root_flags = btrfs_root_flags(&root->root_item); 1708 root_flags = btrfs_root_flags(&root->root_item);
1709 if (flags & BTRFS_SUBVOL_RDONLY) 1709 if (flags & BTRFS_SUBVOL_RDONLY) {
1710 btrfs_set_root_flags(&root->root_item, 1710 btrfs_set_root_flags(&root->root_item,
1711 root_flags | BTRFS_ROOT_SUBVOL_RDONLY); 1711 root_flags | BTRFS_ROOT_SUBVOL_RDONLY);
1712 else 1712 } else {
1713 btrfs_set_root_flags(&root->root_item, 1713 /*
1714 * Block RO -> RW transition if this subvolume is involved in
1715 * send
1716 */
1717 spin_lock(&root->root_item_lock);
1718 if (root->send_in_progress == 0) {
1719 btrfs_set_root_flags(&root->root_item,
1714 root_flags & ~BTRFS_ROOT_SUBVOL_RDONLY); 1720 root_flags & ~BTRFS_ROOT_SUBVOL_RDONLY);
1721 spin_unlock(&root->root_item_lock);
1722 } else {
1723 spin_unlock(&root->root_item_lock);
1724 btrfs_warn(root->fs_info,
1725 "Attempt to set subvolume %llu read-write during send",
1726 root->root_key.objectid);
1727 ret = -EPERM;
1728 goto out_drop_sem;
1729 }
1730 }
1715 1731
1716 trans = btrfs_start_transaction(root, 1); 1732 trans = btrfs_start_transaction(root, 1);
1717 if (IS_ERR(trans)) { 1733 if (IS_ERR(trans)) {