Skip to content

Commit 5bd95a3

Browse files
koverstreetKent Overstreet
authored andcommitted
bcachefs: new avoid mechanism for io retries
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
1 parent 4779932 commit 5bd95a3

File tree

6 files changed

+77
-38
lines changed

6 files changed

+77
-38
lines changed

fs/bcachefs/btree_io.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,11 +1345,9 @@ static void btree_node_read_work(struct work_struct *work)
13451345
struct bch_dev *ca = bch_dev_bkey_exists(c, rb->pick.ptr.dev);
13461346
struct btree *b = rb->bio.bi_private;
13471347
struct bio *bio = &rb->bio;
1348-
struct bch_devs_mask avoid;
1348+
struct bch_io_failures failed = { .nr = 0 };
13491349
bool can_retry;
13501350

1351-
memset(&avoid, 0, sizeof(avoid));
1352-
13531351
goto start;
13541352
while (1) {
13551353
bch_info(c, "retrying read");
@@ -1371,8 +1369,9 @@ static void btree_node_read_work(struct work_struct *work)
13711369
percpu_ref_put(&ca->io_ref);
13721370
rb->have_ioref = false;
13731371

1374-
__set_bit(rb->pick.ptr.dev, avoid.d);
1375-
can_retry = bch2_btree_pick_ptr(c, b, &avoid, &rb->pick) > 0;
1372+
bch2_mark_io_failure(&failed, &rb->pick);
1373+
1374+
can_retry = bch2_btree_pick_ptr(c, b, &failed, &rb->pick) > 0;
13761375

13771376
if (!bio->bi_status &&
13781377
!bch2_btree_node_read_done(c, b, can_retry))

fs/bcachefs/extents.c

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -519,12 +519,45 @@ static size_t extent_print_ptrs(struct bch_fs *c, char *buf,
519519
return out - buf;
520520
}
521521

522-
static inline bool dev_latency_better(struct bch_fs *c,
523-
const struct bch_extent_ptr *ptr1,
524-
const struct bch_extent_ptr *ptr2)
522+
static struct bch_dev_io_failures *dev_io_failures(struct bch_io_failures *f,
523+
unsigned dev)
525524
{
526-
struct bch_dev *dev1 = bch_dev_bkey_exists(c, ptr1->dev);
527-
struct bch_dev *dev2 = bch_dev_bkey_exists(c, ptr2->dev);
525+
struct bch_dev_io_failures *i;
526+
527+
for (i = f->devs; i < f->devs + f->nr; i++)
528+
if (i->dev == dev)
529+
return i;
530+
531+
return NULL;
532+
}
533+
534+
void bch2_mark_io_failure(struct bch_io_failures *failed,
535+
struct extent_ptr_decoded *p)
536+
{
537+
struct bch_dev_io_failures *f = dev_io_failures(failed, p->ptr.dev);
538+
539+
if (!f) {
540+
BUG_ON(failed->nr >= ARRAY_SIZE(failed->devs));
541+
542+
f = &failed->devs[failed->nr++];
543+
f->dev = p->ptr.dev;
544+
f->nr_failed = 1;
545+
f->nr_retries = 0;
546+
} else {
547+
f->nr_failed++;
548+
}
549+
}
550+
551+
/*
552+
* returns true if p1 is better than p2:
553+
*/
554+
static inline bool ptr_better(struct bch_fs *c,
555+
const struct extent_ptr_decoded p1,
556+
const struct extent_ptr_decoded p2)
557+
{
558+
struct bch_dev *dev1 = bch_dev_bkey_exists(c, p1.ptr.dev);
559+
struct bch_dev *dev2 = bch_dev_bkey_exists(c, p2.ptr.dev);
560+
528561
u64 l1 = atomic64_read(&dev1->cur_latency[READ]);
529562
u64 l2 = atomic64_read(&dev2->cur_latency[READ]);
530563

@@ -535,11 +568,12 @@ static inline bool dev_latency_better(struct bch_fs *c,
535568

536569
static int extent_pick_read_device(struct bch_fs *c,
537570
struct bkey_s_c_extent e,
538-
struct bch_devs_mask *avoid,
571+
struct bch_io_failures *failed,
539572
struct extent_ptr_decoded *pick)
540573
{
541574
const union bch_extent_entry *entry;
542575
struct extent_ptr_decoded p;
576+
struct bch_dev_io_failures *f;
543577
struct bch_dev *ca;
544578
int ret = 0;
545579

@@ -549,14 +583,11 @@ static int extent_pick_read_device(struct bch_fs *c,
549583
if (p.ptr.cached && ptr_stale(ca, &p.ptr))
550584
continue;
551585

552-
/*
553-
* XXX: need to make avoid work correctly for stripe ptrs
554-
*/
555-
556-
if (avoid && test_bit(p.ptr.dev, avoid->d))
586+
f = failed ? dev_io_failures(failed, p.ptr.dev) : NULL;
587+
if (f && f->nr_failed >= f->nr_retries)
557588
continue;
558589

559-
if (ret && !dev_latency_better(c, &p.ptr, &pick->ptr))
590+
if (ret && !ptr_better(c, p, *pick))
560591
continue;
561592

562593
*pick = p;
@@ -685,11 +716,11 @@ int bch2_btree_ptr_to_text(struct bch_fs *c, char *buf,
685716
}
686717

687718
int bch2_btree_pick_ptr(struct bch_fs *c, const struct btree *b,
688-
struct bch_devs_mask *avoid,
719+
struct bch_io_failures *failed,
689720
struct extent_ptr_decoded *pick)
690721
{
691722
return extent_pick_read_device(c, bkey_i_to_s_c_extent(&b->key),
692-
avoid, pick);
723+
failed, pick);
693724
}
694725

695726
/* Extents */
@@ -1909,7 +1940,7 @@ void bch2_extent_mark_replicas_cached(struct bch_fs *c,
19091940
* other devices, it will still pick a pointer from avoid.
19101941
*/
19111942
int bch2_extent_pick_ptr(struct bch_fs *c, struct bkey_s_c k,
1912-
struct bch_devs_mask *avoid,
1943+
struct bch_io_failures *failed,
19131944
struct extent_ptr_decoded *pick)
19141945
{
19151946
int ret;
@@ -1921,7 +1952,7 @@ int bch2_extent_pick_ptr(struct bch_fs *c, struct bkey_s_c k,
19211952
case BCH_EXTENT:
19221953
case BCH_EXTENT_CACHED:
19231954
ret = extent_pick_read_device(c, bkey_s_c_to_extent(k),
1924-
avoid, pick);
1955+
failed, pick);
19251956

19261957
if (!ret && !bkey_extent_is_cached(k.k))
19271958
ret = -EIO;

fs/bcachefs/extents.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,13 @@ struct btree_nr_keys bch2_extent_sort_fix_overlapping(struct bch_fs *c,
5353
struct btree *,
5454
struct btree_node_iter_large *);
5555

56+
void bch2_mark_io_failure(struct bch_io_failures *,
57+
struct extent_ptr_decoded *);
5658
int bch2_btree_pick_ptr(struct bch_fs *, const struct btree *,
57-
struct bch_devs_mask *avoid,
59+
struct bch_io_failures *,
5860
struct extent_ptr_decoded *);
59-
6061
int bch2_extent_pick_ptr(struct bch_fs *, struct bkey_s_c,
61-
struct bch_devs_mask *,
62+
struct bch_io_failures *,
6263
struct extent_ptr_decoded *);
6364

6465
void bch2_extent_trim_atomic(struct bkey_i *, struct btree_iter *);

fs/bcachefs/extents_types.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,13 @@ struct extent_ptr_decoded {
2424
struct bch_extent_ptr ptr;
2525
};
2626

27+
struct bch_io_failures {
28+
u8 nr;
29+
struct bch_dev_io_failures {
30+
u8 dev;
31+
u8 nr_failed;
32+
u8 nr_retries;
33+
} devs[BCH_REPLICAS_MAX];
34+
};
35+
2736
#endif /* _BCACHEFS_EXTENTS_TYPES_H */

fs/bcachefs/io.c

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,7 +1203,8 @@ static void bch2_rbio_done(struct bch_read_bio *rbio)
12031203

12041204
static void bch2_read_retry_nodecode(struct bch_fs *c, struct bch_read_bio *rbio,
12051205
struct bvec_iter bvec_iter, u64 inode,
1206-
struct bch_devs_mask *avoid, unsigned flags)
1206+
struct bch_io_failures *failed,
1207+
unsigned flags)
12071208
{
12081209
struct btree_iter iter;
12091210
BKEY_PADDED(k) tmp;
@@ -1237,7 +1238,7 @@ static void bch2_read_retry_nodecode(struct bch_fs *c, struct bch_read_bio *rbio
12371238
goto out;
12381239
}
12391240

1240-
ret = __bch2_read_extent(c, rbio, bvec_iter, k, avoid, flags);
1241+
ret = __bch2_read_extent(c, rbio, bvec_iter, k, failed, flags);
12411242
if (ret == READ_RETRY)
12421243
goto retry;
12431244
if (ret)
@@ -1251,7 +1252,7 @@ static void bch2_read_retry_nodecode(struct bch_fs *c, struct bch_read_bio *rbio
12511252

12521253
static void bch2_read_retry(struct bch_fs *c, struct bch_read_bio *rbio,
12531254
struct bvec_iter bvec_iter, u64 inode,
1254-
struct bch_devs_mask *avoid, unsigned flags)
1255+
struct bch_io_failures *failed, unsigned flags)
12551256
{
12561257
struct btree_iter iter;
12571258
struct bkey_s_c k;
@@ -1274,7 +1275,7 @@ static void bch2_read_retry(struct bch_fs *c, struct bch_read_bio *rbio,
12741275
(k.k->p.offset - bvec_iter.bi_sector) << 9);
12751276
swap(bvec_iter.bi_size, bytes);
12761277

1277-
ret = __bch2_read_extent(c, rbio, bvec_iter, k, avoid, flags);
1278+
ret = __bch2_read_extent(c, rbio, bvec_iter, k, failed, flags);
12781279
switch (ret) {
12791280
case READ_RETRY:
12801281
goto retry;
@@ -1310,14 +1311,12 @@ static void bch2_rbio_retry(struct work_struct *work)
13101311
struct bvec_iter iter = rbio->bvec_iter;
13111312
unsigned flags = rbio->flags;
13121313
u64 inode = rbio->pos.inode;
1313-
struct bch_devs_mask avoid;
1314+
struct bch_io_failures failed = { .nr = 0 };
13141315

13151316
trace_read_retry(&rbio->bio);
13161317

1317-
memset(&avoid, 0, sizeof(avoid));
1318-
13191318
if (rbio->retry == READ_RETRY_AVOID)
1320-
__set_bit(rbio->pick.ptr.dev, avoid.d);
1319+
bch2_mark_io_failure(&failed, &rbio->pick);
13211320

13221321
rbio->bio.bi_status = 0;
13231322

@@ -1327,9 +1326,9 @@ static void bch2_rbio_retry(struct work_struct *work)
13271326
flags &= ~BCH_READ_MAY_PROMOTE;
13281327

13291328
if (flags & BCH_READ_NODECODE)
1330-
bch2_read_retry_nodecode(c, rbio, iter, inode, &avoid, flags);
1329+
bch2_read_retry_nodecode(c, rbio, iter, inode, &failed, flags);
13311330
else
1332-
bch2_read_retry(c, rbio, iter, inode, &avoid, flags);
1331+
bch2_read_retry(c, rbio, iter, inode, &failed, flags);
13331332
}
13341333

13351334
static void bch2_rbio_error(struct bch_read_bio *rbio, int retry,
@@ -1569,7 +1568,7 @@ static void bch2_read_endio(struct bio *bio)
15691568

15701569
int __bch2_read_extent(struct bch_fs *c, struct bch_read_bio *orig,
15711570
struct bvec_iter iter, struct bkey_s_c k,
1572-
struct bch_devs_mask *avoid, unsigned flags)
1571+
struct bch_io_failures *failed, unsigned flags)
15731572
{
15741573
struct extent_ptr_decoded pick;
15751574
struct bch_read_bio *rbio = NULL;
@@ -1579,7 +1578,7 @@ int __bch2_read_extent(struct bch_fs *c, struct bch_read_bio *orig,
15791578
struct bpos pos = bkey_start_pos(k.k);
15801579
int pick_ret;
15811580

1582-
pick_ret = bch2_extent_pick_ptr(c, k, avoid, &pick);
1581+
pick_ret = bch2_extent_pick_ptr(c, k, failed, &pick);
15831582

15841583
/* hole or reservation - just zero fill: */
15851584
if (!pick_ret)
@@ -1750,7 +1749,7 @@ int __bch2_read_extent(struct bch_fs *c, struct bch_read_bio *orig,
17501749
rbio = bch2_rbio_free(rbio);
17511750

17521751
if (ret == READ_RETRY_AVOID) {
1753-
__set_bit(pick.ptr.dev, avoid->d);
1752+
bch2_mark_io_failure(failed, &pick);
17541753
ret = READ_RETRY;
17551754
}
17561755

fs/bcachefs/io.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ struct cache_promote_op;
102102
struct extent_ptr_decoded;
103103

104104
int __bch2_read_extent(struct bch_fs *, struct bch_read_bio *, struct bvec_iter,
105-
struct bkey_s_c, struct bch_devs_mask *, unsigned);
105+
struct bkey_s_c, struct bch_io_failures *, unsigned);
106106
void bch2_read(struct bch_fs *, struct bch_read_bio *, u64);
107107

108108
enum bch_read_flags {

0 commit comments

Comments
 (0)