mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-04-03 11:07:10 -04:00
btrfs: check squota parent usage on membership change
We could have detected the quick inherit bug more directly if we had an extra warning about squota hierarchy consistency while modifying the hierarchy. In squotas, the parent usage always simply adds up to the sum of its children, so we can just check for that when changing membership and detect more accounting bugs. Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Boris Burkov <boris@bur.io> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
committed by
David Sterba
parent
a5eb902436
commit
9c46bcda5f
@@ -346,6 +346,42 @@ int btrfs_verify_qgroup_counts(const struct btrfs_fs_info *fs_info, u64 qgroupid
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool squota_check_parent_usage(struct btrfs_fs_info *fs_info, struct btrfs_qgroup *parent)
|
||||
{
|
||||
u64 excl_sum = 0;
|
||||
u64 rfer_sum = 0;
|
||||
u64 excl_cmpr_sum = 0;
|
||||
u64 rfer_cmpr_sum = 0;
|
||||
struct btrfs_qgroup_list *glist;
|
||||
int nr_members = 0;
|
||||
bool mismatch;
|
||||
|
||||
if (btrfs_qgroup_mode(fs_info) != BTRFS_QGROUP_MODE_SIMPLE)
|
||||
return false;
|
||||
if (btrfs_qgroup_level(parent->qgroupid) == 0)
|
||||
return false;
|
||||
|
||||
/* Eligible parent qgroup. Squota; level > 0; empty members list. */
|
||||
list_for_each_entry(glist, &parent->members, next_member) {
|
||||
excl_sum += glist->member->excl;
|
||||
rfer_sum += glist->member->rfer;
|
||||
excl_cmpr_sum += glist->member->excl_cmpr;
|
||||
rfer_cmpr_sum += glist->member->rfer_cmpr;
|
||||
nr_members++;
|
||||
}
|
||||
mismatch = (parent->excl != excl_sum || parent->rfer != rfer_sum ||
|
||||
parent->excl_cmpr != excl_cmpr_sum || parent->rfer_cmpr != excl_cmpr_sum);
|
||||
|
||||
WARN(mismatch,
|
||||
"parent squota qgroup %hu/%llu has mismatched usage from its %d members. "
|
||||
"%llu %llu %llu %llu vs %llu %llu %llu %llu\n",
|
||||
btrfs_qgroup_level(parent->qgroupid),
|
||||
btrfs_qgroup_subvolid(parent->qgroupid), nr_members, parent->excl,
|
||||
parent->rfer, parent->excl_cmpr, parent->rfer_cmpr, excl_sum,
|
||||
rfer_sum, excl_cmpr_sum, rfer_cmpr_sum);
|
||||
return mismatch;
|
||||
}
|
||||
|
||||
__printf(2, 3)
|
||||
static void qgroup_mark_inconsistent(struct btrfs_fs_info *fs_info, const char *fmt, ...)
|
||||
{
|
||||
@@ -1562,6 +1598,7 @@ int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, u64 dst
|
||||
goto out;
|
||||
}
|
||||
ret = quick_update_accounting(fs_info, src, dst, 1);
|
||||
squota_check_parent_usage(fs_info, parent);
|
||||
spin_unlock(&fs_info->qgroup_lock);
|
||||
out:
|
||||
kfree(prealloc);
|
||||
@@ -1618,6 +1655,8 @@ static int __del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src,
|
||||
spin_lock(&fs_info->qgroup_lock);
|
||||
del_relation_rb(fs_info, src, dst);
|
||||
ret = quick_update_accounting(fs_info, src, dst, -1);
|
||||
ASSERT(parent);
|
||||
squota_check_parent_usage(fs_info, parent);
|
||||
spin_unlock(&fs_info->qgroup_lock);
|
||||
}
|
||||
out:
|
||||
|
||||
Reference in New Issue
Block a user