summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQu Wenruo <wqu@suse.com>2025-12-04 14:38:23 +1030
committerDavid Sterba <dsterba@suse.com>2025-12-16 22:53:14 +0100
commit68d4b3fa18d72b7f649e83012e7e08f1881f6b75 (patch)
tree73c0623b739e95dfa10e115e52be495fba716419
parent7ee19a59a75e3d5b9ec00499b86af8e2a46fbe86 (diff)
btrfs: qgroup: update all parent qgroups when doing quick inherit
[BUG] There is a bug that if a subvolume has multi-level parent qgroups, and is able to do a quick inherit, only the direct parent qgroup got updated: mkfs.btrfs -f -O quota $dev mount $dev $mnt btrfs subv create $mnt/subv1 btrfs qgroup create 1/100 $mnt btrfs qgroup create 2/100 $mnt btrfs qgroup assign 1/100 2/100 $mnt btrfs qgroup assign 0/256 1/100 $mnt btrfs qgroup show -p --sync $mnt Qgroupid Referenced Exclusive Parent Path -------- ---------- --------- ------ ---- 0/5 16.00KiB 16.00KiB - <toplevel> 0/256 16.00KiB 16.00KiB 1/100 subv1 1/100 16.00KiB 16.00KiB 2/100 2/100<1 member qgroup> 2/100 16.00KiB 16.00KiB - <0 member qgroups> btrfs subv snap -i 1/100 $mnt/subv1 $mnt/snap1 btrfs qgroup show -p --sync $mnt Qgroupid Referenced Exclusive Parent Path -------- ---------- --------- ------ ---- 0/5 16.00KiB 16.00KiB - <toplevel> 0/256 16.00KiB 16.00KiB 1/100 subv1 0/257 16.00KiB 16.00KiB 1/100 snap1 1/100 32.00KiB 32.00KiB 2/100 2/100<1 member qgroup> 2/100 16.00KiB 16.00KiB - <0 member qgroups> # Note that 2/100 is not updated, and qgroup numbers are inconsistent umount $mnt [CAUSE] If the snapshot source subvolume belongs to a parent qgroup, and the new snapshot target is also added to the new same parent qgroup, we allow a quick update without marking qgroup inconsistent. But that quick update only update the parent qgroup, without checking if there is any more parent qgroups. [FIX] Iterate through all parent qgroups during the quick inherit. Reported-by: Boris Burkov <boris@bur.io> Fixes: b20fe56cd285 ("btrfs: qgroup: allow quick inherit if snapshot is created and added to the same parent") Reviewed-by: Boris Burkov <boris@bur.io> Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/qgroup.c18
1 files changed, 16 insertions, 2 deletions
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 904d2a05e63a..206587820fec 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -3208,7 +3208,10 @@ static int qgroup_snapshot_quick_inherit(struct btrfs_fs_info *fs_info,
{
struct btrfs_qgroup *src;
struct btrfs_qgroup *parent;
+ struct btrfs_qgroup *qgroup;
struct btrfs_qgroup_list *list;
+ LIST_HEAD(qgroup_list);
+ const u32 nodesize = fs_info->nodesize;
int nr_parents = 0;
if (btrfs_qgroup_mode(fs_info) != BTRFS_QGROUP_MODE_FULL)
@@ -3248,8 +3251,19 @@ static int qgroup_snapshot_quick_inherit(struct btrfs_fs_info *fs_info,
if (parent->excl != parent->rfer)
return 1;
- parent->excl += fs_info->nodesize;
- parent->rfer += fs_info->nodesize;
+ qgroup_iterator_add(&qgroup_list, parent);
+ list_for_each_entry(qgroup, &qgroup_list, iterator) {
+ qgroup->rfer += nodesize;
+ qgroup->rfer_cmpr += nodesize;
+ qgroup->excl += nodesize;
+ qgroup->excl_cmpr += nodesize;
+ qgroup_dirty(fs_info, qgroup);
+
+ /* Append parent qgroups to @qgroup_list. */
+ list_for_each_entry(list, &qgroup->groups, next_group)
+ qgroup_iterator_add(&qgroup_list, list->group);
+ }
+ qgroup_iterator_clean(&qgroup_list);
return 0;
}