Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1344361 > unrolled thread

[PATCH v2 0/4] block: fix bio_will_gap()

Started byMing Lei <ming.lei@canonical.com>
First post2016-02-26 16:50 +0100
Last post2016-02-28 11:00 +0100
Articles 4 — 2 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH v2 0/4] block: fix bio_will_gap() Ming Lei <ming.lei@canonical.com> - 2016-02-26 16:50 +0100
    [PATCH v2 4/4] block: merge: get the 1st and last bvec via helpers Ming Lei <ming.lei@canonical.com> - 2016-02-26 16:50 +0100
    [PATCH v2 2/4] block: check virt boundary in bio_will_gap() Ming Lei <ming.lei@canonical.com> - 2016-02-26 16:50 +0100
    Re: [PATCH v2 0/4] block: fix bio_will_gap() Sagi Grimberg <sagig@dev.mellanox.co.il> - 2016-02-28 11:00 +0100

#1344361 — [PATCH v2 0/4] block: fix bio_will_gap()

FromMing Lei <ming.lei@canonical.com>
Date2016-02-26 16:50 +0100
Subject[PATCH v2 0/4] block: fix bio_will_gap()
Message-ID<r6sOt-5pp-9@gated-at.bofh.it>
Hi Guys,

The bio passed to bio_will_gap() may be fast cloned from upper
layer(dm, md, bcache, fs, ...), or from bio splitting in block
core. Unfortunately bio_will_gap() just figures out the last
bvec via 'bi_io_vec[prev->bi_vcnt - 1]' directly, and this way
is obviously wrong in case of fast-cloned bio.

It is observed that lots of BIOs are still merged even if
the virt boundary limit is violated by the merge, and the issue
was reported from Sagi Grimberg.

This patch introduces two helpers for getting the first and last
bvec of one bio and applys them to fix the issue. Sagi has confirmed
the fix.

Thanks for Sagi and Christoph's review.

V2:
	- remove unnecessary comment
	- add reviewed-by

V1:
	- get bvec directly for non-cloned bio
	- implement bio_get_last_bvec() with single bio_advance_iter(),
	and avoid to use bio_for_each_segment() which looks a bit inefficient
	- avoid to double check queue_virt_boundary() in bio_will_gap()

 block/blk-merge.c      |  8 ++------
 include/linux/bio.h    | 37 +++++++++++++++++++++++++++++++++++++
 include/linux/blkdev.h | 23 +++++++++++++++++------
 3 files changed, 56 insertions(+), 12 deletions(-)


Thanks,
Ming

[toc] | [next] | [standalone]


#1344363 — [PATCH v2 4/4] block: merge: get the 1st and last bvec via helpers

FromMing Lei <ming.lei@canonical.com>
Date2016-02-26 16:50 +0100
Subject[PATCH v2 4/4] block: merge: get the 1st and last bvec via helpers
Message-ID<r6sOu-5pp-37@gated-at.bofh.it>
In reply to#1344361
This patch applies the two introduced helpers to
figure out the 1st and last bvec.

Reviewed-by: Sagi Grimberg <sagig@mellanox.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Ming Lei <ming.lei@canonical.com>
---
 block/blk-merge.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/block/blk-merge.c b/block/blk-merge.c
index 888a7fe..2613531 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -304,7 +304,6 @@ static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio,
 				   struct bio *nxt)
 {
 	struct bio_vec end_bv = { NULL }, nxt_bv;
-	struct bvec_iter iter;
 
 	if (!blk_queue_cluster(q))
 		return 0;
@@ -316,11 +315,8 @@ static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio,
 	if (!bio_has_data(bio))
 		return 1;
 
-	bio_for_each_segment(end_bv, bio, iter)
-		if (end_bv.bv_len == iter.bi_size)
-			break;
-
-	nxt_bv = bio_iovec(nxt);
+	bio_get_last_bvec(bio, &end_bv);
+	bio_get_first_bvec(nxt, &nxt_bv);
 
 	if (!BIOVEC_PHYS_MERGEABLE(&end_bv, &nxt_bv))
 		return 0;
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1344365 — [PATCH v2 2/4] block: check virt boundary in bio_will_gap()

FromMing Lei <ming.lei@canonical.com>
Date2016-02-26 16:50 +0100
Subject[PATCH v2 2/4] block: check virt boundary in bio_will_gap()
Message-ID<r6sOv-5pp-49@gated-at.bofh.it>
In reply to#1344361
In the following patch, the way for figuring out
the last bvec will be changed with a bit cost introduced,
so return immediately if the queue doesn't have virt
boundary limit. Actually most of devices have not
this limit.

Reviewed-by: Sagi Grimberg <sagig@mellanox.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Ming Lei <ming.lei@canonical.com>
---
 include/linux/blkdev.h | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 4571ef1..cd06a41 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1372,6 +1372,13 @@ static inline void put_dev_sector(Sector p)
 	page_cache_release(p.v);
 }
 
+static inline bool __bvec_gap_to_prev(struct request_queue *q,
+				struct bio_vec *bprv, unsigned int offset)
+{
+	return offset ||
+		((bprv->bv_offset + bprv->bv_len) & queue_virt_boundary(q));
+}
+
 /*
  * Check if adding a bio_vec after bprv with offset would create a gap in
  * the SG list. Most drivers don't care about this, but some do.
@@ -1381,18 +1388,17 @@ static inline bool bvec_gap_to_prev(struct request_queue *q,
 {
 	if (!queue_virt_boundary(q))
 		return false;
-	return offset ||
-		((bprv->bv_offset + bprv->bv_len) & queue_virt_boundary(q));
+	return __bvec_gap_to_prev(q, bprv, offset);
 }
 
 static inline bool bio_will_gap(struct request_queue *q, struct bio *prev,
 			 struct bio *next)
 {
-	if (!bio_has_data(prev))
+	if (!bio_has_data(prev) || !queue_virt_boundary(q))
 		return false;
 
-	return bvec_gap_to_prev(q, &prev->bi_io_vec[prev->bi_vcnt - 1],
-				next->bi_io_vec[0].bv_offset);
+	return __bvec_gap_to_prev(q, &prev->bi_io_vec[prev->bi_vcnt - 1],
+				  next->bi_io_vec[0].bv_offset);
 }
 
 static inline bool req_gap_back_merge(struct request *req, struct bio *bio)
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1345200

FromSagi Grimberg <sagig@dev.mellanox.co.il>
Date2016-02-28 11:00 +0100
Message-ID<r76iS-q5-7@gated-at.bofh.it>
In reply to#1344361
Still looks good, still want it for 4.5 :)

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web