summaryrefslogtreecommitdiffstats
path: root/block/bounce.c
diff options
context:
space:
mode:
authorMing Lei <ming.lei@redhat.com>2017-12-18 15:40:43 +0800
committerJens Axboe <axboe@kernel.dk>2017-12-18 13:55:43 -0700
commit14cb0dc6479dc5ebc63b3a459a5d89a2f1b39fed (patch)
treedb336ec3ba6267370615b5bc60c104f03f924bef /block/bounce.c
parenta9fa99146ab4fc029ba5551a1a3a0102fae7fddf (diff)
downloadlinux-0-day-14cb0dc6479dc5ebc63b3a459a5d89a2f1b39fed.tar.gz
linux-0-day-14cb0dc6479dc5ebc63b3a459a5d89a2f1b39fed.tar.xz
block: don't let passthrough IO go into .make_request_fn()
Commit a8821f3f3("block: Improvements to bounce-buffer handling") tries to make sure that the bio to .make_request_fn won't exceed BIO_MAX_PAGES, but ignores that passthrough I/O can use blk_queue_bounce() too. Especially, passthrough IO may not be sector-aligned, and the check of 'sectors < bio_sectors(*bio_orig)' inside __blk_queue_bounce() may become true even though the max bvec number doesn't exceed BIO_MAX_PAGES, then cause the bio splitted, and the original passthrough bio is submited to generic_make_request(). This patch fixes this issue by checking if the bio is passthrough IO, and use bio_kmalloc() to allocate the cloned passthrough bio. Cc: NeilBrown <neilb@suse.com> Fixes: a8821f3f3("block: Improvements to bounce-buffer handling") Tested-by: Michele Ballabio <barra_cuda@katamail.com> Signed-off-by: Ming Lei <ming.lei@redhat.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block/bounce.c')
-rw-r--r--block/bounce.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/block/bounce.c b/block/bounce.c
index fceb1a96480bf..1d05c422c932a 100644
--- a/block/bounce.c
+++ b/block/bounce.c
@@ -200,6 +200,7 @@ static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig,
unsigned i = 0;
bool bounce = false;
int sectors = 0;
+ bool passthrough = bio_is_passthrough(*bio_orig);
bio_for_each_segment(from, *bio_orig, iter) {
if (i++ < BIO_MAX_PAGES)
@@ -210,13 +211,14 @@ static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig,
if (!bounce)
return;
- if (sectors < bio_sectors(*bio_orig)) {
+ if (!passthrough && sectors < bio_sectors(*bio_orig)) {
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 = bio_clone_bioset(*bio_orig, GFP_NOIO, passthrough ? NULL :
+ bounce_bio_set);
bio_for_each_segment_all(to, bio, i) {
struct page *page = to->bv_page;