summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/qgroup.c39
1 files changed, 39 insertions, 0 deletions
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 206587820fec..3a74759b59ee 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -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 @@ delete_item:
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: