summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMark Fasheh <mfasheh@suse.de>2014-08-18 14:01:17 -0700
committerLuis Henriques <luis.henriques@canonical.com>2015-01-05 10:21:14 +0000
commita3871f584e03957c1c5abd9d1442ebec8d24fe8f (patch)
tree002d9b9620295ad0c517deabe3686c4e6c18d58b /fs
parentfbf62d837f1c278f8e367c92d740f3d51bc98166 (diff)
downloadlinux-stable-a3871f584e03957c1c5abd9d1442ebec8d24fe8f.tar.gz
linux-stable-a3871f584e03957c1c5abd9d1442ebec8d24fe8f.tar.bz2
linux-stable-a3871f584e03957c1c5abd9d1442ebec8d24fe8f.zip
btrfs: don't go readonly on existing qgroup items
commit 0b4699dcb65c2cff793210b07f40b98c2d423a43 upstream. btrfs_drop_snapshot() leaves subvolume qgroup items on disk after completion. This can cause problems with snapshot creation. If a new snapshot tries to claim the deleted subvolumes id, btrfs will get -EEXIST from add_qgroup_item() and go read-only. The following commands will reproduce this problem (assume btrfs is on /dev/sda and is mounted at /btrfs) mkfs.btrfs -f /dev/sda mount -t btrfs /dev/sda /btrfs/ btrfs quota enable /btrfs/ btrfs su sna /btrfs/ /btrfs/snap btrfs su de /btrfs/snap sleep 45 umount /btrfs/ mount -t btrfs /dev/sda /btrfs/ We can fix this by catching -EEXIST in add_qgroup_item() and initializing the existing items. We have the problem of orphaned relation items being on disk from an old snapshot but that is outside the scope of this patch. Signed-off-by: Mark Fasheh <mfasheh@suse.de> Signed-off-by: Chris Mason <clm@fb.com> Cc: Sebastiaan L. Zoutendijk <baszoutendijk@gmail.com> Signed-off-by: Luis Henriques <luis.henriques@canonical.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/qgroup.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 3eec914710b2..0e32f21e0868 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -551,9 +551,15 @@ static int add_qgroup_item(struct btrfs_trans_handle *trans,
key.type = BTRFS_QGROUP_INFO_KEY;
key.offset = qgroupid;
+ /*
+ * Avoid a transaction abort by catching -EEXIST here. In that
+ * case, we proceed by re-initializing the existing structure
+ * on disk.
+ */
+
ret = btrfs_insert_empty_item(trans, quota_root, path, &key,
sizeof(*qgroup_info));
- if (ret)
+ if (ret && ret != -EEXIST)
goto out;
leaf = path->nodes[0];
@@ -572,7 +578,7 @@ static int add_qgroup_item(struct btrfs_trans_handle *trans,
key.type = BTRFS_QGROUP_LIMIT_KEY;
ret = btrfs_insert_empty_item(trans, quota_root, path, &key,
sizeof(*qgroup_limit));
- if (ret)
+ if (ret && ret != -EEXIST)
goto out;
leaf = path->nodes[0];