| From 9c7b0c2e8dbfbcd80a71e2cbfe02704f26c185c6 Mon Sep 17 00:00:00 2001 |
| From: Qu Wenruo <wqu@suse.com> |
| Date: Fri, 10 Aug 2018 10:20:26 +0800 |
| Subject: btrfs: qgroup: Dirty all qgroups before rescan |
| |
| From: Qu Wenruo <wqu@suse.com> |
| |
| commit 9c7b0c2e8dbfbcd80a71e2cbfe02704f26c185c6 upstream. |
| |
| [BUG] |
| In the following case, rescan won't zero out the number of qgroup 1/0: |
| |
| $ mkfs.btrfs -fq $DEV |
| $ mount $DEV /mnt |
| |
| $ btrfs quota enable /mnt |
| $ btrfs qgroup create 1/0 /mnt |
| $ btrfs sub create /mnt/sub |
| $ btrfs qgroup assign 0/257 1/0 /mnt |
| |
| $ dd if=/dev/urandom of=/mnt/sub/file bs=1k count=1000 |
| $ btrfs sub snap /mnt/sub /mnt/snap |
| $ btrfs quota rescan -w /mnt |
| $ btrfs qgroup show -pcre /mnt |
| qgroupid rfer excl max_rfer max_excl parent child |
| -------- ---- ---- -------- -------- ------ ----- |
| 0/5 16.00KiB 16.00KiB none none --- --- |
| 0/257 1016.00KiB 16.00KiB none none 1/0 --- |
| 0/258 1016.00KiB 16.00KiB none none --- --- |
| 1/0 1016.00KiB 16.00KiB none none --- 0/257 |
| |
| So far so good, but: |
| |
| $ btrfs qgroup remove 0/257 1/0 /mnt |
| WARNING: quotas may be inconsistent, rescan needed |
| $ btrfs quota rescan -w /mnt |
| $ btrfs qgroup show -pcre /mnt |
| qgoupid rfer excl max_rfer max_excl parent child |
| -------- ---- ---- -------- -------- ------ ----- |
| 0/5 16.00KiB 16.00KiB none none --- --- |
| 0/257 1016.00KiB 16.00KiB none none --- --- |
| 0/258 1016.00KiB 16.00KiB none none --- --- |
| 1/0 1016.00KiB 16.00KiB none none --- --- |
| ^^^^^^^^^^ ^^^^^^^^ not cleared |
| |
| [CAUSE] |
| Before rescan we call qgroup_rescan_zero_tracking() to zero out all |
| qgroups' accounting numbers. |
| |
| However we don't mark all qgroups dirty, but rely on rescan to do so. |
| |
| If we have any high level qgroup without children, it won't be marked |
| dirty during rescan, since we cannot reach that qgroup. |
| |
| This will cause QGROUP_INFO items of childless qgroups never get updated |
| in the quota tree, thus their numbers will stay the same in "btrfs |
| qgroup show" output. |
| |
| [FIX] |
| Just mark all qgroups dirty in qgroup_rescan_zero_tracking(), so even if |
| we have childless qgroups, their QGROUP_INFO items will still get |
| updated during rescan. |
| |
| Reported-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com> |
| CC: stable@vger.kernel.org # 4.4+ |
| Signed-off-by: Qu Wenruo <wqu@suse.com> |
| Reviewed-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com> |
| Tested-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com> |
| Signed-off-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/btrfs/qgroup.c | 1 + |
| 1 file changed, 1 insertion(+) |
| |
| --- a/fs/btrfs/qgroup.c |
| +++ b/fs/btrfs/qgroup.c |
| @@ -2498,6 +2498,7 @@ qgroup_rescan_zero_tracking(struct btrfs |
| qgroup->rfer_cmpr = 0; |
| qgroup->excl = 0; |
| qgroup->excl_cmpr = 0; |
| + qgroup_dirty(fs_info, qgroup); |
| } |
| spin_unlock(&fs_info->qgroup_lock); |
| } |