Skip to content

Commit 8a443d3

Browse files
author
Kent Overstreet
committed
bcachefs: Proper refcounting for journal_keys
The btree iterator code overlays keys from the journal until journal replay is finished; since we're now starting copygc/rebalance etc. before replay is finished, this is multithreaded access and thus needs refcounting. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
1 parent 63807d9 commit 8a443d3

6 files changed

Lines changed: 42 additions & 11 deletions

File tree

fs/bcachefs/bcachefs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,8 @@ struct journal_keys {
638638
size_t gap;
639639
size_t nr;
640640
size_t size;
641+
atomic_t ref;
642+
bool initial_ref_held;
641643
};
642644

643645
struct btree_trans_buf {

fs/bcachefs/btree_iter.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2981,7 +2981,8 @@ struct btree_trans *__bch2_trans_get(struct bch_fs *c, unsigned fn_idx)
29812981
trans->fn_idx = fn_idx;
29822982
trans->locking_wait.task = current;
29832983
trans->journal_replay_not_finished =
2984-
!test_bit(JOURNAL_REPLAY_DONE, &c->journal.flags);
2984+
unlikely(!test_bit(JOURNAL_REPLAY_DONE, &c->journal.flags)) &&
2985+
atomic_inc_not_zero(&c->journal_keys.ref);
29852986
closure_init_stack(&trans->ref);
29862987

29872988
s = btree_trans_stats(trans);
@@ -3098,6 +3099,9 @@ void bch2_trans_put(struct btree_trans *trans)
30983099
kfree(trans->fs_usage_deltas);
30993100
}
31003101

3102+
if (unlikely(trans->journal_replay_not_finished))
3103+
bch2_journal_keys_put(c);
3104+
31013105
if (trans->mem_bytes == BTREE_TRANS_MEM_MAX)
31023106
mempool_free(trans->mem, &c->btree_trans_mem_pool);
31033107
else

fs/bcachefs/btree_journal_iter.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ struct bkey_i *bch2_journal_keys_peek_upto(struct bch_fs *c, enum btree_id btree
8080
struct journal_keys *keys = &c->journal_keys;
8181
unsigned iters = 0;
8282
struct journal_key *k;
83+
84+
BUG_ON(*idx > keys->nr);
8385
search:
8486
if (!*idx)
8587
*idx = __bch2_journal_key_search(keys, btree_id, level, pos);
@@ -189,10 +191,12 @@ int bch2_journal_key_insert_take(struct bch_fs *c, enum btree_id id,
189191
/* Since @keys was full, there was no gap: */
190192
memcpy(new_keys.d, keys->d, sizeof(keys->d[0]) * keys->nr);
191193
kvfree(keys->d);
192-
*keys = new_keys;
194+
keys->d = new_keys.d;
195+
keys->nr = new_keys.nr;
196+
keys->size = new_keys.size;
193197

194198
/* And now the gap is at the end: */
195-
keys->gap = keys->nr;
199+
keys->gap = keys->nr;
196200
}
197201

198202
journal_iters_move_gap(c, keys->gap, idx);
@@ -415,10 +419,16 @@ static int journal_sort_key_cmp(const void *_l, const void *_r)
415419
cmp_int(l->journal_offset, r->journal_offset);
416420
}
417421

418-
void bch2_journal_keys_free(struct journal_keys *keys)
422+
void bch2_journal_keys_put(struct bch_fs *c)
419423
{
424+
struct journal_keys *keys = &c->journal_keys;
420425
struct journal_key *i;
421426

427+
BUG_ON(atomic_read(&keys->ref) <= 0);
428+
429+
if (!atomic_dec_and_test(&keys->ref))
430+
return;
431+
422432
move_gap(keys->d, keys->nr, keys->size, keys->gap, keys->nr);
423433
keys->gap = keys->nr;
424434

@@ -429,6 +439,8 @@ void bch2_journal_keys_free(struct journal_keys *keys)
429439
kvfree(keys->d);
430440
keys->d = NULL;
431441
keys->nr = keys->gap = keys->size = 0;
442+
443+
bch2_journal_entries_free(c);
432444
}
433445

434446
static void __journal_keys_sort(struct journal_keys *keys)

fs/bcachefs/btree_journal_iter.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,15 @@ void bch2_btree_and_journal_iter_init_node_iter(struct btree_and_journal_iter *,
4949
struct bch_fs *,
5050
struct btree *);
5151

52-
void bch2_journal_keys_free(struct journal_keys *);
52+
void bch2_journal_keys_put(struct bch_fs *);
53+
54+
static inline void bch2_journal_keys_put_initial(struct bch_fs *c)
55+
{
56+
if (c->journal_keys.initial_ref_held)
57+
bch2_journal_keys_put(c);
58+
c->journal_keys.initial_ref_held = false;
59+
}
60+
5361
void bch2_journal_entries_free(struct bch_fs *);
5462

5563
int bch2_journal_keys_sort(struct bch_fs *);

fs/bcachefs/recovery.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ static int bch2_journal_replay(struct bch_fs *c)
167167
goto err;
168168
}
169169

170+
BUG_ON(!atomic_read(&keys->ref));
171+
170172
for (i = 0; i < keys->nr; i++) {
171173
k = keys_sorted[i];
172174

@@ -188,6 +190,9 @@ static int bch2_journal_replay(struct bch_fs *c)
188190
}
189191
}
190192

193+
if (!c->opts.keep_journal)
194+
bch2_journal_keys_put_initial(c);
195+
191196
replay_now_at(j, j->replay_journal_seq_end);
192197
j->replay_journal_seq = 0;
193198

@@ -909,10 +914,8 @@ int bch2_fs_recovery(struct bch_fs *c)
909914
bch2_flush_fsck_errs(c);
910915

911916
if (!c->opts.keep_journal &&
912-
test_bit(JOURNAL_REPLAY_DONE, &c->journal.flags)) {
913-
bch2_journal_keys_free(&c->journal_keys);
914-
bch2_journal_entries_free(c);
915-
}
917+
test_bit(JOURNAL_REPLAY_DONE, &c->journal.flags))
918+
bch2_journal_keys_put_initial(c);
916919
kfree(clean);
917920

918921
if (!ret && test_bit(BCH_FS_NEED_DELETE_DEAD_SNAPSHOTS, &c->flags)) {

fs/bcachefs/super.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -508,8 +508,8 @@ static void __bch2_fs_free(struct bch_fs *c)
508508
bch2_io_clock_exit(&c->io_clock[WRITE]);
509509
bch2_io_clock_exit(&c->io_clock[READ]);
510510
bch2_fs_compress_exit(c);
511-
bch2_journal_keys_free(&c->journal_keys);
512-
bch2_journal_entries_free(c);
511+
bch2_journal_keys_put_initial(c);
512+
BUG_ON(atomic_read(&c->journal_keys.ref));
513513
bch2_fs_btree_write_buffer_exit(c);
514514
percpu_free_rwsem(&c->mark_lock);
515515
free_percpu(c->online_reserved);
@@ -706,6 +706,8 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts)
706706

707707
init_rwsem(&c->gc_lock);
708708
mutex_init(&c->gc_gens_lock);
709+
atomic_set(&c->journal_keys.ref, 1);
710+
c->journal_keys.initial_ref_held = true;
709711

710712
for (i = 0; i < BCH_TIME_STAT_NR; i++)
711713
bch2_time_stats_init(&c->times[i]);

0 commit comments

Comments
 (0)