]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
bcachefs: Fix bch2_gc_accounting_done() locking
authorKent Overstreet <kent.overstreet@linux.dev>
Thu, 6 Jun 2024 18:33:27 +0000 (14:33 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 14 Jul 2024 23:00:15 +0000 (19:00 -0400)
The transaction commit path takes mark_lock, so we shouldn't be holding
it; use a bpos as an iterator so that we can drop and retake.

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

index 5b1546d1a23d0d93d5ea1d9589a8f6d90fd53b3e..dcdd59249c23eb5f896772da06f5d87a55a74fd4 100644 (file)
@@ -448,18 +448,26 @@ int bch2_gc_accounting_done(struct bch_fs *c)
        struct bch_accounting_mem *acc = &c->accounting;
        struct btree_trans *trans = bch2_trans_get(c);
        struct printbuf buf = PRINTBUF;
+       struct bpos pos = POS_MIN;
        int ret = 0;
 
-       percpu_down_read(&c->mark_lock);
+       percpu_down_write(&c->mark_lock);
+       while (1) {
+               unsigned idx = eytzinger0_find_ge(acc->k.data, acc->k.nr, sizeof(acc->k.data[0]),
+                                                 accounting_pos_cmp, &pos);
+
+               if (idx >= acc->k.nr)
+                       break;
+
+               struct accounting_mem_entry *e = acc->k.data + idx;
+               pos = bpos_successor(e->pos);
 
-       darray_for_each(acc->k, e) {
                struct disk_accounting_pos acc_k;
                bpos_to_disk_accounting_pos(&acc_k, e->pos);
 
                u64 src_v[BCH_ACCOUNTING_MAX_COUNTERS];
                u64 dst_v[BCH_ACCOUNTING_MAX_COUNTERS];
 
-               unsigned idx = e - acc->k.data;
                unsigned nr = e->nr_counters;
                bch2_accounting_mem_read_counters(acc, idx, dst_v, nr, false);
                bch2_accounting_mem_read_counters(acc, idx, src_v, nr, true);
@@ -481,8 +489,10 @@ int bch2_gc_accounting_done(struct bch_fs *c)
                                src_v[j] -= dst_v[j];
 
                        if (fsck_err(trans, accounting_mismatch, "%s", buf.buf)) {
+                               percpu_up_write(&c->mark_lock);
                                ret = commit_do(trans, NULL, NULL, 0,
                                                bch2_disk_accounting_mod(trans, &acc_k, src_v, nr, false));
+                               percpu_down_write(&c->mark_lock);
                                if (ret)
                                        goto err;
 
@@ -504,7 +514,7 @@ int bch2_gc_accounting_done(struct bch_fs *c)
        }
 err:
 fsck_err:
-       percpu_up_read(&c->mark_lock);
+       percpu_up_write(&c->mark_lock);
        printbuf_exit(&buf);
        bch2_trans_put(trans);
        bch_err_fn(c, ret);
index 795f4fc0bab17708fbc584042853b5a6bf6705bc..0541192d7bc02b667e7a9f80222a34ca2f5da10b 100644 (file)
@@ -286,6 +286,17 @@ static inline int eytzinger0_find_gt(void *base, size_t nr, size_t size,
        return eytzinger0_next(idx, nr);
 }
 
+static inline int eytzinger0_find_ge(void *base, size_t nr, size_t size,
+                                    cmp_func_t cmp, const void *search)
+{
+       ssize_t idx = eytzinger0_find_le(base, nr, size, cmp, search);
+
+       if (idx < nr && !cmp(base + idx * size, search))
+               return idx;
+
+       return eytzinger0_next(idx, nr);
+}
+
 #define eytzinger0_find(base, nr, size, _cmp, search)                  \
 ({                                                                     \
        void *_base             = (base);                               \