]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bcachefs: Coalesce accounting in trans commit
authorKent Overstreet <kent.overstreet@linux.dev>
Sat, 17 May 2025 00:43:18 +0000 (20:43 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Thu, 22 May 2025 00:15:06 +0000 (20:15 -0400)
Accounting has gotten quite heavy, and there's lots of redundancy in
accounting updates within a transaction, as we often add/delete multiple
extents that touch the same accountign counters.

This will reduce the amount of data that we journal, and reduce pressure
downstream on the btree write buffer.

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

index 088b015fc198fc02ffd471a4e9d3bd79d8e7f54c..9f20db560eab2c99d872ed0a182daa8f5ca2be24 100644 (file)
@@ -68,23 +68,31 @@ static const char * const disk_accounting_type_strs[] = {
        NULL
 };
 
-static inline void accounting_key_init(struct bkey_i *k, struct disk_accounting_pos *pos,
-                                      s64 *d, unsigned nr)
+static inline void __accounting_key_init(struct bkey_i *k, struct bpos pos,
+                                        s64 *d, unsigned nr)
 {
        struct bkey_i_accounting *acc = bkey_accounting_init(k);
 
-       acc->k.p = disk_accounting_pos_to_bpos(pos);
+       acc->k.p = pos;
        set_bkey_val_u64s(&acc->k, sizeof(struct bch_accounting) / sizeof(u64) + nr);
 
        memcpy_u64s_small(acc->v.d, d, nr);
 }
 
+static inline void accounting_key_init(struct bkey_i *k, struct disk_accounting_pos *pos,
+                                      s64 *d, unsigned nr)
+{
+       return __accounting_key_init(k, disk_accounting_pos_to_bpos(pos), d, nr);
+}
+
 static int bch2_accounting_update_sb_one(struct bch_fs *, struct bpos);
 
 int bch2_disk_accounting_mod(struct btree_trans *trans,
                             struct disk_accounting_pos *k,
                             s64 *d, unsigned nr, bool gc)
 {
+       BUG_ON(nr > BCH_ACCOUNTING_MAX_COUNTERS);
+
        /* Normalize: */
        switch (k->type) {
        case BCH_DISK_ACCOUNTING_replicas:
@@ -92,22 +100,32 @@ int bch2_disk_accounting_mod(struct btree_trans *trans,
                break;
        }
 
-       BUG_ON(nr > BCH_ACCOUNTING_MAX_COUNTERS);
+       struct bpos pos = disk_accounting_pos_to_bpos(k);
 
        if (likely(!gc)) {
-               unsigned u64s = sizeof(struct bkey_i_accounting) / sizeof(u64) + nr;
-               struct bkey_i_accounting *a =
-                       bch2_trans_subbuf_alloc(trans, &trans->accounting, u64s);
+               struct bkey_i_accounting *a;
+
+               for (a = btree_trans_subbuf_base(trans, &trans->accounting);
+                    a != btree_trans_subbuf_top(trans, &trans->accounting);
+                    a = (void *) bkey_next(&a->k_i))
+                       if (bpos_eq(a->k.p, pos)) {
+                               BUG_ON(nr != bch2_accounting_counters(&a->k));
+                               acc_u64s(a->v.d, d, nr);
+                               return 0;
+                       }
+
+               unsigned u64s = sizeof(*a) / sizeof(u64) + nr;
+               a = bch2_trans_subbuf_alloc(trans, &trans->accounting, u64s);
                int ret = PTR_ERR_OR_ZERO(a);
                if (ret)
                        return ret;
 
-               accounting_key_init(&a->k_i, k, d, nr);
+               __accounting_key_init(&a->k_i, pos, d, nr);
                return 0;
        } else {
                struct { __BKEY_PADDED(k, BCH_ACCOUNTING_MAX_COUNTERS); } k_i;
 
-               accounting_key_init(&k_i.k, k, d, nr);
+               __accounting_key_init(&k_i.k, pos, d, nr);
 
                int ret = bch2_accounting_mem_add(trans, bkey_i_to_s_c_accounting(&k_i.k), true);
                if (ret == -BCH_ERR_btree_insert_need_mark_replicas)