From: Qu Wenruo <wqu@suse.com>
To: linux-btrfs@vger.kernel.org
Subject: [PATCH RFC v2 07/12] btrfs: allow btrfs read repair to submit all writes in one go
Date: Wed, 27 Apr 2022 15:18:53 +0800 [thread overview]
Message-ID: <834bd7a42f6223794b0bafcbb55b4e167145d024.1651043618.git.wqu@suse.com> (raw)
In-Reply-To: <cover.1651043617.git.wqu@suse.com>
Currently if we want to submit write for read time repair, we call
repair_io_failure(), which will submit the bio and wait for it.
But for our newer btrfs_read_repair infrastructure , we want to submit
all write bios in one go, and then wait for all bios to finish, just
like how we handle the read bios.
This patch will get rid of the repair_io_failure() call, replacing it
with the same bios handling, by assembling all bios into a bio_list,
then submit them all and wait for them.
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/extent_io.c | 116 +++++++++++++++++++++++++++----------------
fs/btrfs/extent_io.h | 2 +-
2 files changed, 75 insertions(+), 43 deletions(-)
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 7db6800cba31..bbdd8d1a966a 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -2795,20 +2795,28 @@ static void read_repair_end_bio(struct bio *bio)
/* Add a sector into the read repair bios list for later submission */
static void read_repair_bio_add_sector(struct btrfs_read_repair_ctrl *ctrl,
- int sector_nr)
+ int sector_nr, unsigned int opf)
{
- const struct btrfs_fs_info *fs_info = btrfs_sb(ctrl->inode->i_sb);
+ struct btrfs_fs_info *fs_info = btrfs_sb(ctrl->inode->i_sb);
struct page *page;
int pgoff;
struct bio *bio;
int ret;
+ ASSERT(opf == REQ_OP_WRITE || opf == REQ_OP_READ);
+
+ /* For write, we need to handle zoned case first */
+ if (opf == REQ_OP_WRITE) {
+ if (btrfs_repair_one_zone(fs_info, ctrl->logical))
+ return;
+ }
+
page = read_repair_get_sector(ctrl, sector_nr, &pgoff);
ASSERT(page);
/* Check if the sector can be added to the last bio */
- if (!bio_list_empty(&ctrl->read_bios)) {
- bio = ctrl->read_bios.tail;
+ if (!bio_list_empty(&ctrl->bios)) {
+ bio = ctrl->bios.tail;
if ((bio->bi_iter.bi_sector << SECTOR_SHIFT) + bio->bi_iter.bi_size ==
ctrl->logical + (sector_nr << fs_info->sectorsize_bits))
goto add;
@@ -2824,12 +2832,12 @@ static void read_repair_bio_add_sector(struct btrfs_read_repair_ctrl *ctrl,
/* It's backed by mempool, thus should not fail */
ASSERT(bio);
- bio->bi_opf = REQ_OP_READ;
+ bio->bi_opf = opf;
bio->bi_iter.bi_sector = ((sector_nr << fs_info->sectorsize_bits) +
ctrl->logical) >> SECTOR_SHIFT;
bio->bi_private = ctrl;
bio->bi_end_io = read_repair_end_bio;
- bio_list_add(&ctrl->read_bios, bio);
+ bio_list_add(&ctrl->bios, bio);
add:
ret = bio_add_page(bio, page, fs_info->sectorsize, pgoff);
@@ -2841,19 +2849,57 @@ static void read_repair_bio_add_sector(struct btrfs_read_repair_ctrl *ctrl,
atomic_add(fs_info->sectorsize, &ctrl->io_bytes);
}
+static void read_repair_submit_bio(struct btrfs_read_repair_ctrl *ctrl,
+ struct bio *bio, int mirror)
+{
+ struct btrfs_fs_info *fs_info = btrfs_sb(ctrl->inode->i_sb);
+ blk_status_t ret;
+
+ btrfs_bio(bio)->iter = bio->bi_iter;
+
+ /*
+ * Zoned repair will be handled separately, thus we would only have
+ * regular write or read bios here.
+ */
+ ASSERT(bio_op(bio) == REQ_OP_WRITE || bio_op(bio) == REQ_OP_READ);
+ ASSERT(bio->bi_private == ctrl);
+ ASSERT(bio->bi_end_io == read_repair_end_bio);
+
+ /*
+ * Avoid races with device replace and make sure our bioc has devices
+ * associated to its stripes that don't go away while we are doing the
+ * write operation.
+ */
+ if (bio_op(bio) == REQ_OP_WRITE)
+ btrfs_bio_counter_inc_blocked(fs_info);
+
+ /*
+ * Our endio is super atomic, and we don't want to waste time on
+ * lookup data csum. So here we just call btrfs_map_bio()
+ * directly.
+ */
+ ret = btrfs_map_bio(fs_info, bio, mirror);
+
+ if (bio_op(bio) == REQ_OP_WRITE)
+ btrfs_bio_counter_dec(fs_info);
+
+ if (ret) {
+ bio->bi_status = ret;
+ bio_endio(bio);
+ }
+}
+
static void read_repair_from_one_mirror(struct btrfs_read_repair_ctrl *ctrl,
struct inode *inode, int mirror)
{
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
const int nbits = ctrl->bio_size >> fs_info->sectorsize_bits;
- const u64 failed_logical = ctrl->failed_bio->bi_iter.bi_sector <<
- SECTOR_SHIFT;
const u32 sectorsize = fs_info->sectorsize;
struct bio *bio;
int bit;
/* We shouldn't have any pending read */
- ASSERT(bio_list_size(&ctrl->read_bios) == 0 &&
+ ASSERT(bio_list_size(&ctrl->bios) == 0 &&
atomic_read(&ctrl->io_bytes) == 0);
/*
@@ -2863,39 +2909,19 @@ static void read_repair_from_one_mirror(struct btrfs_read_repair_ctrl *ctrl,
*/
bitmap_copy(ctrl->prev_bad_bitmap, ctrl->cur_bad_bitmap, nbits);
- /* Queue all bad sectors into our read_bios list */
+ /* Queue all bad sectors into our bios list */
for_each_set_bit(bit, ctrl->prev_bad_bitmap, nbits)
- read_repair_bio_add_sector(ctrl, bit);
-
- /* Submit all bios in read_bios and wait for them to finish */
- for (bio = bio_list_pop(&ctrl->read_bios); bio;
- bio = bio_list_pop(&ctrl->read_bios)) {
- blk_status_t ret;
+ read_repair_bio_add_sector(ctrl, bit, REQ_OP_READ);
- btrfs_bio(bio)->iter = bio->bi_iter;
-
- ASSERT(bio_op(bio) == REQ_OP_READ);
- ASSERT(bio->bi_private == ctrl);
- ASSERT(bio->bi_end_io == read_repair_end_bio);
-
- /*
- * Our endio is super atomic, and we don't want to waste time on
- * lookup data csum. So here we just call btrfs_map_bio()
- * directly.
- */
- ret = btrfs_map_bio(fs_info, bio, mirror);
- if (ret) {
- bio->bi_status = ret;
- bio_endio(bio);
- }
- }
+ /* Submit all bios in bios list and wait for them to finish */
+ for (bio = bio_list_pop(&ctrl->bios); bio;
+ bio = bio_list_pop(&ctrl->bios))
+ read_repair_submit_bio(ctrl, bio, mirror);
wait_event(ctrl->io_wait, atomic_read(&ctrl->io_bytes) == 0);
/* Now re-verify the newly read out data */
for_each_set_bit(bit, ctrl->prev_bad_bitmap, nbits) {
struct extent_state *cached = NULL;
- const u64 logical = failed_logical +
- (bit << fs_info->sectorsize_bits);
const u64 file_offset = ctrl->file_offset +
(bit << fs_info->sectorsize_bits);
struct page *page;
@@ -2934,13 +2960,12 @@ static void read_repair_from_one_mirror(struct btrfs_read_repair_ctrl *ctrl,
uptodate:
clear_bit(bit, ctrl->cur_bad_bitmap);
/*
- * We repaired one sector, write the correct data back
- * to the bad mirror. Note that this function do the
- * write synchronously, and can be optimized later.
+ * We repaired one sector, queue this sector for later
+ * writeback to recover the bad mirror.
+ * Don't worry about zoned yet, it will be handled
+ * in that function.
*/
- repair_io_failure(fs_info, btrfs_ino(BTRFS_I(inode)),
- file_offset, sectorsize, logical, page, pgoff,
- get_prev_mirror(mirror, ctrl->num_copies));
+ read_repair_bio_add_sector(ctrl, bit, REQ_OP_WRITE);
/* Also update the page status */
end_page_read(page, true, file_offset, sectorsize);
@@ -2951,6 +2976,13 @@ static void read_repair_from_one_mirror(struct btrfs_read_repair_ctrl *ctrl,
file_offset, file_offset + sectorsize - 1,
&cached);
}
+
+ /* Submit and wait for all bios in the bios list */
+ for (bio = bio_list_pop(&ctrl->bios); bio;
+ bio = bio_list_pop(&ctrl->bios))
+ read_repair_submit_bio(ctrl, bio,
+ get_prev_mirror(mirror, ctrl->num_copies));
+ wait_event(ctrl->io_wait, atomic_read(&ctrl->io_bytes) == 0);
}
static int read_repair_add_sector(struct inode *inode,
@@ -2984,7 +3016,7 @@ static int read_repair_add_sector(struct inode *inode,
ctrl->num_copies = btrfs_num_copies(fs_info, ctrl->logical,
sectorsize);
init_waitqueue_head(&ctrl->io_wait);
- bio_list_init(&ctrl->read_bios);
+ bio_list_init(&ctrl->bios);
atomic_set(&ctrl->io_bytes, 0);
ctrl->cur_bad_bitmap = bitmap_alloc(ctrl->bio_size >>
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index 8b2ccbb2813e..e056ebc7ae01 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -122,7 +122,7 @@ struct btrfs_read_repair_ctrl {
*/
unsigned long *prev_bad_bitmap;
- struct bio_list read_bios;
+ struct bio_list bios;
wait_queue_head_t io_wait;
--
2.36.0
next prev parent reply other threads:[~2022-04-27 7:19 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <cover.1651043617.git.wqu@suse.com>
2022-04-27 7:18 ` [PATCH RFC v2 01/12] btrfs: introduce a pure data checksum checking helper Qu Wenruo
2022-04-28 13:26 ` Christoph Hellwig
2022-04-27 7:18 ` [PATCH RFC v2 02/12] btrfs: always save bio::bi_iter into btrfs_bio::iter before submitting Qu Wenruo
2022-04-28 5:16 ` Qu Wenruo
2022-04-28 13:32 ` Christoph Hellwig
2022-04-28 22:41 ` Qu Wenruo
2022-04-29 15:09 ` Christoph Hellwig
2022-04-29 23:04 ` Qu Wenruo
2022-04-27 7:18 ` [PATCH RFC v2 03/12] btrfs: remove duplicated parameters from submit_data_read_repair() Qu Wenruo
2022-04-28 13:32 ` Christoph Hellwig
2022-04-27 7:18 ` [PATCH RFC v2 04/12] btrfs: add btrfs_read_repair_ctrl to record corrupted sectors Qu Wenruo
2022-04-28 13:37 ` Christoph Hellwig
2022-04-28 22:51 ` Qu Wenruo
2022-04-29 0:09 ` Qu Wenruo
2022-04-29 15:12 ` Christoph Hellwig
2022-04-29 15:11 ` Christoph Hellwig
2022-04-27 7:18 ` [PATCH RFC v2 05/12] btrfs: add a helper to queue a corrupted sector for read repair Qu Wenruo
2022-04-28 5:20 ` Qu Wenruo
2022-04-28 13:44 ` Christoph Hellwig
2022-04-28 22:55 ` Qu Wenruo
2022-04-29 7:11 ` Qu Wenruo
2022-04-29 15:14 ` Christoph Hellwig
2022-04-29 23:08 ` Qu Wenruo
2022-05-01 23:59 ` Qu Wenruo
2022-05-02 16:45 ` Christoph Hellwig
2022-05-02 23:00 ` Qu Wenruo
2022-04-27 7:18 ` [PATCH RFC v2 06/12] btrfs: introduce a helper to repair from one mirror Qu Wenruo
2022-04-27 7:18 ` Qu Wenruo [this message]
2022-04-27 7:18 ` [PATCH RFC v2 08/12] btrfs: switch buffered read to the new btrfs_read_repair_* based repair routine Qu Wenruo
2022-04-27 7:18 ` [PATCH RFC v2 09/12] btrfs: switch direct IO routine to use btrfs_read_repair_ctrl Qu Wenruo
2022-04-27 7:18 ` [PATCH RFC v2 10/12] btrfs: cleanup btrfs_repair_one_sector() Qu Wenruo
2022-04-28 13:45 ` Christoph Hellwig
2022-04-27 7:18 ` [PATCH RFC v2 11/12] btrfs: remove io_failure_record infrastructure completely Qu Wenruo
2022-04-27 7:18 ` [PATCH RFC v2 12/12] btrfs: remove btrfs_inode::io_failure_tree Qu Wenruo
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=834bd7a42f6223794b0bafcbb55b4e167145d024.1651043618.git.wqu@suse.com \
--to=wqu@suse.com \
--cc=linux-btrfs@vger.kernel.org \
/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