summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/bcachefs/data_update.c30
-rw-r--r--fs/bcachefs/disk_accounting.c203
-rw-r--r--fs/bcachefs/nocow_locking.c9
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 =