bcachefs: Fix ec_stripes_read()

Change it to not mark keys that will be overwritten by keys in the
journal - this fixes a bug where we pop an assertion in
bucket_set_stripe() because of a stale pointer - because the stripe that
has the stale pointer has been deleted.

This code could be factored out and used elsewhere, at some point.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Kent Overstreet 2019-07-12 17:08:32 -04:00 committed by Kent Overstreet
parent f516c87272
commit e222d206f2
3 changed files with 82 additions and 11 deletions

View File

@ -1267,10 +1267,10 @@ int bch2_stripes_write(struct bch_fs *c, unsigned flags, bool *wrote)
int bch2_stripes_read(struct bch_fs *c, struct journal_keys *journal_keys)
{
struct journal_key *i;
struct btree_trans trans;
struct btree_iter *iter;
struct bkey_s_c k;
struct btree_iter *btree_iter;
struct journal_iter journal_iter;
struct bkey_s_c btree_k, journal_k, k;
int ret;
ret = bch2_fs_ec_start(c);
@ -1279,10 +1279,41 @@ int bch2_stripes_read(struct bch_fs *c, struct journal_keys *journal_keys)
bch2_trans_init(&trans, c, 0, 0);
for_each_btree_key(&trans, iter, BTREE_ID_EC, POS_MIN, 0, k, ret)
btree_iter = bch2_trans_get_iter(&trans, BTREE_ID_EC, POS_MIN, 0);
journal_iter = bch2_journal_iter_init(journal_keys, BTREE_ID_EC);
btree_k = bch2_btree_iter_peek(btree_iter);
journal_k = bch2_journal_iter_peek(&journal_iter);
while (1) {
if (btree_k.k && journal_k.k) {
int cmp = bkey_cmp(btree_k.k->p, journal_k.k->p);
if (cmp < 0) {
k = btree_k;
btree_k = bch2_btree_iter_next(btree_iter);
} else if (cmp == 0) {
btree_k = bch2_btree_iter_next(btree_iter);
k = journal_k;
journal_k = bch2_journal_iter_next(&journal_iter);
} else {
k = journal_k;
journal_k = bch2_journal_iter_next(&journal_iter);
}
} else if (btree_k.k) {
k = btree_k;
btree_k = bch2_btree_iter_next(btree_iter);
} else if (journal_k.k) {
k = journal_k;
journal_k = bch2_journal_iter_next(&journal_iter);
} else {
break;
}
bch2_mark_key(c, k, 0, NULL, 0,
BCH_BUCKET_MARK_ALLOC_READ|
BCH_BUCKET_MARK_NOATOMIC);
}
ret = bch2_trans_exit(&trans) ?: ret;
if (ret) {
@ -1290,13 +1321,6 @@ int bch2_stripes_read(struct bch_fs *c, struct journal_keys *journal_keys)
return ret;
}
for_each_journal_key(*journal_keys, i)
if (i->btree_id == BTREE_ID_EC)
bch2_mark_key(c, bkey_i_to_s_c(i->k),
0, NULL, 0,
BCH_BUCKET_MARK_ALLOC_READ|
BCH_BUCKET_MARK_NOATOMIC);
return 0;
}

View File

@ -24,6 +24,42 @@
#define QSTR(n) { { { .len = strlen(n) } }, .name = n }
/* iterate over keys read from the journal: */
struct journal_iter bch2_journal_iter_init(struct journal_keys *keys,
enum btree_id id)
{
return (struct journal_iter) {
.keys = keys,
.k = keys->d,
.btree_id = id,
};
}
struct bkey_s_c bch2_journal_iter_peek(struct journal_iter *iter)
{
while (1) {
if (iter->k == iter->keys->d + iter->keys->nr)
return bkey_s_c_null;
if (iter->k->btree_id == iter->btree_id)
return bkey_i_to_s_c(iter->k->k);
iter->k++;
}
return bkey_s_c_null;
}
struct bkey_s_c bch2_journal_iter_next(struct journal_iter *iter)
{
if (iter->k == iter->keys->d + iter->keys->nr)
return bkey_s_c_null;
iter->k++;
return bch2_journal_iter_peek(iter);
}
/* sort and dedup all keys in the journal: */
static void journal_entries_free(struct list_head *list)

View File

@ -18,6 +18,17 @@ struct journal_keys {
#define for_each_journal_key(keys, i) \
for (i = (keys).d; i < (keys).d + (keys).nr; (i)++)
struct journal_iter {
struct journal_keys *keys;
struct journal_key *k;
enum btree_id btree_id;
};
struct journal_iter bch2_journal_iter_init(struct journal_keys *,
enum btree_id);
struct bkey_s_c bch2_journal_iter_peek(struct journal_iter *);
struct bkey_s_c bch2_journal_iter_next(struct journal_iter *);
int bch2_fs_recovery(struct bch_fs *);
int bch2_fs_initialize(struct bch_fs *);