For case where we exceed qgroup limits, we should also report it as an
error.

Signed-off-by: Qu Wenruo <w...@suse.com>
---
 qgroup-verify.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 82 insertions(+)

diff --git a/qgroup-verify.c b/qgroup-verify.c
index f5885589f02c..ab9b5f284d66 100644
--- a/qgroup-verify.c
+++ b/qgroup-verify.c
@@ -54,6 +54,11 @@ struct qgroup_info {
        u64 exclusive_compressed;
 };
 
+struct qgroup_limit {
+       u64 max_rfer;
+       u64 max_excl;
+};
+
 struct qgroup_count {
        u64 qgroupid;
        int subvol_exists;
@@ -63,6 +68,8 @@ struct qgroup_count {
 
        struct qgroup_info info;
 
+       struct qgroup_limit limit;
+
        struct rb_node rb_node;
 
        /* Parents when we are a child group */
@@ -926,6 +933,48 @@ static void read_qgroup_status(struct extent_buffer *eb, 
int slot,
        counts->scan_progress = btrfs_qgroup_status_rescan(eb, status_item);
 }
 
+static void read_qgroup_limit(struct extent_buffer *leaf, int slot)
+{
+       struct btrfs_key key;
+       struct btrfs_qgroup_limit_item *qli;
+       struct qgroup_count *count;
+       u64 flags;
+
+       btrfs_item_key_to_cpu(leaf, &key, slot);
+       qli = btrfs_item_ptr(leaf, slot, struct btrfs_qgroup_limit_item);
+       flags = btrfs_qgroup_limit_flags(leaf, qli);
+
+       /*
+        * Despite the deprecated LIMIT_RSV_* flags, for CMPR (compressed)
+        * limit it doesn't really work either.
+        * As qgroup works at extent level, all numbers are at compressed size
+        * already.
+        */
+       if (flags & (__BTRFS_QGROUP_LIMIT_RSV_RFER |
+                    __BTRFS_QGROUP_LIMIT_RSV_EXCL |
+                    BTRFS_QGROUP_LIMIT_RFER_CMPR |
+                    BTRFS_QGROUP_LIMIT_EXCL_CMPR)) {
+               warning("ignoring deprecated limit flags for qgroup %llu/%llu",
+                       btrfs_qgroup_level(key.offset),
+                       btrfs_qgroup_subvid(key.offset));
+       }
+       count = find_count(key.offset);
+       if (!count) {
+               warning(
+       "found orphan QGROUP_LIMIT item, qgroup %llu/%llu doesn't exist",
+                       btrfs_qgroup_level(key.offset),
+                       btrfs_qgroup_subvid(key.offset));
+               return;
+       }
+       memset(&count->limit, 0, sizeof(struct qgroup_limit));
+       if (flags & BTRFS_QGROUP_LIMIT_MAX_RFER)
+               count->limit.max_rfer =
+                       btrfs_qgroup_limit_max_referenced(leaf, qli);
+       if (flags & BTRFS_QGROUP_LIMIT_MAX_EXCL)
+               count->limit.max_excl =
+                       btrfs_qgroup_limit_max_exclusive(leaf, qli);
+}
+
 static int load_quota_info(struct btrfs_fs_info *info)
 {
        int ret;
@@ -979,6 +1028,10 @@ loop:
                                continue;
                        }
 
+                       if (key.type == BTRFS_QGROUP_LIMIT_KEY) {
+                               read_qgroup_limit(leaf, i);
+                               continue;
+                       }
                        if (key.type == BTRFS_QGROUP_STATUS_KEY) {
                                read_qgroup_status(leaf, i, &counts);
                                continue;
@@ -1308,6 +1361,31 @@ static int report_qgroup_difference(struct qgroup_count 
*count, int verbose)
        return is_different;
 }
 
+bool report_qgroup_limit_error(struct qgroup_count *count)
+{
+       struct qgroup_info *info = &count->info;
+       struct qgroup_limit *limit = &count->limit;
+       bool ret = false;
+
+       if (limit->max_excl && limit->max_excl < info->exclusive) {
+               printf("Exclusive limit for qgroup id: %llu/%llu is exceeded\n",
+                       btrfs_qgroup_level(count->qgroupid),
+                       btrfs_qgroup_subvid(count->qgroupid));
+               print_fields(limit->max_excl, info->exclusive, "limit",
+                            "exclusive");
+               ret = true;
+       }
+       if (limit->max_rfer && limit->max_rfer < info->referenced) {
+               printf("Referenced limit for qgroup id: %llu/%llu is 
exceeded\n",
+                       btrfs_qgroup_level(count->qgroupid),
+                       btrfs_qgroup_subvid(count->qgroupid));
+               print_fields(limit->max_rfer, info->referenced, "limit",
+                            "referenced");
+               ret = true;
+       }
+       return ret;
+}
+
 /*
  * Report qgroups errors
  * Return 0 if nothing wrong.
@@ -1352,6 +1430,10 @@ int report_qgroups(int all)
                        list_add_tail(&c->bad_list, &bad_qgroups);
                        found_err = true;
                }
+               if (report_qgroup_limit_error(c)) {
+                       list_add_tail(&c->bad_list, &bad_qgroups);
+                       found_err = true;
+               }
 
                node = rb_next(node);
        }
-- 
2.19.1

Reply via email to