]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 30 Dec 2017 16:36:28 +0000 (17:36 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 30 Dec 2017 16:36:28 +0000 (17:36 +0100)
added patches:
block-don-t-let-passthrough-io-go-into-.make_request_fn.patch
block-fix-blk_rq_append_bio.patch

queue-4.14/block-don-t-let-passthrough-io-go-into-.make_request_fn.patch [new file with mode: 0644]
queue-4.14/block-fix-blk_rq_append_bio.patch [new file with mode: 0644]
queue-4.14/series

diff --git a/queue-4.14/block-don-t-let-passthrough-io-go-into-.make_request_fn.patch b/queue-4.14/block-don-t-let-passthrough-io-go-into-.make_request_fn.patch
new file mode 100644 (file)
index 0000000..d1f3859
--- /dev/null
@@ -0,0 +1,103 @@
+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;
diff --git a/queue-4.14/block-fix-blk_rq_append_bio.patch b/queue-4.14/block-fix-blk_rq_append_bio.patch
new file mode 100644 (file)
index 0000000..3649f26
--- /dev/null
@@ -0,0 +1,157 @@
+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 *);
index 7020f74efc2d42ba73bcf02799b487fe1d4a5e5c..681d35384498df116b39d9a46d13ede92447ae09 100644 (file)
@@ -53,3 +53,5 @@ alsa-hda-change-the-location-for-one-mic-on-a-lenovo-machine.patch
 alsa-hda-fix-headset-mic-detection-issue-on-a-dell-machine.patch
 alsa-hda-fix-missing-coef-init-for-alc225-295-299.patch
 cpufreq-schedutil-use-idle_calls-counter-of-the-remote-cpu.patch
+block-fix-blk_rq_append_bio.patch
+block-don-t-let-passthrough-io-go-into-.make_request_fn.patch