From: Kent Overstreet Date: Fri, 7 Mar 2025 15:50:49 +0000 (-0500) Subject: bcachefs: Change BCH_MEMBER_STATE_failed semantics X-Git-Tag: v6.15-rc1~146^2~66 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d71e023376d3e56bf2a787c9b5d2600a2db2aabf;p=thirdparty%2Fkernel%2Flinux.git bcachefs: Change BCH_MEMBER_STATE_failed semantics Previously, we woudn't try to read at all from a failed device - that doesn't make much sense, the device may be unhealthy (perhaps taking longer than it should to service reads), but if it's our only option we should still try to read from it. Now, bch2_bkey_pick_read_device() will pick failed devices only if there are no non-failed replicas to read from. Signed-off-by: Kent Overstreet --- diff --git a/fs/bcachefs/extents.c b/fs/bcachefs/extents.c index d9bdf433c118a..032cd0bda017d 100644 --- a/fs/bcachefs/extents.c +++ b/fs/bcachefs/extents.c @@ -79,12 +79,16 @@ void bch2_mark_io_failure(struct bch_io_failures *failed, } } -static inline u64 dev_latency(struct bch_fs *c, unsigned dev) +static inline u64 dev_latency(struct bch_dev *ca) { - struct bch_dev *ca = bch2_dev_rcu(c, dev); return ca ? atomic64_read(&ca->cur_latency[READ]) : S64_MAX; } +static inline int dev_failed(struct bch_dev *ca) +{ + return !ca || ca->mi.state == BCH_MEMBER_STATE_failed; +} + /* * returns true if p1 is better than p2: */ @@ -93,8 +97,16 @@ static inline bool ptr_better(struct bch_fs *c, const struct extent_ptr_decoded p2) { if (likely(!p1.idx && !p2.idx)) { - u64 l1 = dev_latency(c, p1.ptr.dev); - u64 l2 = dev_latency(c, p2.ptr.dev); + struct bch_dev *ca1 = bch2_dev_rcu(c, p1.ptr.dev); + struct bch_dev *ca2 = bch2_dev_rcu(c, p2.ptr.dev); + + int failed_delta = dev_failed(ca1) - dev_failed(ca2); + + if (failed_delta) + return failed_delta < 0; + + u64 l1 = dev_latency(ca1); + u64 l2 = dev_latency(ca2); /* * Square the latencies, to bias more in favor of the faster @@ -170,7 +182,7 @@ int bch2_bkey_pick_read_device(struct bch_fs *c, struct bkey_s_c k, ? f->idx : f->idx + 1; - if (!p.idx && (!ca || !bch2_dev_is_readable(ca))) + if (!p.idx && (!ca || !bch2_dev_is_online(ca))) p.idx++; if (!p.idx && p.has_ec && bch2_force_reconstruct_read) @@ -1012,7 +1024,7 @@ static bool want_cached_ptr(struct bch_fs *c, struct bch_io_opts *opts, struct bch_dev *ca = bch2_dev_rcu_noerror(c, ptr->dev); - return ca && bch2_dev_is_readable(ca) && !dev_ptr_stale_rcu(ca, ptr); + return ca && bch2_dev_is_healthy(ca) && !dev_ptr_stale_rcu(ca, ptr); } void bch2_extent_ptr_set_cached(struct bch_fs *c, diff --git a/fs/bcachefs/sb-members.h b/fs/bcachefs/sb-members.h index df91b02ce5754..38261638a611b 100644 --- a/fs/bcachefs/sb-members.h +++ b/fs/bcachefs/sb-members.h @@ -35,7 +35,7 @@ static inline bool bch2_dev_idx_is_online(struct bch_fs *c, unsigned dev) return ret; } -static inline bool bch2_dev_is_readable(struct bch_dev *ca) +static inline bool bch2_dev_is_healthy(struct bch_dev *ca) { return bch2_dev_is_online(ca) && ca->mi.state != BCH_MEMBER_STATE_failed;