diff options
Diffstat (limited to 'fs/bcachefs/disk_accounting.c')
-rw-r--r-- | fs/bcachefs/disk_accounting.c | 75 |
1 files changed, 40 insertions, 35 deletions
diff --git a/fs/bcachefs/disk_accounting.c b/fs/bcachefs/disk_accounting.c index f96530c70262..5ec57b710501 100644 --- a/fs/bcachefs/disk_accounting.c +++ b/fs/bcachefs/disk_accounting.c @@ -184,6 +184,9 @@ int bch2_accounting_validate(struct bch_fs *c, struct bkey_s_c k, void *end = &acc_k + 1; int ret = 0; + if (acc_k.type >= BCH_DISK_ACCOUNTING_TYPE_NR) + return 0; + bkey_fsck_err_on((from.flags & BCH_VALIDATE_commit) && bversion_zero(k.k->bversion), c, accounting_key_version_0, @@ -762,75 +765,77 @@ int bch2_accounting_read(struct bch_fs *c) iter.flags &= ~BTREE_ITER_with_journal; int ret = for_each_btree_key_continue(trans, iter, BTREE_ITER_prefetch|BTREE_ITER_all_snapshots, k, ({ - struct bkey u; - struct bkey_s_c k = bch2_btree_path_peek_slot_exact(btree_iter_path(trans, &iter), &u); + struct bkey u; + struct bkey_s_c k = bch2_btree_path_peek_slot_exact(btree_iter_path(trans, &iter), &u); - if (k.k->type != KEY_TYPE_accounting) - continue; + if (k.k->type != KEY_TYPE_accounting) + continue; - struct disk_accounting_pos acc_k; - bpos_to_disk_accounting_pos(&acc_k, k.k->p); + struct disk_accounting_pos acc_k; + bpos_to_disk_accounting_pos(&acc_k, k.k->p); - if (acc_k.type >= BCH_DISK_ACCOUNTING_TYPE_NR) - break; + if (acc_k.type >= BCH_DISK_ACCOUNTING_TYPE_NR) + break; - if (!bch2_accounting_is_mem(&acc_k)) { - struct disk_accounting_pos next; - memset(&next, 0, sizeof(next)); - next.type = acc_k.type + 1; - bch2_btree_iter_set_pos(&iter, disk_accounting_pos_to_bpos(&next)); - continue; - } + if (!bch2_accounting_is_mem(&acc_k)) { + struct disk_accounting_pos next; + memset(&next, 0, sizeof(next)); + next.type = acc_k.type + 1; + bch2_btree_iter_set_pos(&iter, disk_accounting_pos_to_bpos(&next)); + continue; + } - accounting_read_key(trans, k); - })); + accounting_read_key(trans, k); + })); bch2_trans_iter_exit(&iter); if (ret) return ret; struct journal_keys *keys = &c->journal_keys; - struct journal_key *dst = keys->data; move_gap(keys, keys->nr); darray_for_each(*keys, i) { - if (i->k->k.type == KEY_TYPE_accounting) { + if (i->overwritten) + continue; + + struct bkey_i *k = journal_key_k(c, i); + + if (k->k.type == KEY_TYPE_accounting) { struct disk_accounting_pos acc_k; - bpos_to_disk_accounting_pos(&acc_k, i->k->k.p); + bpos_to_disk_accounting_pos(&acc_k, k->k.p); if (!bch2_accounting_is_mem(&acc_k)) continue; - struct bkey_s_c k = bkey_i_to_s_c(i->k); unsigned idx = eytzinger0_find(acc->k.data, acc->k.nr, sizeof(acc->k.data[0]), - accounting_pos_cmp, &k.k->p); + accounting_pos_cmp, &k->k.p); bool applied = idx < acc->k.nr && - bversion_cmp(acc->k.data[idx].bversion, k.k->bversion) >= 0; + bversion_cmp(acc->k.data[idx].bversion, k->k.bversion) >= 0; if (applied) continue; - if (i + 1 < &darray_top(*keys) && - i[1].k->k.type == KEY_TYPE_accounting && - !journal_key_cmp(i, i + 1)) { - WARN_ON(bversion_cmp(i[0].k->k.bversion, i[1].k->k.bversion) >= 0); + darray_for_each_from(*keys, j, i + 1) { + if (journal_key_cmp(c, i, j)) + break; - i[1].journal_seq = i[0].journal_seq; + struct bkey_i *n = journal_key_k(c, j); + if (n->k.type == KEY_TYPE_accounting) { + WARN_ON(bversion_cmp(k->k.bversion, n->k.bversion) >= 0); - bch2_accounting_accumulate(bkey_i_to_accounting(i[1].k), - bkey_s_c_to_accounting(k)); - continue; + bch2_accounting_accumulate(bkey_i_to_accounting(k), + bkey_i_to_s_c_accounting(n)); + j->overwritten = true; + } } - ret = accounting_read_key(trans, k); + ret = accounting_read_key(trans, bkey_i_to_s_c(k)); if (ret) return ret; } - - *dst++ = *i; } - keys->gap = keys->nr = dst - keys->data; guard(percpu_write)(&c->mark_lock); |