Skip to content

Commit 30e615a

Browse files
author
Kent Overstreet
committed
bcachefs: Fix gap buffer bug in bch2_journal_key_insert_take()
Multiple bug fixes for journal iters: - When the journal keys gap buffer is resized, we have to adjust the iterators for moving the gap to the end - We don't want to rewind iterators to point to the key we just inserted if it's not for the correct btree/level Also, add some new assertions. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
1 parent 2d793e9 commit 30e615a

1 file changed

Lines changed: 45 additions & 10 deletions

File tree

fs/bcachefs/btree_journal_iter.c

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -130,22 +130,45 @@ struct bkey_i *bch2_journal_keys_peek_slot(struct bch_fs *c, enum btree_id btree
130130
return bch2_journal_keys_peek_upto(c, btree_id, level, pos, pos, &idx);
131131
}
132132

133+
static void journal_iter_verify(struct journal_iter *iter)
134+
{
135+
struct journal_keys *keys = iter->keys;
136+
size_t gap_size = keys->size - keys->nr;
137+
138+
BUG_ON(iter->idx >= keys->gap &&
139+
iter->idx < keys->gap + gap_size);
140+
141+
if (iter->idx < keys->size) {
142+
struct journal_key *k = keys->data + iter->idx;
143+
144+
int cmp = cmp_int(k->btree_id, iter->btree_id) ?:
145+
cmp_int(k->level, iter->level);
146+
BUG_ON(cmp < 0);
147+
}
148+
}
149+
133150
static void journal_iters_fix(struct bch_fs *c)
134151
{
135152
struct journal_keys *keys = &c->journal_keys;
136153
/* The key we just inserted is immediately before the gap: */
137154
size_t gap_end = keys->gap + (keys->size - keys->nr);
138-
struct btree_and_journal_iter *iter;
155+
struct journal_key *new_key = &keys->data[keys->gap - 1];
156+
struct journal_iter *iter;
139157

140158
/*
141159
* If an iterator points one after the key we just inserted, decrement
142160
* the iterator so it points at the key we just inserted - if the
143161
* decrement was unnecessary, bch2_btree_and_journal_iter_peek() will
144162
* handle that:
145163
*/
146-
list_for_each_entry(iter, &c->journal_iters, journal.list)
147-
if (iter->journal.idx == gap_end)
148-
iter->journal.idx = keys->gap - 1;
164+
list_for_each_entry(iter, &c->journal_iters, list) {
165+
journal_iter_verify(iter);
166+
if (iter->idx == gap_end &&
167+
new_key->btree_id == iter->btree_id &&
168+
new_key->level == iter->level)
169+
iter->idx = keys->gap - 1;
170+
journal_iter_verify(iter);
171+
}
149172
}
150173

151174
static void journal_iters_move_gap(struct bch_fs *c, size_t old_gap, size_t new_gap)
@@ -192,7 +215,12 @@ int bch2_journal_key_insert_take(struct bch_fs *c, enum btree_id id,
192215
if (idx > keys->gap)
193216
idx -= keys->size - keys->nr;
194217

218+
size_t old_gap = keys->gap;
219+
195220
if (keys->nr == keys->size) {
221+
journal_iters_move_gap(c, old_gap, keys->size);
222+
old_gap = keys->size;
223+
196224
struct journal_keys new_keys = {
197225
.nr = keys->nr,
198226
.size = max_t(size_t, keys->size, 8) * 2,
@@ -216,7 +244,7 @@ int bch2_journal_key_insert_take(struct bch_fs *c, enum btree_id id,
216244
keys->gap = keys->nr;
217245
}
218246

219-
journal_iters_move_gap(c, keys->gap, idx);
247+
journal_iters_move_gap(c, old_gap, idx);
220248

221249
move_gap(keys, idx);
222250

@@ -301,16 +329,21 @@ static void bch2_journal_iter_advance(struct journal_iter *iter)
301329

302330
static struct bkey_s_c bch2_journal_iter_peek(struct journal_iter *iter)
303331
{
304-
struct journal_key *k = iter->keys->data + iter->idx;
332+
journal_iter_verify(iter);
333+
334+
while (iter->idx < iter->keys->size) {
335+
struct journal_key *k = iter->keys->data + iter->idx;
336+
337+
int cmp = cmp_int(k->btree_id, iter->btree_id) ?:
338+
cmp_int(k->level, iter->level);
339+
if (cmp > 0)
340+
break;
341+
BUG_ON(cmp);
305342

306-
while (k < iter->keys->data + iter->keys->size &&
307-
k->btree_id == iter->btree_id &&
308-
k->level == iter->level) {
309343
if (!k->overwritten)
310344
return bkey_i_to_s_c(k->k);
311345

312346
bch2_journal_iter_advance(iter);
313-
k = iter->keys->data + iter->idx;
314347
}
315348

316349
return bkey_s_c_null;
@@ -330,6 +363,8 @@ static void bch2_journal_iter_init(struct bch_fs *c,
330363
iter->level = level;
331364
iter->keys = &c->journal_keys;
332365
iter->idx = bch2_journal_key_search(&c->journal_keys, id, level, pos);
366+
367+
journal_iter_verify(iter);
333368
}
334369

335370
static struct bkey_s_c bch2_journal_iter_peek_btree(struct btree_and_journal_iter *iter)

0 commit comments

Comments
 (0)