bcachefs: Validate number of counters for accounting keys
authorKent Overstreet <kent.overstreet@linux.dev>
Tue, 25 Mar 2025 14:06:33 +0000 (10:06 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Wed, 26 Mar 2025 20:26:35 +0000 (16:26 -0400)
We weren't checking that accounting keys have the expected number of
accounters. Originally we probably wanted to be flexible on this, but it
doesn't look like that will be required - accounting is extended by
adding new counter types, not more counters to an existing type.

This means we can drop a BUG_ON() that popped once in automated testing,
and the new validation will make that bug easier to track down.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/disk_accounting.c
fs/bcachefs/disk_accounting.h
fs/bcachefs/disk_accounting_format.h
fs/bcachefs/sb-errors_format.h

index b32e91ba8be85fd7e345a58c251928493a5b744d..8a8de61429d87b6dc65c32d89ec61f725345d253 100644 (file)
@@ -135,6 +135,12 @@ static inline bool is_zero(char *start, char *end)
 
 #define field_end(p, member)   (((void *) (&p.member)) + sizeof(p.member))
 
+static const unsigned bch2_accounting_type_nr_counters[] = {
+#define x(f, id, nr)   [BCH_DISK_ACCOUNTING_##f]       = nr,
+       BCH_DISK_ACCOUNTING_TYPES()
+#undef x
+};
+
 int bch2_accounting_validate(struct bch_fs *c, struct bkey_s_c k,
                             struct bkey_validate_context from)
 {
@@ -193,6 +199,11 @@ int bch2_accounting_validate(struct bch_fs *c, struct bkey_s_c k,
        bkey_fsck_err_on(!is_zero(end, (void *) (&acc_k + 1)),
                         c, accounting_key_junk_at_end,
                         "junk at end of accounting key");
+
+       bkey_fsck_err_on(bch2_accounting_counters(k.k) != bch2_accounting_type_nr_counters[acc_k.type],
+                        c, accounting_key_nr_counters_wrong,
+                        "accounting key with %u counters, should be %u",
+                        bch2_accounting_counters(k.k), bch2_accounting_type_nr_counters[acc_k.type]);
 fsck_err:
        return ret;
 }
index f9214e2d13464c683a9f6e399a43c4797c2eeda8..abb1f6206fe9287d779b79bcf37a183263d85651 100644 (file)
@@ -33,10 +33,12 @@ static inline bool bch2_accounting_key_is_zero(struct bkey_s_c_accounting a)
 static inline void bch2_accounting_accumulate(struct bkey_i_accounting *dst,
                                              struct bkey_s_c_accounting src)
 {
-       EBUG_ON(dst->k.u64s != src.k->u64s);
-
-       for (unsigned i = 0; i < bch2_accounting_counters(&dst->k); i++)
+       for (unsigned i = 0;
+            i < min(bch2_accounting_counters(&dst->k),
+                    bch2_accounting_counters(src.k));
+            i++)
                dst->v.d[i] += src.v->d[i];
+
        if (bversion_cmp(dst->k.bversion, src.k->bversion) < 0)
                dst->k.bversion = src.k->bversion;
 }
index 15190196485ff997bfad6ed881e694e6125f69ec..09198ffb57b188ddd8855b67a038970cca819c42 100644 (file)
@@ -95,19 +95,25 @@ static inline bool data_type_is_hidden(enum bch_data_type type)
        }
 }
 
+/*
+ * field 1: name
+ * field 2: id
+ * field 3: number of counters (max 3)
+ */
+
 #define BCH_DISK_ACCOUNTING_TYPES()            \
-       x(nr_inodes,            0)              \
-       x(persistent_reserved,  1)              \
-       x(replicas,             2)              \
-       x(dev_data_type,        3)              \
-       x(compression,          4)              \
-       x(snapshot,             5)              \
-       x(btree,                6)              \
-       x(rebalance_work,       7)              \
-       x(inum,                 8)
+       x(nr_inodes,            0,      1)      \
+       x(persistent_reserved,  1,      1)      \
+       x(replicas,             2,      1)      \
+       x(dev_data_type,        3,      3)      \
+       x(compression,          4,      3)      \
+       x(snapshot,             5,      1)      \
+       x(btree,                6,      1)      \
+       x(rebalance_work,       7,      1)      \
+       x(inum,                 8,      3)
 
 enum disk_accounting_type {
-#define x(f, nr)       BCH_DISK_ACCOUNTING_##f = nr,
+#define x(f, nr, ...)  BCH_DISK_ACCOUNTING_##f = nr,
        BCH_DISK_ACCOUNTING_TYPES()
 #undef x
        BCH_DISK_ACCOUNTING_TYPE_NR,
index 67455beb8358a088ebfe9a49b508cee5d24d5fb3..1736abea9ed1c20716c9868ec8f427e12fbe0a81 100644 (file)
@@ -311,13 +311,14 @@ enum bch_fsck_flags {
        x(accounting_key_replicas_nr_required_bad,              279,    FSCK_AUTOFIX)   \
        x(accounting_key_replicas_devs_unsorted,                280,    FSCK_AUTOFIX)   \
        x(accounting_key_version_0,                             282,    FSCK_AUTOFIX)   \
+       x(accounting_key_nr_counters_wrong,                     307,    FSCK_AUTOFIX)   \
        x(logged_op_but_clean,                                  283,    FSCK_AUTOFIX)   \
        x(compression_opt_not_marked_in_sb,                     295,    FSCK_AUTOFIX)   \
        x(compression_type_not_marked_in_sb,                    296,    FSCK_AUTOFIX)   \
        x(directory_size_mismatch,                              303,    FSCK_AUTOFIX)   \
        x(dirent_cf_name_too_big,                               304,    0)              \
        x(dirent_stray_data_after_cf_name,                      305,    0)              \
-       x(MAX,                                                  307,    0)
+       x(MAX,                                                  308,    0)
 
 enum bch_sb_error_id {
 #define x(t, n, ...) BCH_FSCK_ERR_##t = n,