Skip to content

Commit 852eee6

Browse files
Christoph Hellwigkdave
Christoph Hellwig
authored andcommitted
btrfs: allow btrfs_submit_bio to split bios
Currently the I/O submitters have to split bios according to the chunk stripe boundaries. This leads to extra lookups in the extent trees and a lot of boilerplate code. To drop this requirement, split the bio when __btrfs_map_block returns a mapping that is smaller than the requested size and keep a count of pending bios in the original btrfs_bio so that the upper level completion is only invoked when all clones have completed. Based on a patch from Qu Wenruo. Reviewed-by: Josef Bacik <[email protected]> Reviewed-by: Johannes Thumshirn <[email protected]> Reviewed-by: Qu Wenruo <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 542e300 commit 852eee6

File tree

2 files changed

+93
-18
lines changed

2 files changed

+93
-18
lines changed

fs/btrfs/bio.c

Lines changed: 92 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "file-item.h"
1818

1919
static struct bio_set btrfs_bioset;
20+
static struct bio_set btrfs_clone_bioset;
2021
static struct bio_set btrfs_repair_bioset;
2122
static mempool_t btrfs_failed_bio_pool;
2223

@@ -38,6 +39,7 @@ static inline void btrfs_bio_init(struct btrfs_bio *bbio,
3839
bbio->inode = inode;
3940
bbio->end_io = end_io;
4041
bbio->private = private;
42+
atomic_set(&bbio->pending_ios, 1);
4143
}
4244

4345
/*
@@ -75,6 +77,59 @@ struct bio *btrfs_bio_clone_partial(struct bio *orig, u64 offset, u64 size,
7577
return bio;
7678
}
7779

80+
static struct bio *btrfs_split_bio(struct bio *orig, u64 map_length)
81+
{
82+
struct btrfs_bio *orig_bbio = btrfs_bio(orig);
83+
struct bio *bio;
84+
85+
bio = bio_split(orig, map_length >> SECTOR_SHIFT, GFP_NOFS,
86+
&btrfs_clone_bioset);
87+
btrfs_bio_init(btrfs_bio(bio), orig_bbio->inode, NULL, orig_bbio);
88+
89+
btrfs_bio(bio)->file_offset = orig_bbio->file_offset;
90+
if (!(orig->bi_opf & REQ_BTRFS_ONE_ORDERED))
91+
orig_bbio->file_offset += map_length;
92+
93+
atomic_inc(&orig_bbio->pending_ios);
94+
return bio;
95+
}
96+
97+
static void btrfs_orig_write_end_io(struct bio *bio);
98+
99+
static void btrfs_bbio_propagate_error(struct btrfs_bio *bbio,
100+
struct btrfs_bio *orig_bbio)
101+
{
102+
/*
103+
* For writes we tolerate nr_mirrors - 1 write failures, so we can't
104+
* just blindly propagate a write failure here. Instead increment the
105+
* error count in the original I/O context so that it is guaranteed to
106+
* be larger than the error tolerance.
107+
*/
108+
if (bbio->bio.bi_end_io == &btrfs_orig_write_end_io) {
109+
struct btrfs_io_stripe *orig_stripe = orig_bbio->bio.bi_private;
110+
struct btrfs_io_context *orig_bioc = orig_stripe->bioc;
111+
112+
atomic_add(orig_bioc->max_errors, &orig_bioc->error);
113+
} else {
114+
orig_bbio->bio.bi_status = bbio->bio.bi_status;
115+
}
116+
}
117+
118+
static void btrfs_orig_bbio_end_io(struct btrfs_bio *bbio)
119+
{
120+
if (bbio->bio.bi_pool == &btrfs_clone_bioset) {
121+
struct btrfs_bio *orig_bbio = bbio->private;
122+
123+
if (bbio->bio.bi_status)
124+
btrfs_bbio_propagate_error(bbio, orig_bbio);
125+
bio_put(&bbio->bio);
126+
bbio = orig_bbio;
127+
}
128+
129+
if (atomic_dec_and_test(&bbio->pending_ios))
130+
bbio->end_io(bbio);
131+
}
132+
78133
static int next_repair_mirror(struct btrfs_failed_bio *fbio, int cur_mirror)
79134
{
80135
if (cur_mirror == fbio->num_copies)
@@ -92,7 +147,7 @@ static int prev_repair_mirror(struct btrfs_failed_bio *fbio, int cur_mirror)
92147
static void btrfs_repair_done(struct btrfs_failed_bio *fbio)
93148
{
94149
if (atomic_dec_and_test(&fbio->repair_count)) {
95-
fbio->bbio->end_io(fbio->bbio);
150+
btrfs_orig_bbio_end_io(fbio->bbio);
96151
mempool_free(fbio, &btrfs_failed_bio_pool);
97152
}
98153
}
@@ -229,7 +284,7 @@ static void btrfs_check_read_bio(struct btrfs_bio *bbio, struct btrfs_device *de
229284
if (fbio)
230285
btrfs_repair_done(fbio);
231286
else
232-
bbio->end_io(bbio);
287+
btrfs_orig_bbio_end_io(bbio);
233288
}
234289

235290
static void btrfs_log_dev_io_error(struct bio *bio, struct btrfs_device *dev)
@@ -283,7 +338,7 @@ static void btrfs_simple_end_io(struct bio *bio)
283338
} else {
284339
if (bio_op(bio) == REQ_OP_ZONE_APPEND)
285340
btrfs_record_physical_zoned(bbio);
286-
bbio->end_io(bbio);
341+
btrfs_orig_bbio_end_io(bbio);
287342
}
288343
}
289344

@@ -297,7 +352,7 @@ static void btrfs_raid56_end_io(struct bio *bio)
297352
if (bio_op(bio) == REQ_OP_READ && !(bbio->bio.bi_opf & REQ_META))
298353
btrfs_check_read_bio(bbio, NULL);
299354
else
300-
bbio->end_io(bbio);
355+
btrfs_orig_bbio_end_io(bbio);
301356

302357
btrfs_put_bioc(bioc);
303358
}
@@ -324,7 +379,7 @@ static void btrfs_orig_write_end_io(struct bio *bio)
324379
else
325380
bio->bi_status = BLK_STS_OK;
326381

327-
bbio->end_io(bbio);
382+
btrfs_orig_bbio_end_io(bbio);
328383
btrfs_put_bioc(bioc);
329384
}
330385

@@ -488,7 +543,7 @@ static void run_one_async_done(struct btrfs_work *work)
488543

489544
/* If an error occurred we just want to clean up the bio and move on. */
490545
if (bio->bi_status) {
491-
btrfs_bio_end_io(async->bbio, bio->bi_status);
546+
btrfs_orig_bbio_end_io(async->bbio);
492547
return;
493548
}
494549

@@ -563,9 +618,11 @@ static bool btrfs_wq_submit_bio(struct btrfs_bio *bbio,
563618
return true;
564619
}
565620

566-
void btrfs_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, int mirror_num)
621+
static bool btrfs_submit_chunk(struct btrfs_fs_info *fs_info, struct bio *bio,
622+
int mirror_num)
567623
{
568624
struct btrfs_bio *bbio = btrfs_bio(bio);
625+
struct btrfs_bio *orig_bbio = bbio;
569626
u64 logical = bio->bi_iter.bi_sector << 9;
570627
u64 length = bio->bi_iter.bi_size;
571628
u64 map_length = length;
@@ -582,11 +639,10 @@ void btrfs_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, int mirror
582639
goto fail;
583640
}
584641

642+
map_length = min(map_length, length);
585643
if (map_length < length) {
586-
btrfs_crit(fs_info,
587-
"mapping failed logical %llu bio len %llu len %llu",
588-
logical, length, map_length);
589-
BUG();
644+
bio = btrfs_split_bio(bio, map_length);
645+
bbio = btrfs_bio(bio);
590646
}
591647

592648
/*
@@ -597,14 +653,14 @@ void btrfs_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, int mirror
597653
bbio->saved_iter = bio->bi_iter;
598654
ret = btrfs_lookup_bio_sums(bbio);
599655
if (ret)
600-
goto fail;
656+
goto fail_put_bio;
601657
}
602658

603659
if (btrfs_op(bio) == BTRFS_MAP_WRITE) {
604660
if (bio_op(bio) == REQ_OP_ZONE_APPEND) {
605661
ret = btrfs_extract_ordered_extent(btrfs_bio(bio));
606662
if (ret)
607-
goto fail;
663+
goto fail_put_bio;
608664
}
609665

610666
/*
@@ -616,20 +672,32 @@ void btrfs_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, int mirror
616672
!btrfs_is_data_reloc_root(bbio->inode->root)) {
617673
if (should_async_write(bbio) &&
618674
btrfs_wq_submit_bio(bbio, bioc, &smap, mirror_num))
619-
return;
675+
goto done;
620676

621677
ret = btrfs_bio_csum(bbio);
622678
if (ret)
623-
goto fail;
679+
goto fail_put_bio;
624680
}
625681
}
626682

627683
__btrfs_submit_bio(bio, bioc, &smap, mirror_num);
628-
return;
684+
done:
685+
return map_length == length;
629686

687+
fail_put_bio:
688+
if (map_length < length)
689+
bio_put(bio);
630690
fail:
631691
btrfs_bio_counter_dec(fs_info);
632-
btrfs_bio_end_io(bbio, ret);
692+
btrfs_bio_end_io(orig_bbio, ret);
693+
/* Do not submit another chunk */
694+
return true;
695+
}
696+
697+
void btrfs_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, int mirror_num)
698+
{
699+
while (!btrfs_submit_chunk(fs_info, bio, mirror_num))
700+
;
633701
}
634702

635703
/*
@@ -737,17 +805,22 @@ int __init btrfs_bioset_init(void)
737805
offsetof(struct btrfs_bio, bio),
738806
BIOSET_NEED_BVECS))
739807
return -ENOMEM;
808+
if (bioset_init(&btrfs_clone_bioset, BIO_POOL_SIZE,
809+
offsetof(struct btrfs_bio, bio), 0))
810+
goto out_free_bioset;
740811
if (bioset_init(&btrfs_repair_bioset, BIO_POOL_SIZE,
741812
offsetof(struct btrfs_bio, bio),
742813
BIOSET_NEED_BVECS))
743-
goto out_free_bioset;
814+
goto out_free_clone_bioset;
744815
if (mempool_init_kmalloc_pool(&btrfs_failed_bio_pool, BIO_POOL_SIZE,
745816
sizeof(struct btrfs_failed_bio)))
746817
goto out_free_repair_bioset;
747818
return 0;
748819

749820
out_free_repair_bioset:
750821
bioset_exit(&btrfs_repair_bioset);
822+
out_free_clone_bioset:
823+
bioset_exit(&btrfs_clone_bioset);
751824
out_free_bioset:
752825
bioset_exit(&btrfs_bioset);
753826
return -ENOMEM;
@@ -757,5 +830,6 @@ void __cold btrfs_bioset_exit(void)
757830
{
758831
mempool_exit(&btrfs_failed_bio_pool);
759832
bioset_exit(&btrfs_repair_bioset);
833+
bioset_exit(&btrfs_clone_bioset);
760834
bioset_exit(&btrfs_bioset);
761835
}

fs/btrfs/bio.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ struct btrfs_bio {
5555

5656
/* For internal use in read end I/O handling */
5757
unsigned int mirror_num;
58+
atomic_t pending_ios;
5859
struct work_struct end_io_work;
5960

6061
/*

0 commit comments

Comments
 (0)