summaryrefslogtreecommitdiff
path: root/fs/bcachefs/super.c
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2020-05-28 16:06:13 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-22 17:08:40 -0400
commit039fc4c5221f7433d8383e25a7c70b30793b4916 (patch)
tree89321991d534139bbcb0dd259d53905e1edbf6de /fs/bcachefs/super.c
parentbaeed3c3c028359c625fbe92bc5924edaea91ec4 (diff)
bcachefs: Fixes for going RO
Now that interior btree updates are fully transactional, we don't need to write out alloc info in a loop. However, interior btree updates do put more things in the journal, so we still need a loop in the RO sequence. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs/super.c')
-rw-r--r--fs/bcachefs/super.c52
1 files changed, 29 insertions, 23 deletions
diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c
index 3cf75ac1b804..9da64d9d52e5 100644
--- a/fs/bcachefs/super.c
+++ b/fs/bcachefs/super.c
@@ -175,7 +175,7 @@ struct bch_fs *bch2_uuid_to_fs(__uuid_t uuid)
static void __bch2_fs_read_only(struct bch_fs *c)
{
struct bch_dev *ca;
- bool wrote;
+ bool wrote = false;
unsigned i, clean_passes = 0;
int ret;
@@ -200,39 +200,46 @@ static void __bch2_fs_read_only(struct bch_fs *c)
goto nowrote_alloc;
bch_verbose(c, "writing alloc info");
+ /*
+ * This should normally just be writing the bucket read/write clocks:
+ */
+ ret = bch2_stripes_write(c, BTREE_INSERT_NOCHECK_RW, &wrote) ?:
+ bch2_alloc_write(c, BTREE_INSERT_NOCHECK_RW, &wrote);
+ bch_verbose(c, "writing alloc info complete");
- do {
- wrote = false;
+ if (ret && !test_bit(BCH_FS_EMERGENCY_RO, &c->flags))
+ bch2_fs_inconsistent(c, "error writing out alloc info %i", ret);
- ret = bch2_stripes_write(c, BTREE_INSERT_NOCHECK_RW, &wrote) ?:
- bch2_alloc_write(c, BTREE_INSERT_NOCHECK_RW, &wrote);
+ if (ret)
+ goto nowrote_alloc;
- if (ret && !test_bit(BCH_FS_EMERGENCY_RO, &c->flags))
- bch2_fs_inconsistent(c, "error writing out alloc info %i", ret);
+ bch_verbose(c, "flushing journal and stopping allocators");
- if (ret)
- goto nowrote_alloc;
+ bch2_journal_flush_all_pins(&c->journal);
+ set_bit(BCH_FS_ALLOCATOR_STOPPING, &c->flags);
- for_each_member_device(ca, c, i)
- bch2_dev_allocator_quiesce(c, ca);
+ do {
+ clean_passes++;
- bch2_journal_flush_all_pins(&c->journal);
+ if (bch2_journal_flush_all_pins(&c->journal))
+ clean_passes = 0;
/*
- * We need to explicitly wait on btree interior updates to complete
- * before stopping the journal, flushing all journal pins isn't
- * sufficient, because in the BTREE_INTERIOR_UPDATING_ROOT case btree
- * interior updates have to drop their journal pin before they're
- * fully complete:
+ * In flight interior btree updates will generate more journal
+ * updates and btree updates (alloc btree):
*/
- closure_wait_event(&c->btree_interior_update_wait,
- !bch2_btree_interior_updates_nr_pending(c));
+ if (bch2_btree_interior_updates_nr_pending(c)) {
+ closure_wait_event(&c->btree_interior_update_wait,
+ !bch2_btree_interior_updates_nr_pending(c));
+ clean_passes = 0;
+ }
flush_work(&c->btree_interior_update_work);
- clean_passes = wrote ? 0 : clean_passes + 1;
+ if (bch2_journal_flush_all_pins(&c->journal))
+ clean_passes = 0;
} while (clean_passes < 2);
+ bch_verbose(c, "flushing journal and stopping allocators complete");
- bch_verbose(c, "writing alloc info complete");
set_bit(BCH_FS_ALLOC_CLEAN, &c->flags);
nowrote_alloc:
closure_wait_event(&c->btree_interior_update_wait,
@@ -243,11 +250,10 @@ nowrote_alloc:
bch2_dev_allocator_stop(ca);
clear_bit(BCH_FS_ALLOCATOR_RUNNING, &c->flags);
+ clear_bit(BCH_FS_ALLOCATOR_STOPPING, &c->flags);
bch2_fs_journal_stop(&c->journal);
- /* XXX: mark super that alloc info is persistent */
-
/*
* the journal kicks off btree writes via reclaim - wait for in flight
* writes after stopping journal: