Commit 5a8d75a1 authored by Ming Lei's avatar Ming Lei Committed by Jens Axboe

block: fix bio_will_gap() for first bvec with offset

Commit 729204ef("block: relax check on sg gap") allows us to merge
bios, if both are physically contiguous.  This change can merge a huge
number of small bios, through mkfs for example, mkfs.ntfs running time
can be decreased to ~1/10.

But if one rq starts with a non-aligned buffer (the 1st bvec's bv_offset
is non-zero) and if we allow the merge, it is quite difficult to respect
sg gap limit, especially the max segment size, or we risk having an
unaligned virtual boundary.  This patch tries to avoid the issue by
disallowing a merge, if the req starts with an unaligned buffer.

Also add comments to explain why the merged segment can't end in
unaligned virt boundary.

Fixes: 729204ef ("block: relax check on sg gap")
Tested-by: default avatarJohannes Thumshirn <jthumshirn@suse.de>
Reviewed-by: default avatarJohannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: default avatarMing Lei <ming.lei@redhat.com>

Rewrote parts of the commit message and comments.
Signed-off-by: default avatarJens Axboe <axboe@fb.com>
parent c6c64a94
...@@ -1672,12 +1672,36 @@ static inline bool bios_segs_mergeable(struct request_queue *q, ...@@ -1672,12 +1672,36 @@ static inline bool bios_segs_mergeable(struct request_queue *q,
return true; return true;
} }
static inline bool bio_will_gap(struct request_queue *q, struct bio *prev, static inline bool bio_will_gap(struct request_queue *q,
struct bio *next) struct request *prev_rq,
struct bio *prev,
struct bio *next)
{ {
if (bio_has_data(prev) && queue_virt_boundary(q)) { if (bio_has_data(prev) && queue_virt_boundary(q)) {
struct bio_vec pb, nb; struct bio_vec pb, nb;
/*
* don't merge if the 1st bio starts with non-zero
* offset, otherwise it is quite difficult to respect
* sg gap limit. We work hard to merge a huge number of small
* single bios in case of mkfs.
*/
if (prev_rq)
bio_get_first_bvec(prev_rq->bio, &pb);
else
bio_get_first_bvec(prev, &pb);
if (pb.bv_offset)
return true;
/*
* We don't need to worry about the situation that the
* merged segment ends in unaligned virt boundary:
*
* - if 'pb' ends aligned, the merged segment ends aligned
* - if 'pb' ends unaligned, the next bio must include
* one single bvec of 'nb', otherwise the 'nb' can't
* merge with 'pb'
*/
bio_get_last_bvec(prev, &pb); bio_get_last_bvec(prev, &pb);
bio_get_first_bvec(next, &nb); bio_get_first_bvec(next, &nb);
...@@ -1690,12 +1714,12 @@ static inline bool bio_will_gap(struct request_queue *q, struct bio *prev, ...@@ -1690,12 +1714,12 @@ static inline bool bio_will_gap(struct request_queue *q, struct bio *prev,
static inline bool req_gap_back_merge(struct request *req, struct bio *bio) static inline bool req_gap_back_merge(struct request *req, struct bio *bio)
{ {
return bio_will_gap(req->q, req->biotail, bio); return bio_will_gap(req->q, req, req->biotail, bio);
} }
static inline bool req_gap_front_merge(struct request *req, struct bio *bio) static inline bool req_gap_front_merge(struct request *req, struct bio *bio)
{ {
return bio_will_gap(req->q, bio, req->bio); return bio_will_gap(req->q, NULL, bio, req->bio);
} }
int kblockd_schedule_work(struct work_struct *work); int kblockd_schedule_work(struct work_struct *work);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment