diff mbox series

[RFC,1/2] block: add a function for *segment_split fast path

Message ID a46250fdd157adda8b46e51518ea29116c6663f3.1609875589.git.asml.silence@gmail.com (mailing list archive)
State New, archived
Headers show
Series optimise split bio | expand

Commit Message

Pavel Begunkov Jan. 5, 2021, 7:43 p.m. UTC
Don't keep blk_bio_segment_split()'s fast path hand coded in
__blk_queue_split(), extract it into a function. It's inlined perfectly
well.

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
 block/blk-merge.c | 84 ++++++++++++++++++++++++++---------------------
 1 file changed, 46 insertions(+), 38 deletions(-)
diff mbox series

Patch

diff --git a/block/blk-merge.c b/block/blk-merge.c
index 808768f6b174..84b9635b5d57 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -223,29 +223,10 @@  static bool bvec_split_segs(const struct request_queue *q,
 	return len > 0 || bv->bv_len > max_len;
 }
 
-/**
- * blk_bio_segment_split - split a bio in two bios
- * @q:    [in] request queue pointer
- * @bio:  [in] bio to be split
- * @bs:	  [in] bio set to allocate the clone from
- * @segs: [out] number of segments in the bio with the first half of the sectors
- *
- * Clone @bio, update the bi_iter of the clone to represent the first sectors
- * of @bio and update @bio->bi_iter to represent the remaining sectors. The
- * following is guaranteed for the cloned bio:
- * - That it has at most get_max_io_size(@q, @bio) sectors.
- * - That it has at most queue_max_segments(@q) segments.
- *
- * Except for discard requests the cloned bio will point at the bi_io_vec of
- * the original bio. It is the responsibility of the caller to ensure that the
- * original bio is not freed before the cloned bio. The caller is also
- * responsible for ensuring that @bs is only destroyed after processing of the
- * split bio has finished.
- */
-static struct bio *blk_bio_segment_split(struct request_queue *q,
-					 struct bio *bio,
-					 struct bio_set *bs,
-					 unsigned *segs)
+static struct bio *__blk_bio_segment_split(struct request_queue *q,
+					   struct bio *bio,
+					   struct bio_set *bs,
+					   unsigned *segs)
 {
 	struct bio_vec bv, bvprv, *bvprvp = NULL;
 	struct bvec_iter iter;
@@ -290,6 +271,48 @@  static struct bio *blk_bio_segment_split(struct request_queue *q,
 	return bio_split(bio, sectors, GFP_NOIO, bs);
 }
 
+/**
+ * blk_bio_segment_split - split a bio in two bios
+ * @q:    [in] request queue pointer
+ * @bio:  [in] bio to be split
+ * @bs:	  [in] bio set to allocate the clone from
+ * @segs: [out] number of segments in the bio with the first half of the sectors
+ *
+ * Clone @bio, update the bi_iter of the clone to represent the first sectors
+ * of @bio and update @bio->bi_iter to represent the remaining sectors. The
+ * following is guaranteed for the cloned bio:
+ * - That it has at most get_max_io_size(@q, @bio) sectors.
+ * - That it has at most queue_max_segments(@q) segments.
+ *
+ * Except for discard requests the cloned bio will point at the bi_io_vec of
+ * the original bio. It is the responsibility of the caller to ensure that the
+ * original bio is not freed before the cloned bio. The caller is also
+ * responsible for ensuring that @bs is only destroyed after processing of the
+ * split bio has finished.
+ */
+static inline struct bio *blk_bio_segment_split(struct request_queue *q,
+						struct bio *bio,
+						struct bio_set *bs,
+						unsigned *nr_segs)
+{
+	/*
+	 * All drivers must accept single-segments bios that are <=
+	 * PAGE_SIZE.  This is a quick and dirty check that relies on
+	 * the fact that bi_io_vec[0] is always valid if a bio has data.
+	 * The check might lead to occasional false negatives when bios
+	 * are cloned, but compared to the performance impact of cloned
+	 * bios themselves the loop below doesn't matter anyway.
+	 */
+	if (!q->limits.chunk_sectors && bio->bi_vcnt == 1 &&
+	    (bio->bi_io_vec[0].bv_len +
+	     bio->bi_io_vec[0].bv_offset) <= PAGE_SIZE) {
+		*nr_segs = 1;
+		return NULL;
+	}
+
+	return __blk_bio_segment_split(q, bio, bs, nr_segs);
+}
+
 /**
  * __blk_queue_split - split a bio and submit the second half
  * @bio:     [in, out] bio to be split
@@ -322,21 +345,6 @@  void __blk_queue_split(struct bio **bio, unsigned int *nr_segs)
 				nr_segs);
 		break;
 	default:
-		/*
-		 * All drivers must accept single-segments bios that are <=
-		 * PAGE_SIZE.  This is a quick and dirty check that relies on
-		 * the fact that bi_io_vec[0] is always valid if a bio has data.
-		 * The check might lead to occasional false negatives when bios
-		 * are cloned, but compared to the performance impact of cloned
-		 * bios themselves the loop below doesn't matter anyway.
-		 */
-		if (!q->limits.chunk_sectors &&
-		    (*bio)->bi_vcnt == 1 &&
-		    ((*bio)->bi_io_vec[0].bv_len +
-		     (*bio)->bi_io_vec[0].bv_offset) <= PAGE_SIZE) {
-			*nr_segs = 1;
-			break;
-		}
 		split = blk_bio_segment_split(q, *bio, &q->bio_split, nr_segs);
 		break;
 	}