--- /dev/null
+From 14cb0dc6479dc5ebc63b3a459a5d89a2f1b39fed Mon Sep 17 00:00:00 2001
+From: Ming Lei <ming.lei@redhat.com>
+Date: Mon, 18 Dec 2017 15:40:43 +0800
+Subject: block: don't let passthrough IO go into .make_request_fn()
+
+From: Ming Lei <ming.lei@redhat.com>
+
+commit 14cb0dc6479dc5ebc63b3a459a5d89a2f1b39fed upstream.
+
+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>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ block/bounce.c | 6 ++++--
+ include/linux/blkdev.h | 21 +++++++++++++++++++--
+ 2 files changed, 23 insertions(+), 4 deletions(-)
+
+--- a/block/bounce.c
++++ b/block/bounce.c
+@@ -200,6 +200,7 @@ static void __blk_queue_bounce(struct re
+ 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 re
+ 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;
+--- a/include/linux/blkdev.h
++++ b/include/linux/blkdev.h
+@@ -241,14 +241,24 @@ struct request {
+ struct request *next_rq;
+ };
+
++static inline bool blk_op_is_scsi(unsigned int op)
++{
++ return op == REQ_OP_SCSI_IN || op == REQ_OP_SCSI_OUT;
++}
++
++static inline bool blk_op_is_private(unsigned int op)
++{
++ return op == REQ_OP_DRV_IN || op == REQ_OP_DRV_OUT;
++}
++
+ static inline bool blk_rq_is_scsi(struct request *rq)
+ {
+- return req_op(rq) == REQ_OP_SCSI_IN || req_op(rq) == REQ_OP_SCSI_OUT;
++ return blk_op_is_scsi(req_op(rq));
+ }
+
+ static inline bool blk_rq_is_private(struct request *rq)
+ {
+- return req_op(rq) == REQ_OP_DRV_IN || req_op(rq) == REQ_OP_DRV_OUT;
++ return blk_op_is_private(req_op(rq));
+ }
+
+ static inline bool blk_rq_is_passthrough(struct request *rq)
+@@ -256,6 +266,13 @@ static inline bool blk_rq_is_passthrough
+ return blk_rq_is_scsi(rq) || blk_rq_is_private(rq);
+ }
+
++static inline bool bio_is_passthrough(struct bio *bio)
++{
++ unsigned op = bio_op(bio);
++
++ return blk_op_is_scsi(op) || blk_op_is_private(op);
++}
++
+ static inline unsigned short req_get_ioprio(struct request *req)
+ {
+ return req->ioprio;
--- /dev/null
+From 0abc2a10389f0c9070f76ca906c7382788036b93 Mon Sep 17 00:00:00 2001
+From: Jens Axboe <axboe@kernel.dk>
+Date: Mon, 18 Dec 2017 15:40:44 +0800
+Subject: block: fix blk_rq_append_bio
+
+From: Jens Axboe <axboe@kernel.dk>
+
+commit 0abc2a10389f0c9070f76ca906c7382788036b93 upstream.
+
+Commit caa4b02476e3(blk-map: call blk_queue_bounce from blk_rq_append_bio)
+moves blk_queue_bounce() into blk_rq_append_bio(), but don't consider
+the fact that the bounced bio becomes invisible to caller since the
+parameter type is 'struct bio *'. Make it a pointer to a pointer to
+a bio, so the caller sees the right bio also after a bounce.
+
+Fixes: caa4b02476e3 ("blk-map: call blk_queue_bounce from blk_rq_append_bio")
+Cc: Christoph Hellwig <hch@lst.de>
+Reported-by: Michele Ballabio <barra_cuda@katamail.com>
+(handling failure of blk_rq_append_bio(), only call bio_get() after
+blk_rq_append_bio() returns OK)
+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>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ block/blk-map.c | 38 +++++++++++++++++++++----------------
+ drivers/scsi/osd/osd_initiator.c | 4 ++-
+ drivers/target/target_core_pscsi.c | 4 +--
+ include/linux/blkdev.h | 2 -
+ 4 files changed, 28 insertions(+), 20 deletions(-)
+
+--- a/block/blk-map.c
++++ b/block/blk-map.c
+@@ -12,22 +12,29 @@
+ #include "blk.h"
+
+ /*
+- * Append a bio to a passthrough request. Only works can be merged into
+- * the request based on the driver constraints.
++ * Append a bio to a passthrough request. Only works if the bio can be merged
++ * into the request based on the driver constraints.
+ */
+-int blk_rq_append_bio(struct request *rq, struct bio *bio)
++int blk_rq_append_bio(struct request *rq, struct bio **bio)
+ {
+- blk_queue_bounce(rq->q, &bio);
++ struct bio *orig_bio = *bio;
++
++ blk_queue_bounce(rq->q, bio);
+
+ if (!rq->bio) {
+- blk_rq_bio_prep(rq->q, rq, bio);
++ blk_rq_bio_prep(rq->q, rq, *bio);
+ } else {
+- if (!ll_back_merge_fn(rq->q, rq, bio))
++ if (!ll_back_merge_fn(rq->q, rq, *bio)) {
++ if (orig_bio != *bio) {
++ bio_put(*bio);
++ *bio = orig_bio;
++ }
+ return -EINVAL;
++ }
+
+- rq->biotail->bi_next = bio;
+- rq->biotail = bio;
+- rq->__data_len += bio->bi_iter.bi_size;
++ rq->biotail->bi_next = *bio;
++ rq->biotail = *bio;
++ rq->__data_len += (*bio)->bi_iter.bi_size;
+ }
+
+ return 0;
+@@ -80,14 +87,12 @@ static int __blk_rq_map_user_iov(struct
+ * We link the bounce buffer in and could have to traverse it
+ * later so we have to get a ref to prevent it from being freed
+ */
+- ret = blk_rq_append_bio(rq, bio);
+- bio_get(bio);
++ ret = blk_rq_append_bio(rq, &bio);
+ if (ret) {
+- bio_endio(bio);
+ __blk_rq_unmap_user(orig_bio);
+- bio_put(bio);
+ return ret;
+ }
++ bio_get(bio);
+
+ return 0;
+ }
+@@ -220,7 +225,7 @@ int blk_rq_map_kern(struct request_queue
+ int reading = rq_data_dir(rq) == READ;
+ unsigned long addr = (unsigned long) kbuf;
+ int do_copy = 0;
+- struct bio *bio;
++ struct bio *bio, *orig_bio;
+ int ret;
+
+ if (len > (queue_max_hw_sectors(q) << 9))
+@@ -243,10 +248,11 @@ int blk_rq_map_kern(struct request_queue
+ if (do_copy)
+ rq->rq_flags |= RQF_COPY_USER;
+
+- ret = blk_rq_append_bio(rq, bio);
++ orig_bio = bio;
++ ret = blk_rq_append_bio(rq, &bio);
+ if (unlikely(ret)) {
+ /* request is too big */
+- bio_put(bio);
++ bio_put(orig_bio);
+ return ret;
+ }
+
+--- a/drivers/scsi/osd/osd_initiator.c
++++ b/drivers/scsi/osd/osd_initiator.c
+@@ -1576,7 +1576,9 @@ static struct request *_make_request(str
+ return req;
+
+ for_each_bio(bio) {
+- ret = blk_rq_append_bio(req, bio);
++ struct bio *bounce_bio = bio;
++
++ ret = blk_rq_append_bio(req, &bounce_bio);
+ if (ret)
+ return ERR_PTR(ret);
+ }
+--- a/drivers/target/target_core_pscsi.c
++++ b/drivers/target/target_core_pscsi.c
+@@ -920,7 +920,7 @@ pscsi_map_sg(struct se_cmd *cmd, struct
+ " %d i: %d bio: %p, allocating another"
+ " bio\n", bio->bi_vcnt, i, bio);
+
+- rc = blk_rq_append_bio(req, bio);
++ rc = blk_rq_append_bio(req, &bio);
+ if (rc) {
+ pr_err("pSCSI: failed to append bio\n");
+ goto fail;
+@@ -938,7 +938,7 @@ pscsi_map_sg(struct se_cmd *cmd, struct
+ }
+
+ if (bio) {
+- rc = blk_rq_append_bio(req, bio);
++ rc = blk_rq_append_bio(req, &bio);
+ if (rc) {
+ pr_err("pSCSI: failed to append bio\n");
+ goto fail;
+--- a/include/linux/blkdev.h
++++ b/include/linux/blkdev.h
+@@ -952,7 +952,7 @@ extern int blk_rq_prep_clone(struct requ
+ extern void blk_rq_unprep_clone(struct request *rq);
+ extern blk_status_t blk_insert_cloned_request(struct request_queue *q,
+ struct request *rq);
+-extern int blk_rq_append_bio(struct request *rq, struct bio *bio);
++extern int blk_rq_append_bio(struct request *rq, struct bio **bio);
+ extern void blk_delay_queue(struct request_queue *, unsigned long);
+ extern void blk_queue_split(struct request_queue *, struct bio **);
+ extern void blk_recount_segments(struct request_queue *, struct bio *);