mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 16:56:26 +00:00
bcachefs: Fix bch2_gc_accounting_done() locking
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>
This commit is contained in:
parent
f73e6bb6d6
commit
820b9efeb1
@ -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);
|
||||
|
@ -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); \
|
||||
|
Loading…
Reference in New Issue
Block a user