diff options
author | Mark Fasheh <mfasheh@suse.de> | 2014-08-18 17:01:17 -0400 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2014-09-17 16:38:19 -0400 |
commit | 0b4699dcb65c2cff793210b07f40b98c2d423a43 (patch) | |
tree | 5acf4f368d2245924049f2f6276e20f43065c5ad /fs | |
parent | b7831b20f32019b741eb8fe3435c2516e13e0c4a (diff) |
btrfs: don't go readonly on existing qgroup items
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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/qgroup.c | 10 |
1 files changed, 8 insertions, 2 deletions
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 1e4c6e95ab55..cd9717ea8c9d 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, | |||
551 | key.type = BTRFS_QGROUP_INFO_KEY; | 551 | key.type = BTRFS_QGROUP_INFO_KEY; |
552 | key.offset = qgroupid; | 552 | key.offset = qgroupid; |
553 | 553 | ||
554 | /* | ||
555 | * Avoid a transaction abort by catching -EEXIST here. In that | ||
556 | * case, we proceed by re-initializing the existing structure | ||
557 | * on disk. | ||
558 | */ | ||
559 | |||
554 | ret = btrfs_insert_empty_item(trans, quota_root, path, &key, | 560 | ret = btrfs_insert_empty_item(trans, quota_root, path, &key, |
555 | sizeof(*qgroup_info)); | 561 | sizeof(*qgroup_info)); |
556 | if (ret) | 562 | if (ret && ret != -EEXIST) |
557 | goto out; | 563 | goto out; |
558 | 564 | ||
559 | leaf = path->nodes[0]; | 565 | leaf = path->nodes[0]; |
@@ -572,7 +578,7 @@ static int add_qgroup_item(struct btrfs_trans_handle *trans, | |||
572 | key.type = BTRFS_QGROUP_LIMIT_KEY; | 578 | key.type = BTRFS_QGROUP_LIMIT_KEY; |
573 | ret = btrfs_insert_empty_item(trans, quota_root, path, &key, | 579 | ret = btrfs_insert_empty_item(trans, quota_root, path, &key, |
574 | sizeof(*qgroup_limit)); | 580 | sizeof(*qgroup_limit)); |
575 | if (ret) | 581 | if (ret && ret != -EEXIST) |
576 | goto out; | 582 | goto out; |
577 | 583 | ||
578 | leaf = path->nodes[0]; | 584 | leaf = path->nodes[0]; |