summaryrefslogtreecommitdiff
path: root/libbcachefs/extents.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbcachefs/extents.c')
-rw-r--r--libbcachefs/extents.c89
1 files changed, 37 insertions, 52 deletions
diff --git a/libbcachefs/extents.c b/libbcachefs/extents.c
index c5d1e7cb..9efaa1ff 100644
--- a/libbcachefs/extents.c
+++ b/libbcachefs/extents.c
@@ -588,58 +588,51 @@ out:
return out - buf;
}
-static inline bool dev_latency_better(struct bch_dev *dev1,
- struct bch_dev *dev2)
+static inline bool dev_latency_better(struct bch_fs *c,
+ const struct bch_extent_ptr *ptr1,
+ const struct bch_extent_ptr *ptr2)
{
- unsigned l1 = atomic_read(&dev1->latency[READ]);
- unsigned l2 = atomic_read(&dev2->latency[READ]);
+ struct bch_dev *dev1 = bch_dev_bkey_exists(c, ptr1->dev);
+ struct bch_dev *dev2 = bch_dev_bkey_exists(c, ptr2->dev);
+ u64 l1 = atomic64_read(&dev1->cur_latency[READ]);
+ u64 l2 = atomic64_read(&dev2->cur_latency[READ]);
/* Pick at random, biased in favor of the faster device: */
return bch2_rand_range(l1 + l2) > l1;
}
-static void extent_pick_read_device(struct bch_fs *c,
- struct bkey_s_c_extent e,
- struct bch_devs_mask *avoid,
- struct extent_pick_ptr *pick)
+static int extent_pick_read_device(struct bch_fs *c,
+ struct bkey_s_c_extent e,
+ struct bch_devs_mask *avoid,
+ struct extent_pick_ptr *pick)
{
const struct bch_extent_ptr *ptr;
struct bch_extent_crc_unpacked crc;
+ struct bch_dev *ca;
+ int ret = 0;
extent_for_each_ptr_crc(e, ptr, crc) {
- struct bch_dev *ca = bch_dev_bkey_exists(c, ptr->dev);
+ ca = bch_dev_bkey_exists(c, ptr->dev);
if (ptr->cached && ptr_stale(ca, ptr))
continue;
- if (ca->mi.state == BCH_MEMBER_STATE_FAILED)
+ if (avoid && test_bit(ptr->dev, avoid->d))
continue;
- if (avoid) {
- if (test_bit(ca->dev_idx, avoid->d))
- continue;
-
- if (pick->ca &&
- test_bit(pick->ca->dev_idx, avoid->d))
- goto use;
- }
-
- if (pick->ca && !dev_latency_better(ca, pick->ca))
- continue;
-use:
- if (!percpu_ref_tryget(&ca->io_ref))
+ if (ret && !dev_latency_better(c, ptr, &pick->ptr))
continue;
- if (pick->ca)
- percpu_ref_put(&pick->ca->io_ref);
-
*pick = (struct extent_pick_ptr) {
.ptr = *ptr,
.crc = crc,
- .ca = ca,
};
+
+ ret = 1;
}
+
+ return ret;
}
/* Btree ptrs */
@@ -759,16 +752,12 @@ void bch2_btree_ptr_to_text(struct bch_fs *c, char *buf,
#undef p
}
-struct extent_pick_ptr
-bch2_btree_pick_ptr(struct bch_fs *c, const struct btree *b,
- struct bch_devs_mask *avoid)
+int bch2_btree_pick_ptr(struct bch_fs *c, const struct btree *b,
+ struct bch_devs_mask *avoid,
+ struct extent_pick_ptr *pick)
{
- struct extent_pick_ptr pick = { .ca = NULL };
-
- extent_pick_read_device(c, bkey_i_to_s_c_extent(&b->key),
- avoid, &pick);
-
- return pick;
+ return extent_pick_read_device(c, bkey_i_to_s_c_extent(&b->key),
+ avoid, pick);
}
/* Extents */
@@ -2057,37 +2046,33 @@ void bch2_extent_mark_replicas_cached(struct bch_fs *c,
* Avoid can be NULL, meaning pick any. If there are no non-stale pointers to
* other devices, it will still pick a pointer from avoid.
*/
-void bch2_extent_pick_ptr(struct bch_fs *c, struct bkey_s_c k,
- struct bch_devs_mask *avoid,
- struct extent_pick_ptr *ret)
+int bch2_extent_pick_ptr(struct bch_fs *c, struct bkey_s_c k,
+ struct bch_devs_mask *avoid,
+ struct extent_pick_ptr *pick)
{
- struct bkey_s_c_extent e;
+ int ret;
switch (k.k->type) {
case KEY_TYPE_DELETED:
case KEY_TYPE_DISCARD:
case KEY_TYPE_COOKIE:
- ret->ca = NULL;
- return;
+ return 0;
case KEY_TYPE_ERROR:
- ret->ca = ERR_PTR(-EIO);
- return;
+ return -EIO;
case BCH_EXTENT:
case BCH_EXTENT_CACHED:
- e = bkey_s_c_to_extent(k);
- ret->ca = NULL;
+ ret = extent_pick_read_device(c, bkey_s_c_to_extent(k),
+ avoid, pick);
- extent_pick_read_device(c, bkey_s_c_to_extent(k), avoid, ret);
+ if (!ret && !bkey_extent_is_cached(k.k))
+ ret = -EIO;
- if (!ret->ca && !bkey_extent_is_cached(e.k))
- ret->ca = ERR_PTR(-EIO);
- return;
+ return ret;
case BCH_RESERVATION:
- ret->ca = NULL;
- return;
+ return 0;
default:
BUG();