All of lore.kernel.org
 help / color / mirror / Atom feed
From: NeilBrown <neilb@suse.com>
To: Jens Axboe <axboe@kernel.dk>
Cc: linux-block@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH 04/11] block: Improvements to bounce-buffer handling
Date: Thu, 20 Apr 2017 15:38:49 +1000	[thread overview]
Message-ID: <149266672902.27388.15322863417005890204.stgit@noble> (raw)
In-Reply-To: <149266645258.27388.14083229348123176454.stgit@noble>

Since commit 23688bf4f830 ("block: ensure to split after potentially
bouncing a bio") blk_queue_bounce() is called *before*
blk_queue_split().
This means that:
 1/ the comments blk_queue_split() about bounce buffers are
    irrelevant, and
 2/ a very large bio (more than BIO_MAX_PAGES) will no longer be
    split before it arrives at blk_queue_bounce(), leading to the
    possibility that bio_clone_bioset() will fail and a NULL
    will be dereferenced.

Separately, blk_queue_bounce() shouldn't use fs_bio_set as the bio
being copied could be from the same set, and this could lead to a
deadlock.

So:
 - allocate 2 private biosets for blk_queue_bounce, one for
   splitting enormous bios and one for cloning bios.
 - add code to split a bio that exceeds BIO_MAX_PAGES.
 - Fix up the comments in blk_queue_split()

Signed-off-by: NeilBrown <neilb@suse.com>
---
 block/blk-merge.c |   14 ++++----------
 block/bounce.c    |   27 ++++++++++++++++++++++++++-
 2 files changed, 30 insertions(+), 11 deletions(-)

diff --git a/block/blk-merge.c b/block/blk-merge.c
index d59074556703..51c84540d3bb 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -117,17 +117,11 @@ static struct bio *blk_bio_segment_split(struct request_queue *q,
 		 * each holds at most BIO_MAX_PAGES bvecs because
 		 * bio_clone() can fail to allocate big bvecs.
 		 *
-		 * It should have been better to apply the limit per
-		 * request queue in which bio_clone() is involved,
-		 * instead of globally. The biggest blocker is the
-		 * bio_clone() in bio bounce.
+		 * Those drivers which will need to use bio_clone()
+		 * should tell us in some way.  For now, impose the
+		 * BIO_MAX_PAGES limit on all queues.
 		 *
-		 * If bio is splitted by this reason, we should have
-		 * allowed to continue bios merging, but don't do
-		 * that now for making the change simple.
-		 *
-		 * TODO: deal with bio bounce's bio_clone() gracefully
-		 * and convert the global limit into per-queue limit.
+		 * TODO: handle users of bio_clone() differently.
 		 */
 		if (bvecs++ >= BIO_MAX_PAGES)
 			goto split;
diff --git a/block/bounce.c b/block/bounce.c
index 1cb5dd3a5da1..51fb538b504d 100644
--- a/block/bounce.c
+++ b/block/bounce.c
@@ -26,6 +26,7 @@
 #define POOL_SIZE	64
 #define ISA_POOL_SIZE	16
 
+struct bio_set *bounce_bio_set, *bounce_bio_split;
 static mempool_t *page_pool, *isa_page_pool;
 
 #if defined(CONFIG_HIGHMEM) || defined(CONFIG_NEED_BOUNCE_POOL)
@@ -40,6 +41,14 @@ static __init int init_emergency_pool(void)
 	BUG_ON(!page_pool);
 	pr_info("pool size: %d pages\n", POOL_SIZE);
 
+	bounce_bio_set = bioset_create(BIO_POOL_SIZE, 0);
+	BUG_ON(!bounce_bio_set);
+	if (bioset_integrity_create(bounce_bio_set, BIO_POOL_SIZE))
+		BUG_ON(1);
+
+	bounce_bio_split = bioset_create_nobvec(BIO_POOL_SIZE, 0);
+	BUG_ON(!bounce_bio_split);
+
 	return 0;
 }
 
@@ -194,7 +203,23 @@ static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig,
 
 	return;
 bounce:
-	bio = bio_clone_bioset(*bio_orig, GFP_NOIO, fs_bio_set);
+	if (bio_segments(*bio_orig) > BIO_MAX_PAGES) {
+		int cnt = 0;
+		int sectors = 0;
+		struct bio_vec bv;
+		struct bvec_iter iter;
+		bio_for_each_segment(bv, *bio_orig, iter) {
+			if (cnt++ < BIO_MAX_PAGES)
+				sectors += bv.bv_len >> 9;
+			else
+				break;
+		}
+		bio = bio_split(*bio_orig, sectors, GFP_NOIO, bounce_bio_split);
+		bio_chain(bio, *bio_orig);
+		generic_make_request(*bio_orig);
+		*bio_orig = bio;
+	}
+	bio = bio_clone_bioset(*bio_orig, GFP_NOIO, bounce_bio_set);
 
 	bio_for_each_segment_all(to, bio, i) {
 		struct page *page = to->bv_page;

  parent reply	other threads:[~2017-04-20  5:38 UTC|newest]

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-04-20  5:38 [PATCH 00/10] block: assorted cleanup for bio splitting and cloning NeilBrown
2017-04-20  5:38 ` NeilBrown
2017-04-20  5:38 ` [PATCH 00/11] " NeilBrown
2017-04-20  5:38 ` [PATCH 01/11] blk: remove bio_set arg from blk_queue_split() NeilBrown
2017-04-21 11:21   ` Christoph Hellwig
2017-04-21 15:14   ` Ming Lei
2017-04-22  9:16   ` Javier González
2017-04-24  2:32     ` NeilBrown
2017-04-20  5:38 ` [PATCH 02/11] blk: make the bioset rescue_workqueue optional NeilBrown
2017-04-21 11:24   ` Christoph Hellwig
2017-04-24  1:51     ` NeilBrown
2017-04-24 15:10       ` Christoph Hellwig
2017-05-01  5:00         ` NeilBrown
2017-05-01 14:02           ` Jens Axboe
2017-05-02  3:33             ` NeilBrown
2017-04-20  5:38 ` [PATCH 07/11] pktcdvd: use bio_clone_fast() instead of bio_clone() NeilBrown
2017-04-21 11:29   ` Christoph Hellwig
2017-04-20  5:38 ` [PATCH 05/11] rbd: " NeilBrown
2017-04-20  5:38   ` NeilBrown
2017-04-21 11:31   ` Christoph Hellwig
2017-04-20  5:38 ` [PATCH 03/11] blk: use non-rescuing bioset for q->bio_split NeilBrown
2017-04-21 11:25   ` Christoph Hellwig
2017-04-20  5:38 ` NeilBrown [this message]
2017-04-21 11:28   ` [PATCH 04/11] block: Improvements to bounce-buffer handling Christoph Hellwig
2017-04-21 15:39   ` Ming Lei
2017-04-20  5:38 ` [PATCH 06/11] drbd: use bio_clone_fast() instead of bio_clone() NeilBrown
2017-04-21 11:30   ` Christoph Hellwig
2017-04-20  5:38 ` [PATCH 09/11] bcache: use kmalloc to allocate bio in bch_data_verify() NeilBrown
2017-04-20  5:38   ` NeilBrown
2017-04-21 11:31   ` Christoph Hellwig
2017-04-21 11:32   ` Kent Overstreet
2017-04-21 15:41   ` Ming Lei
2017-04-20  5:38 ` [PATCH 08/11] xen-blkfront: remove bio splitting NeilBrown
2017-04-20  5:38   ` NeilBrown
2017-04-20  5:38   ` NeilBrown
2017-04-20 10:00   ` Roger Pau Monné
2017-04-20 10:00   ` Roger Pau Monné
2017-04-20 10:00     ` Roger Pau Monné
2017-04-21 11:36   ` Christoph Hellwig
2017-04-21 11:36   ` Christoph Hellwig
2017-04-21 11:46     ` Roger Pau Monne
2017-04-21 11:46     ` Roger Pau Monne
2017-04-20  5:38 ` [PATCH 11/11] block: don't check for BIO_MAX_PAGES in blk_bio_segment_split() NeilBrown
2017-04-21 11:34   ` Christoph Hellwig
2017-04-21 15:48     ` Ming Lei
2017-04-24  3:16       ` NeilBrown
2017-04-24  3:14     ` NeilBrown
2017-04-20  5:38 ` [PATCH 10/11] block: remove bio_clone() and all references NeilBrown
2017-04-21 11:32   ` Christoph Hellwig
2017-04-21 15:43   ` Ming Lei

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=149266672902.27388.15322863417005890204.stgit@noble \
    --to=neilb@suse.com \
    --cc=axboe@kernel.dk \
    --cc=linux-block@vger.kernel.org \
    --cc=linux-kernel@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.