Skip to content

Commit ca43f73

Browse files
author
Kent Overstreet
committed
bcachefs: bch2_btree_write_buffer_flush_going_ro()
The write buffer needs to be specifically flushed when going RO: keys in the journal that haven't yet been moved to the write buffer don't have a journal pin yet. This fixes numerous syzbot bugs, all with symptoms of still doing writes after we've got RO. Signed-off-by: Kent Overstreet <[email protected]>
1 parent 8440da9 commit ca43f73

File tree

3 files changed

+29
-3
lines changed

3 files changed

+29
-3
lines changed

fs/bcachefs/btree_write_buffer.c

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,10 @@ static int bch2_btree_write_buffer_flush_locked(struct btree_trans *trans)
277277
bool accounting_replay_done = test_bit(BCH_FS_accounting_replay_done, &c->flags);
278278
int ret = 0;
279279

280+
ret = bch2_journal_error(&c->journal);
281+
if (ret)
282+
return ret;
283+
280284
bch2_trans_unlock(trans);
281285
bch2_trans_begin(trans);
282286

@@ -491,7 +495,8 @@ static int fetch_wb_keys_from_journal(struct bch_fs *c, u64 seq)
491495
return ret;
492496
}
493497

494-
static int btree_write_buffer_flush_seq(struct btree_trans *trans, u64 seq)
498+
static int btree_write_buffer_flush_seq(struct btree_trans *trans, u64 seq,
499+
bool *did_work)
495500
{
496501
struct bch_fs *c = trans->c;
497502
struct btree_write_buffer *wb = &c->btree_write_buffer;
@@ -502,6 +507,8 @@ static int btree_write_buffer_flush_seq(struct btree_trans *trans, u64 seq)
502507

503508
fetch_from_journal_err = fetch_wb_keys_from_journal(c, seq);
504509

510+
*did_work |= wb->inc.keys.nr || wb->flushing.keys.nr;
511+
505512
/*
506513
* On memory allocation failure, bch2_btree_write_buffer_flush_locked()
507514
* is not guaranteed to empty wb->inc:
@@ -521,17 +528,34 @@ static int bch2_btree_write_buffer_journal_flush(struct journal *j,
521528
struct journal_entry_pin *_pin, u64 seq)
522529
{
523530
struct bch_fs *c = container_of(j, struct bch_fs, journal);
531+
bool did_work = false;
524532

525-
return bch2_trans_run(c, btree_write_buffer_flush_seq(trans, seq));
533+
return bch2_trans_run(c, btree_write_buffer_flush_seq(trans, seq, &did_work));
526534
}
527535

528536
int bch2_btree_write_buffer_flush_sync(struct btree_trans *trans)
529537
{
530538
struct bch_fs *c = trans->c;
539+
bool did_work = false;
531540

532541
trace_and_count(c, write_buffer_flush_sync, trans, _RET_IP_);
533542

534-
return btree_write_buffer_flush_seq(trans, journal_cur_seq(&c->journal));
543+
return btree_write_buffer_flush_seq(trans, journal_cur_seq(&c->journal), &did_work);
544+
}
545+
546+
/*
547+
* The write buffer requires flushing when going RO: keys in the journal for the
548+
* write buffer don't have a journal pin yet
549+
*/
550+
bool bch2_btree_write_buffer_flush_going_ro(struct bch_fs *c)
551+
{
552+
if (bch2_journal_error(&c->journal))
553+
return false;
554+
555+
bool did_work = false;
556+
bch2_trans_run(c, btree_write_buffer_flush_seq(trans,
557+
journal_cur_seq(&c->journal), &did_work));
558+
return did_work;
535559
}
536560

537561
int bch2_btree_write_buffer_flush_nocheck_rw(struct btree_trans *trans)

fs/bcachefs/btree_write_buffer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ static inline bool bch2_btree_write_buffer_must_wait(struct bch_fs *c)
2121

2222
struct btree_trans;
2323
int bch2_btree_write_buffer_flush_sync(struct btree_trans *);
24+
bool bch2_btree_write_buffer_flush_going_ro(struct bch_fs *);
2425
int bch2_btree_write_buffer_flush_nocheck_rw(struct btree_trans *);
2526
int bch2_btree_write_buffer_tryflush(struct btree_trans *);
2627

fs/bcachefs/super.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ static void __bch2_fs_read_only(struct bch_fs *c)
272272
clean_passes++;
273273

274274
if (bch2_btree_interior_updates_flush(c) ||
275+
bch2_btree_write_buffer_flush_going_ro(c) ||
275276
bch2_journal_flush_all_pins(&c->journal) ||
276277
bch2_btree_flush_all_writes(c) ||
277278
seq != atomic64_read(&c->journal.seq)) {

0 commit comments

Comments
 (0)