From: Guoqing Jiang jgq516@gmail.com
mainline inclusion from mainline-v5.14-rc1 commit 1147f58e1010b8688bac1fd3bbab753b1379291d category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I587H6 CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
-------------------------------
After enable io accounting, chunk read bio could be cloned twice which is not good. To avoid such inefficiency, let's clone align_bio from io_acct_set too, then we need only call md_account_bio in make_request unconditionally.
Signed-off-by: Guoqing Jiang jiangguoqing@kylinos.cn Signed-off-by: Song Liu song@kernel.org Conflict: drivers/md/raid5.c Signed-off-by: Zhang Wensheng zhangwensheng5@huawei.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/md/raid5.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 35dacc6e754f..7103f3e330a7 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5364,11 +5364,13 @@ static struct bio *remove_bio_from_retry(struct r5conf *conf, */ static void raid5_align_endio(struct bio *bi) { - struct bio* raid_bi = bi->bi_private; + struct md_io_acct *md_io_acct = bi->bi_private; + struct bio *raid_bi = md_io_acct->orig_bio; struct mddev *mddev; struct r5conf *conf; struct md_rdev *rdev; blk_status_t error = bi->bi_status; + unsigned long start_time = md_io_acct->start_time;
bio_put(bi);
@@ -5380,6 +5382,8 @@ static void raid5_align_endio(struct bio *bi) rdev_dec_pending(rdev, conf->mddev);
if (!error) { + if (blk_queue_io_stat(raid_bi->bi_disk->queue)) + bio_end_io_acct(raid_bi, start_time); bio_endio(raid_bi); if (atomic_dec_and_test(&conf->active_aligned_reads)) wake_up(&conf->wait_for_quiescent); @@ -5398,6 +5402,7 @@ static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio) struct bio* align_bi; struct md_rdev *rdev; sector_t end_sector; + struct md_io_acct *md_io_acct;
if (!in_chunk_boundary(mddev, raid_bio)) { pr_debug("%s: non aligned\n", __func__); @@ -5406,15 +5411,20 @@ static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio) /* * use bio_clone_fast to make a copy of the bio */ - align_bi = bio_clone_fast(raid_bio, GFP_NOIO, &mddev->bio_set); + align_bi = bio_clone_fast(raid_bio, GFP_NOIO, &mddev->io_acct_set); if (!align_bi) return 0; + md_io_acct = container_of(align_bi, struct md_io_acct, bio_clone); + raid_bio->bi_next = (void *)rdev; + if (blk_queue_io_stat(raid_bio->bi_disk->queue)) + md_io_acct->start_time = bio_start_io_acct(raid_bio); + md_io_acct->orig_bio = raid_bio; /* * set bi_end_io to a new function, and set bi_private to the * original bio. */ align_bi->bi_end_io = raid5_align_endio; - align_bi->bi_private = raid_bio; + align_bi->bi_private = md_io_acct; /* * compute position */ @@ -5487,7 +5497,6 @@ static struct bio *chunk_aligned_read(struct mddev *mddev, struct bio *raid_bio) sector_t sector = raid_bio->bi_iter.bi_sector; unsigned chunk_sects = mddev->chunk_sectors; unsigned sectors = chunk_sects - (sector & (chunk_sects-1)); - struct r5conf *conf = mddev->private;
if (sectors < bio_sectors(raid_bio)) { struct r5conf *conf = mddev->private; @@ -5497,9 +5506,6 @@ static struct bio *chunk_aligned_read(struct mddev *mddev, struct bio *raid_bio) raid_bio = split; }
- if (raid_bio->bi_pool != &conf->bio_split) - md_account_bio(mddev, &raid_bio); - if (!raid5_read_one_chunk(mddev, raid_bio)) return raid_bio;
@@ -5779,7 +5785,6 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi) DEFINE_WAIT(w); bool do_prepare; bool do_flush = false; - bool do_clone = false;
if (unlikely(bi->bi_opf & REQ_PREFLUSH)) { int ret = log_handle_flush_request(conf, bi); @@ -5808,7 +5813,6 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi) if (rw == READ && mddev->degraded == 0 && mddev->reshape_position == MaxSector) { bi = chunk_aligned_read(mddev, bi); - do_clone = true; if (!bi) return true; } @@ -5823,9 +5827,7 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi) last_sector = bio_end_sector(bi); bi->bi_next = NULL;
- if (!do_clone) - md_account_bio(mddev, &bi); - + md_account_bio(mddev, &bi); prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE); for (; logical_sector < last_sector; logical_sector += RAID5_STRIPE_SECTORS(conf)) { int previous;