diff options
-rw-r--r-- | fs/bcachefs/data_update.c | 30 | ||||
-rw-r--r-- | fs/bcachefs/disk_accounting.c | 203 | ||||
-rw-r--r-- | fs/bcachefs/nocow_locking.c | 9 |
3 files changed, 134 insertions, 108 deletions
diff --git a/fs/bcachefs/data_update.c b/fs/bcachefs/data_update.c index 6615c868d066..2d367a081445 100644 --- a/fs/bcachefs/data_update.c +++ b/fs/bcachefs/data_update.c @@ -35,7 +35,8 @@ static void bkey_put_dev_refs(struct bch_fs *c, struct bkey_s_c k) struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k); bkey_for_each_ptr(ptrs, ptr) - bch2_dev_put(bch2_dev_have_ref(c, ptr->dev)); + if (ptr->dev != BCH_SB_MEMBER_INVALID) + bch2_dev_put(bch2_dev_have_ref(c, ptr->dev)); } static bool bkey_get_dev_refs(struct bch_fs *c, struct bkey_s_c k) @@ -43,7 +44,8 @@ static bool bkey_get_dev_refs(struct bch_fs *c, struct bkey_s_c k) struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k); bkey_for_each_ptr(ptrs, ptr) { - if (unlikely(!bch2_dev_tryget(c, ptr->dev))) { + if (ptr->dev != BCH_SB_MEMBER_INVALID && + unlikely(!bch2_dev_tryget(c, ptr->dev))) { bkey_for_each_ptr(ptrs, ptr2) { if (ptr2 == ptr) break; @@ -86,15 +88,18 @@ static void trace_io_move_fail2(struct data_update *m, struct bkey_i *insert, const char *msg) { + if (!trace_io_move_fail_enabled()) + return; + struct bch_fs *c = m->op.c; struct bkey_s_c old = bkey_i_to_s_c(m->k.k); - CLASS(printbuf, buf)(); unsigned rewrites_found = 0; - if (!trace_io_move_fail_enabled()) - return; + CLASS(printbuf, buf)(); + printbuf_indent_add_nextline(&buf, 2); prt_str(&buf, msg); + prt_newline(&buf); if (insert) { const union bch_extent_entry *entry; @@ -117,17 +122,17 @@ static void trace_io_move_fail2(struct data_update *m, bch2_data_update_opts_to_text(&buf, c, &m->op.opts, &m->data_opts); - prt_str(&buf, "\nold: "); + prt_str_indented(&buf, "\nold: "); bch2_bkey_val_to_text(&buf, c, old); - prt_str(&buf, "\nnew: "); + prt_str_indented(&buf, "\nnew: "); bch2_bkey_val_to_text(&buf, c, new); - prt_str(&buf, "\nwrote: "); + prt_str_indented(&buf, "\nwrote: "); bch2_bkey_val_to_text(&buf, c, wrote); if (insert) { - prt_str(&buf, "\ninsert: "); + prt_str_indented(&buf, "\ninsert: "); bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(insert)); } @@ -304,7 +309,9 @@ restart_drop_conflicting_replicas: } if (!bkey_val_u64s(&new->k)) { - trace_io_move_fail2(m, k, bkey_i_to_s_c(&new->k_i), insert, "new replicas conflicted:"); + trace_io_move_fail2(m, k, + bkey_i_to_s_c(bch2_keylist_front(&op->insert_keys)), + insert, "new replicas conflicted:"); goto nowork; } @@ -745,7 +752,8 @@ static int can_write_extent(struct bch_fs *c, struct data_update *m) struct bch_devs_mask devs = target_rw_devs(c, BCH_DATA_user, target); darray_for_each(m->op.devs_have, i) - __clear_bit(*i, devs.d); + if (*i != BCH_SB_MEMBER_INVALID) + __clear_bit(*i, devs.d); CLASS(printbuf, buf)(); diff --git a/fs/bcachefs/disk_accounting.c b/fs/bcachefs/disk_accounting.c index 22b2dbe865f3..26dcc826ffcd 100644 --- a/fs/bcachefs/disk_accounting.c +++ b/fs/bcachefs/disk_accounting.c @@ -786,102 +786,10 @@ static struct journal_key *accumulate_and_read_journal_accounting(struct btree_t return ret ? ERR_PTR(ret) : next; } -/* - * At startup time, initialize the in memory accounting from the btree (and - * journal) - */ -int bch2_accounting_read(struct bch_fs *c) +static int accounting_read_mem_fixups(struct btree_trans *trans) { + struct bch_fs *c = trans->c; struct bch_accounting_mem *acc = &c->accounting; - CLASS(btree_trans, trans)(c); - CLASS(printbuf, buf)(); - - /* - * We might run more than once if we rewind to start topology repair or - * btree node scan - and those might cause us to get different results, - * so we can't just skip if we've already run. - * - * Instead, zero out any accounting we have: - */ - scoped_guard(percpu_write, &c->mark_lock) { - darray_for_each(acc->k, e) - percpu_memset(e->v[0], 0, sizeof(u64) * e->nr_counters); - for_each_member_device(c, ca) - percpu_memset(ca->usage, 0, sizeof(*ca->usage)); - percpu_memset(c->usage, 0, sizeof(*c->usage)); - } - - struct journal_keys *keys = &c->journal_keys; - struct journal_key *jk = keys->data; - - move_gap(keys, keys->nr); - - while (jk < &darray_top(*keys) && - __journal_key_cmp(c, BTREE_ID_accounting, 0, POS_MIN, jk) > 0) - jk++; - - struct journal_key *end = jk; - while (end < &darray_top(*keys) && - __journal_key_cmp(c, BTREE_ID_accounting, 0, SPOS_MAX, end) > 0) - end++; - - struct btree_iter iter; - bch2_trans_iter_init(trans, &iter, BTREE_ID_accounting, POS_MIN, - BTREE_ITER_prefetch|BTREE_ITER_all_snapshots); - iter.flags &= ~BTREE_ITER_with_journal; - int ret = for_each_btree_key_continue(trans, iter, - BTREE_ITER_prefetch|BTREE_ITER_all_snapshots, k, ({ - if (k.k->type != KEY_TYPE_accounting) - continue; - - while (jk < end && - __journal_key_cmp(c, BTREE_ID_accounting, 0, k.k->p, jk) > 0) - jk = accumulate_and_read_journal_accounting(trans, jk); - - while (jk < end && - __journal_key_cmp(c, BTREE_ID_accounting, 0, k.k->p, jk) == 0 && - bversion_cmp(journal_key_k(c, jk)->k.bversion, k.k->bversion) <= 0) { - jk->overwritten = true; - jk++; - } - - if (jk < end && - __journal_key_cmp(c, BTREE_ID_accounting, 0, k.k->p, jk) == 0) - jk = accumulate_and_read_journal_accounting(trans, jk); - - 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 (!bch2_accounting_is_mem(&acc_k)) { - struct disk_accounting_pos next_acc; - memset(&next_acc, 0, sizeof(next_acc)); - next_acc.type = acc_k.type + 1; - struct bpos next = bpos_predecessor(disk_accounting_pos_to_bpos(&next_acc)); - if (jk < end) - next = bpos_min(next, journal_key_k(c, jk)->k.p); - - bch2_btree_iter_set_pos(&iter, next); - continue; - } - - accounting_read_key(trans, k); - })); - bch2_trans_iter_exit(&iter); - if (ret) - return ret; - - while (jk < end) - jk = accumulate_and_read_journal_accounting(trans, jk); - - struct journal_key *dst = keys->data; - darray_for_each(*keys, i) - if (!i->overwritten) - *dst++ = *i; - keys->gap = keys->nr = dst - keys->data; - CLASS(printbuf, underflow_err)(); scoped_guard(percpu_write, &c->mark_lock) { @@ -902,7 +810,7 @@ int bch2_accounting_read(struct bch_fs *c) * Remove it, so that if it's re-added it gets re-marked in the * superblock: */ - ret = bch2_is_zero(v, sizeof(v[0]) * i->nr_counters) + int ret = bch2_is_zero(v, sizeof(v[0]) * i->nr_counters) ? -BCH_ERR_remove_disk_accounting_entry : bch2_disk_accounting_validate_late(trans, &acc_k, v, i->nr_counters); @@ -984,7 +892,7 @@ int bch2_accounting_read(struct bch_fs *c) if (underflow_err.pos) { bool print = bch2_count_fsck_err(c, accounting_key_underflow, &underflow_err); unsigned pos = underflow_err.pos; - ret = bch2_run_explicit_recovery_pass(c, &underflow_err, + int ret = bch2_run_explicit_recovery_pass(c, &underflow_err, BCH_RECOVERY_PASS_check_allocations, 0); print |= underflow_err.pos != pos; @@ -994,7 +902,108 @@ int bch2_accounting_read(struct bch_fs *c) return ret; } - return ret; + return 0; +} + +/* + * At startup time, initialize the in memory accounting from the btree (and + * journal) + */ +int bch2_accounting_read(struct bch_fs *c) +{ + struct bch_accounting_mem *acc = &c->accounting; + CLASS(btree_trans, trans)(c); + CLASS(printbuf, buf)(); + + /* + * We might run more than once if we rewind to start topology repair or + * btree node scan - and those might cause us to get different results, + * so we can't just skip if we've already run. + * + * Instead, zero out any accounting we have: + */ + scoped_guard(percpu_write, &c->mark_lock) { + darray_for_each(acc->k, e) + percpu_memset(e->v[0], 0, sizeof(u64) * e->nr_counters); + for_each_member_device(c, ca) + percpu_memset(ca->usage, 0, sizeof(*ca->usage)); + percpu_memset(c->usage, 0, sizeof(*c->usage)); + } + + struct journal_keys *keys = &c->journal_keys; + struct journal_key *jk = keys->data; + + move_gap(keys, keys->nr); + + while (jk < &darray_top(*keys) && + __journal_key_cmp(c, BTREE_ID_accounting, 0, POS_MIN, jk) > 0) + jk++; + + struct journal_key *end = jk; + while (end < &darray_top(*keys) && + __journal_key_cmp(c, BTREE_ID_accounting, 0, SPOS_MAX, end) > 0) + end++; + + struct btree_iter iter; + bch2_trans_iter_init(trans, &iter, BTREE_ID_accounting, POS_MIN, + BTREE_ITER_prefetch|BTREE_ITER_all_snapshots); + iter.flags &= ~BTREE_ITER_with_journal; + int ret = for_each_btree_key_continue(trans, iter, + BTREE_ITER_prefetch|BTREE_ITER_all_snapshots, k, ({ + if (k.k->type != KEY_TYPE_accounting) + continue; + + while (jk < end && + __journal_key_cmp(c, BTREE_ID_accounting, 0, k.k->p, jk) > 0) + jk = accumulate_and_read_journal_accounting(trans, jk); + + while (jk < end && + __journal_key_cmp(c, BTREE_ID_accounting, 0, k.k->p, jk) == 0 && + bversion_cmp(journal_key_k(c, jk)->k.bversion, k.k->bversion) <= 0) { + jk->overwritten = true; + jk++; + } + + if (jk < end && + __journal_key_cmp(c, BTREE_ID_accounting, 0, k.k->p, jk) == 0) + jk = accumulate_and_read_journal_accounting(trans, jk); + + 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 (!bch2_accounting_is_mem(&acc_k)) { + struct disk_accounting_pos next_acc; + memset(&next_acc, 0, sizeof(next_acc)); + next_acc.type = acc_k.type + 1; + struct bpos next = bpos_predecessor(disk_accounting_pos_to_bpos(&next_acc)); + if (jk < end) + next = bpos_min(next, journal_key_k(c, jk)->k.p); + + bch2_btree_iter_set_pos(&iter, next); + continue; + } + + accounting_read_key(trans, k); + })); + bch2_trans_iter_exit(&iter); + if (ret) + return ret; + + while (jk < end) + jk = accumulate_and_read_journal_accounting(trans, jk); + + bch2_trans_unlock(trans); + + struct journal_key *dst = keys->data; + darray_for_each(*keys, i) + if (!i->overwritten) + *dst++ = *i; + keys->gap = keys->nr = dst - keys->data; + + return accounting_read_mem_fixups(trans); } int bch2_dev_usage_remove(struct bch_fs *c, struct bch_dev *ca) diff --git a/fs/bcachefs/nocow_locking.c b/fs/bcachefs/nocow_locking.c index c8907070796f..73e1429979c2 100644 --- a/fs/bcachefs/nocow_locking.c +++ b/fs/bcachefs/nocow_locking.c @@ -95,6 +95,9 @@ void bch2_bkey_nocow_unlock(struct bch_fs *c, struct bkey_s_c k, int flags) struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k); bkey_for_each_ptr(ptrs, ptr) { + if (ptr->dev == BCH_SB_MEMBER_INVALID) + continue; + struct bch_dev *ca = bch2_dev_have_ref(c, ptr->dev); struct bpos bucket = PTR_BUCKET_POS(ca, ptr); @@ -105,6 +108,9 @@ void bch2_bkey_nocow_unlock(struct bch_fs *c, struct bkey_s_c k, int flags) bool bch2_bkey_nocow_trylock(struct bch_fs *c, struct bkey_ptrs_c ptrs, int flags) { bkey_for_each_ptr(ptrs, ptr) { + if (ptr->dev == BCH_SB_MEMBER_INVALID) + continue; + struct bch_dev *ca = bch2_dev_have_ref(c, ptr->dev); struct bpos bucket = PTR_BUCKET_POS(ca, ptr); @@ -144,6 +150,9 @@ void bch2_bkey_nocow_lock(struct bch_fs *c, struct bkey_ptrs_c ptrs, int flags) darray_init(&buckets); bkey_for_each_ptr(ptrs, ptr) { + if (ptr->dev == BCH_SB_MEMBER_INVALID) + continue; + struct bch_dev *ca = bch2_dev_have_ref(c, ptr->dev); u64 b = bucket_to_u64(PTR_BUCKET_POS(ca, ptr)); struct nocow_lock_bucket *l = |