From: Christoph Hellwig <hch@lst.de>
To: Chris Mason <clm@fb.com>, Josef Bacik <josef@toxicpanda.com>,
David Sterba <dsterba@suse.com>
Cc: Damien Le Moal <damien.lemoal@wdc.com>,
Naohiro Aota <naohiro.aota@wdc.com>,
Johannes Thumshirn <johannes.thumshirn@wdc.com>,
Qu Wenruo <wqu@suse.com>, Jens Axboe <axboe@kernel.dk>,
"Darrick J. Wong" <djwong@kernel.org>,
linux-block@vger.kernel.org, linux-btrfs@vger.kernel.org,
linux-fsdevel@vger.kernel.org
Subject: [PATCH 07/17] btrfs: allow btrfs_submit_bio to split bios
Date: Thu, 1 Sep 2022 10:42:06 +0300 [thread overview]
Message-ID: <20220901074216.1849941-8-hch@lst.de> (raw)
In-Reply-To: <20220901074216.1849941-1-hch@lst.de>
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.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/btrfs/volumes.c | 106 +++++++++++++++++++++++++++++++++++++--------
fs/btrfs/volumes.h | 1 +
2 files changed, 90 insertions(+), 17 deletions(-)
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 5c6535e10085d..0a2d144c20604 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -35,6 +35,7 @@
#include "zoned.h"
static struct bio_set btrfs_bioset;
+static struct bio_set btrfs_clone_bioset;
static struct bio_set btrfs_repair_bioset;
static mempool_t btrfs_failed_bio_pool;
@@ -6661,6 +6662,7 @@ static void btrfs_bio_init(struct btrfs_bio *bbio, struct inode *inode,
bbio->inode = inode;
bbio->end_io = end_io;
bbio->private = private;
+ atomic_set(&bbio->pending_ios, 1);
}
/*
@@ -6698,6 +6700,57 @@ struct bio *btrfs_bio_clone_partial(struct bio *orig, u64 offset, u64 size,
return bio;
}
+static struct bio *btrfs_split_bio(struct bio *orig, u64 map_length)
+{
+ struct btrfs_bio *orig_bbio = btrfs_bio(orig);
+ struct bio *bio;
+
+ bio = bio_split(orig, map_length >> SECTOR_SHIFT, GFP_NOFS,
+ &btrfs_clone_bioset);
+ btrfs_bio_init(btrfs_bio(bio), orig_bbio->inode, NULL, orig_bbio);
+
+ btrfs_bio(bio)->file_offset = orig_bbio->file_offset;
+ orig_bbio->file_offset += map_length;
+
+ atomic_inc(&orig_bbio->pending_ios);
+ return bio;
+}
+
+static void btrfs_orig_write_end_io(struct bio *bio);
+static void btrfs_bbio_propagate_error(struct btrfs_bio *bbio,
+ struct btrfs_bio *orig_bbio)
+{
+ /*
+ * For writes btrfs tolerates nr_mirrors - 1 write failures, so we
+ * can't just blindly propagate a write failure here.
+ * Instead increment the error count in the original I/O context so
+ * that it is guaranteed to be larger than the error tolerance.
+ */
+ if (bbio->bio.bi_end_io == &btrfs_orig_write_end_io) {
+ struct btrfs_io_stripe *orig_stripe = orig_bbio->bio.bi_private;
+ struct btrfs_io_context *orig_bioc = orig_stripe->bioc;
+
+ atomic_add(orig_bioc->max_errors, &orig_bioc->error);
+ } else {
+ orig_bbio->bio.bi_status = bbio->bio.bi_status;
+ }
+}
+
+static void btrfs_orig_bbio_end_io(struct btrfs_bio *bbio)
+{
+ if (bbio->bio.bi_pool == &btrfs_clone_bioset) {
+ struct btrfs_bio *orig_bbio = bbio->private;
+
+ if (bbio->bio.bi_status)
+ btrfs_bbio_propagate_error(bbio, orig_bbio);
+ bio_put(&bbio->bio);
+ bbio = orig_bbio;
+ }
+
+ if (atomic_dec_and_test(&bbio->pending_ios))
+ bbio->end_io(bbio);
+}
+
static int next_repair_mirror(struct btrfs_failed_bio *fbio, int cur_mirror)
{
if (cur_mirror == fbio->num_copies)
@@ -6715,7 +6768,7 @@ static int prev_repair_mirror(struct btrfs_failed_bio *fbio, int cur_mirror)
static void btrfs_repair_done(struct btrfs_failed_bio *fbio)
{
if (atomic_dec_and_test(&fbio->repair_count)) {
- fbio->bbio->end_io(fbio->bbio);
+ btrfs_orig_bbio_end_io(fbio->bbio);
mempool_free(fbio, &btrfs_failed_bio_pool);
}
}
@@ -6857,7 +6910,7 @@ static void btrfs_check_read_bio(struct btrfs_bio *bbio,
if (unlikely(fbio))
btrfs_repair_done(fbio);
else
- bbio->end_io(bbio);
+ btrfs_orig_bbio_end_io(bbio);
}
static void btrfs_log_dev_io_error(struct bio *bio, struct btrfs_device *dev)
@@ -6908,7 +6961,7 @@ static void btrfs_simple_end_io(struct bio *bio)
} else {
if (bio_op(bio) == REQ_OP_ZONE_APPEND)
btrfs_record_physical_zoned(bbio);
- bbio->end_io(bbio);
+ btrfs_orig_bbio_end_io(bbio);
}
}
@@ -6922,7 +6975,7 @@ static void btrfs_raid56_end_io(struct bio *bio)
if (bio_op(bio) == REQ_OP_READ)
btrfs_check_read_bio(bbio, NULL);
else
- bbio->end_io(bbio);
+ btrfs_orig_bbio_end_io(bbio);
btrfs_put_bioc(bioc);
}
@@ -6949,7 +7002,7 @@ static void btrfs_orig_write_end_io(struct bio *bio)
else
bio->bi_status = BLK_STS_OK;
- bbio->end_io(bbio);
+ btrfs_orig_bbio_end_io(bbio);
btrfs_put_bioc(bioc);
}
@@ -7190,8 +7243,8 @@ static bool btrfs_wq_submit_bio(struct btrfs_bio *bbio,
return true;
}
-void btrfs_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
- int mirror_num)
+static bool btrfs_submit_chunk(struct btrfs_fs_info *fs_info, struct bio *bio,
+ int mirror_num)
{
struct btrfs_bio *bbio = btrfs_bio(bio);
u64 logical = bio->bi_iter.bi_sector << 9;
@@ -7207,11 +7260,10 @@ void btrfs_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
if (ret)
goto fail;
+ map_length = min(map_length, length);
if (map_length < length) {
- btrfs_crit(fs_info,
- "mapping failed logical %llu bio len %llu len %llu",
- logical, length, map_length);
- BUG();
+ bio = btrfs_split_bio(bio, map_length);
+ bbio = btrfs_bio(bio);
}
/*
@@ -7222,7 +7274,7 @@ void btrfs_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
bbio->saved_iter = bio->bi_iter;
ret = btrfs_lookup_bio_sums(bbio);
if (ret)
- goto fail;
+ goto fail_put_bio;
}
if (btrfs_op(bio) == BTRFS_MAP_WRITE) {
@@ -7231,7 +7283,7 @@ void btrfs_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
if (bio_op(bio) == REQ_OP_ZONE_APPEND) {
ret = btrfs_extract_ordered_extent(btrfs_bio(bio));
if (ret)
- goto fail;
+ goto fail_put_bio;
}
/*
@@ -7243,22 +7295,36 @@ void btrfs_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
!btrfs_is_data_reloc_root(bi->root)) {
if (should_async_write(bbio) &&
btrfs_wq_submit_bio(bbio, bioc, &smap, mirror_num))
- return;
+ goto done;
if (bio->bi_opf & REQ_META)
ret = btree_csum_one_bio(bbio);
else
ret = btrfs_csum_one_bio(bbio);
if (ret)
- goto fail;
+ goto fail_put_bio;
}
}
__btrfs_submit_bio(bio, bioc, &smap, mirror_num);
- return;
+done:
+ return map_length == length;
+
+fail_put_bio:
+ if (map_length < length)
+ bio_put(bio);
fail:
btrfs_bio_counter_dec(fs_info);
btrfs_bio_end_io(bbio, errno_to_blk_status(ret));
+ /* Do not submit another chunk */
+ return true;
+}
+
+void btrfs_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
+ int mirror_num)
+{
+ while (!btrfs_submit_chunk(fs_info, bio, mirror_num))
+ ;
}
/*
@@ -8858,10 +8924,13 @@ int __init btrfs_bioset_init(void)
offsetof(struct btrfs_bio, bio),
BIOSET_NEED_BVECS))
return -ENOMEM;
+ if (bioset_init(&btrfs_clone_bioset, BIO_POOL_SIZE,
+ offsetof(struct btrfs_bio, bio), 0))
+ goto out_free_bioset;
if (bioset_init(&btrfs_repair_bioset, BIO_POOL_SIZE,
offsetof(struct btrfs_bio, bio),
BIOSET_NEED_BVECS))
- goto out_free_bioset;
+ goto out_free_clone_bioset;
if (mempool_init_kmalloc_pool(&btrfs_failed_bio_pool, BIO_POOL_SIZE,
sizeof(struct btrfs_failed_bio)))
goto out_free_repair_bioset;
@@ -8869,6 +8938,8 @@ int __init btrfs_bioset_init(void)
out_free_repair_bioset:
bioset_exit(&btrfs_repair_bioset);
+out_free_clone_bioset:
+ bioset_exit(&btrfs_clone_bioset);
out_free_bioset:
bioset_exit(&btrfs_bioset);
return -ENOMEM;
@@ -8878,5 +8949,6 @@ void __cold btrfs_bioset_exit(void)
{
mempool_exit(&btrfs_failed_bio_pool);
bioset_exit(&btrfs_repair_bioset);
+ bioset_exit(&btrfs_clone_bioset);
bioset_exit(&btrfs_bioset);
}
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 8b248c9bd602b..97877184d0db1 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -386,6 +386,7 @@ struct btrfs_bio {
/* For internal use in read end I/O handling */
unsigned int mirror_num;
+ atomic_t pending_ios;
struct work_struct end_io_work;
/*
--
2.30.2
next prev parent reply other threads:[~2022-09-01 7:43 UTC|newest]
Thread overview: 108+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-09-01 7:41 consolidate btrfs checksumming, repair and bio splitting Christoph Hellwig
2022-09-01 7:42 ` [PATCH 01/17] block: export bio_split_rw Christoph Hellwig
2022-09-01 8:02 ` Johannes Thumshirn
2022-09-01 8:54 ` Qu Wenruo
2022-09-05 6:44 ` Christoph Hellwig
2022-09-05 6:51 ` Qu Wenruo
2022-09-07 17:51 ` Josef Bacik
2022-09-01 7:42 ` [PATCH 02/17] btrfs: stop tracking failed reads in the I/O tree Christoph Hellwig
2022-09-01 8:55 ` Qu Wenruo
2022-09-07 17:52 ` Josef Bacik
2022-09-01 7:42 ` [PATCH 03/17] btrfs: move repair_io_failure to volumes.c Christoph Hellwig
2022-09-07 17:54 ` Josef Bacik
2022-09-01 7:42 ` [PATCH 04/17] btrfs: handle checksum validation and repair at the storage layer Christoph Hellwig
2022-09-01 9:04 ` Qu Wenruo
2022-09-05 6:48 ` Christoph Hellwig
2022-09-05 6:59 ` Qu Wenruo
2022-09-05 14:31 ` Christoph Hellwig
2022-09-05 22:34 ` Qu Wenruo
2022-09-06 4:34 ` Christoph Hellwig
2022-09-07 18:15 ` Josef Bacik
2022-09-12 13:57 ` Christoph Hellwig
2022-09-01 7:42 ` [PATCH 05/17] btrfs: handle checksum generation in " Christoph Hellwig
2022-09-07 20:33 ` Josef Bacik
2022-09-01 7:42 ` [PATCH 06/17] btrfs: handle recording of zoned writes " Christoph Hellwig
2022-09-01 9:44 ` Johannes Thumshirn
2022-09-07 20:36 ` Josef Bacik
2022-09-12 6:11 ` Naohiro Aota
2022-09-01 7:42 ` Christoph Hellwig [this message]
2022-09-01 9:47 ` [PATCH 07/17] btrfs: allow btrfs_submit_bio to split bios Johannes Thumshirn
2022-09-07 20:55 ` Josef Bacik
2022-09-12 13:58 ` Christoph Hellwig
2022-09-12 0:20 ` Qu Wenruo
2022-09-12 13:55 ` Christoph Hellwig
2022-09-12 22:23 ` Qu Wenruo
2022-09-01 7:42 ` [PATCH 08/17] btrfs: pass the iomap bio to btrfs_submit_bio Christoph Hellwig
2022-09-07 21:00 ` Josef Bacik
2022-09-01 7:42 ` [PATCH 09/17] btrfs: remove stripe boundary calculation for buffered I/O Christoph Hellwig
2022-09-07 21:04 ` Josef Bacik
2022-09-01 7:42 ` [PATCH 10/17] btrfs: remove stripe boundary calculation for compressed I/O Christoph Hellwig
2022-09-01 9:56 ` Johannes Thumshirn
2022-09-05 6:49 ` Christoph Hellwig
2022-09-07 21:07 ` Josef Bacik
2022-09-01 7:42 ` [PATCH 11/17] btrfs: remove stripe boundary calculation for encoded I/O Christoph Hellwig
2022-09-01 9:58 ` Johannes Thumshirn
2022-09-07 21:08 ` Josef Bacik
2022-09-01 7:42 ` [PATCH 12/17] btrfs: remove struct btrfs_io_geometry Christoph Hellwig
2022-09-07 21:10 ` Josef Bacik
2022-09-01 7:42 ` [PATCH 13/17] btrfs: remove submit_encoded_read_bio Christoph Hellwig
2022-09-01 10:02 ` Johannes Thumshirn
2022-09-07 21:11 ` Josef Bacik
2022-09-01 7:42 ` [PATCH 14/17] btrfs: remove now spurious bio submission helpers Christoph Hellwig
2022-09-01 10:14 ` Johannes Thumshirn
2022-09-07 21:12 ` Josef Bacik
2022-09-01 7:42 ` [PATCH 15/17] btrfs: calculate file system wide queue limit for zoned mode Christoph Hellwig
2022-09-01 11:28 ` Johannes Thumshirn
2022-09-05 6:50 ` Christoph Hellwig
2022-09-02 1:56 ` Damien Le Moal
2022-09-02 1:59 ` Damien Le Moal
2022-09-05 6:54 ` Christoph Hellwig
2022-09-01 7:42 ` [PATCH 16/17] btrfs: split zone append bios in btrfs_submit_bio Christoph Hellwig
2022-09-02 1:46 ` Damien Le Moal
2022-09-05 6:55 ` Christoph Hellwig
2022-09-05 13:15 ` Johannes Thumshirn
2022-09-05 14:25 ` Christoph Hellwig
2022-09-05 14:31 ` Johannes Thumshirn
2022-09-05 14:39 ` Christoph Hellwig
2022-09-05 14:43 ` Johannes Thumshirn
2022-09-05 15:30 ` Johannes Thumshirn
2022-09-07 21:17 ` Josef Bacik
2022-09-01 7:42 ` [PATCH 17/17] iomap: remove IOMAP_F_ZONE_APPEND Christoph Hellwig
2022-09-01 10:46 ` Johannes Thumshirn
2022-09-02 1:38 ` Damien Le Moal
2022-09-05 6:50 ` Christoph Hellwig
2022-09-05 6:57 ` Damien Le Moal
2022-09-07 21:18 ` Josef Bacik
2022-09-02 15:18 ` consolidate btrfs checksumming, repair and bio splitting Johannes Thumshirn
2022-09-07 9:10 ` code placement for bio / storage layer code Christoph Hellwig
2022-09-07 9:46 ` Johannes Thumshirn
2022-09-07 10:28 ` Qu Wenruo
2022-09-07 11:10 ` Christoph Hellwig
2022-09-07 11:27 ` Qu Wenruo
2022-09-07 11:35 ` Christoph Hellwig
2022-10-10 8:01 ` Johannes Thumshirn
2022-10-24 8:12 ` consolidate btrfs checksumming, repair and bio splitting Johannes Thumshirn
2022-10-24 8:20 ` Qu Wenruo
2022-10-24 9:07 ` Johannes Thumshirn
2022-10-24 9:18 ` Qu Wenruo
2022-10-24 10:21 ` Johannes Thumshirn
2022-10-24 14:44 ` Christoph Hellwig
2022-10-24 15:25 ` Chris Mason
2022-10-24 17:10 ` David Sterba
2022-10-24 17:34 ` Chris Mason
2022-10-24 22:18 ` Damien Le Moal
2022-10-26 7:36 ` Johannes Thumshirn
2022-10-26 11:41 ` Steven Rostedt
2022-10-27 13:54 ` Johannes Thumshirn
2022-10-31 12:19 ` David Sterba
2022-10-31 16:06 ` Chris Mason
2022-11-02 4:00 ` Steven Rostedt
2022-11-02 6:29 ` Christoph Hellwig
2022-11-02 14:00 ` Chris Mason
2022-11-02 14:05 ` Josef Bacik
2022-11-02 14:06 ` Christoph Hellwig
2022-11-02 20:20 ` Andreas Dilger
2022-11-02 22:07 ` Chris Mason
2022-11-03 8:49 ` Christoph Hellwig
2022-11-03 2:54 ` Theodore Ts'o
2022-11-11 17:57 ` David Sterba
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220901074216.1849941-8-hch@lst.de \
--to=hch@lst.de \
--cc=axboe@kernel.dk \
--cc=clm@fb.com \
--cc=damien.lemoal@wdc.com \
--cc=djwong@kernel.org \
--cc=dsterba@suse.com \
--cc=johannes.thumshirn@wdc.com \
--cc=josef@toxicpanda.com \
--cc=linux-block@vger.kernel.org \
--cc=linux-btrfs@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=naohiro.aota@wdc.com \
--cc=wqu@suse.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).