summaryrefslogtreecommitdiff
path: root/libbcachefs/super.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbcachefs/super.c')
-rw-r--r--libbcachefs/super.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/libbcachefs/super.c b/libbcachefs/super.c
index b8139742..19f96921 100644
--- a/libbcachefs/super.c
+++ b/libbcachefs/super.c
@@ -768,6 +768,15 @@ static const char *__bch2_fs_start(struct bch_fs *c)
if (ret)
goto err;
+ for_each_rw_member(ca, c, i)
+ if (ca->need_prio_write) {
+ ret = bch2_prio_write(ca);
+ if (ret) {
+ percpu_ref_put(&ca->io_ref);
+ goto err;
+ }
+ }
+
bch_verbose(c, "fsck done");
} else {
struct bch_inode_unpacked inode;
@@ -1092,6 +1101,7 @@ static int bch2_dev_alloc(struct bch_fs *c, unsigned dev_idx)
spin_lock_init(&ca->freelist_lock);
spin_lock_init(&ca->prio_buckets_lock);
mutex_init(&ca->heap_lock);
+ mutex_init(&ca->prio_write_lock);
bch2_dev_moving_gc_init(ca);
INIT_WORK(&ca->io_error_work, bch2_nonfatal_io_error_work);
@@ -1265,6 +1275,15 @@ bool bch2_fs_may_start(struct bch_fs *c, int flags)
return true;
}
+/*
+ * Note: this function is also used by the error paths - when a particular
+ * device sees an error, we call it to determine whether we can just set the
+ * device RO, or - if this function returns false - we'll set the whole
+ * filesystem RO:
+ *
+ * XXX: maybe we should be more explicit about whether we're changing state
+ * because we got an error or what have you?
+ */
bool bch2_dev_state_allowed(struct bch_fs *c, struct bch_dev *ca,
enum bch_member_state new_state, int flags)
{
@@ -1273,6 +1292,16 @@ bool bch2_dev_state_allowed(struct bch_fs *c, struct bch_dev *ca,
if (new_state == BCH_MEMBER_STATE_RW)
return true;
+ if (ca->mi.state == BCH_MEMBER_STATE_FAILED)
+ return true;
+
+ /*
+ * If the device is already offline - whatever is going on with it can't
+ * possible make the FS need to go RO:
+ */
+ if (!bch2_dev_is_online(ca))
+ return true;
+
if (ca->mi.has_data &&
!(flags & BCH_FORCE_IF_DATA_DEGRADED))
return false;