]> git.proxmox.com Git - pve-kernel.git/commitdiff
add follow-up fix for NVME driver
authorFabian Grünbichler <f.gruenbichler@proxmox.com>
Wed, 2 Aug 2017 12:48:03 +0000 (14:48 +0200)
committerFabian Grünbichler <f.gruenbichler@proxmox.com>
Fri, 4 Aug 2017 11:09:45 +0000 (13:09 +0200)
fixes a BUG_ON triggered by Samsung SM960 Pro NVME devices

0001-block-fix-bio_will_gap-for-first-bvec-with-offset.patch [new file with mode: 0644]
Makefile

diff --git a/0001-block-fix-bio_will_gap-for-first-bvec-with-offset.patch b/0001-block-fix-bio_will_gap-for-first-bvec-with-offset.patch
new file mode 100644 (file)
index 0000000..aed9a58
--- /dev/null
@@ -0,0 +1,96 @@
+From 5a8d75a1b8c99bdc926ba69b7b7dbe4fae81a5af Mon Sep 17 00:00:00 2001
+From: Ming Lei <ming.lei@redhat.com>
+Date: Fri, 14 Apr 2017 13:58:29 -0600
+Subject: [PATCH] block: fix bio_will_gap() for first bvec with offset
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Commit 729204ef49ec("block: relax check on sg gap") allows us to merge
+bios, if both are physically contiguous.  This change can merge a huge
+number of small bios, through mkfs for example, mkfs.ntfs running time
+can be decreased to ~1/10.
+
+But if one rq starts with a non-aligned buffer (the 1st bvec's bv_offset
+is non-zero) and if we allow the merge, it is quite difficult to respect
+sg gap limit, especially the max segment size, or we risk having an
+unaligned virtual boundary.  This patch tries to avoid the issue by
+disallowing a merge, if the req starts with an unaligned buffer.
+
+Also add comments to explain why the merged segment can't end in
+unaligned virt boundary.
+
+Fixes: 729204ef49ec ("block: relax check on sg gap")
+Tested-by: Johannes Thumshirn <jthumshirn@suse.de>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+Signed-off-by: Ming Lei <ming.lei@redhat.com>
+
+Rewrote parts of the commit message and comments.
+
+Signed-off-by: Jens Axboe <axboe@fb.com>
+Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
+---
+ include/linux/blkdev.h | 32 ++++++++++++++++++++++++++++----
+ 1 file changed, 28 insertions(+), 4 deletions(-)
+
+diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
+index 7548f332121a..01a696b0a4d3 100644
+--- a/include/linux/blkdev.h
++++ b/include/linux/blkdev.h
+@@ -1672,12 +1672,36 @@ static inline bool bios_segs_mergeable(struct request_queue *q,
+       return true;
+ }
+-static inline bool bio_will_gap(struct request_queue *q, struct bio *prev,
+-                       struct bio *next)
++static inline bool bio_will_gap(struct request_queue *q,
++                              struct request *prev_rq,
++                              struct bio *prev,
++                              struct bio *next)
+ {
+       if (bio_has_data(prev) && queue_virt_boundary(q)) {
+               struct bio_vec pb, nb;
++              /*
++               * don't merge if the 1st bio starts with non-zero
++               * offset, otherwise it is quite difficult to respect
++               * sg gap limit. We work hard to merge a huge number of small
++               * single bios in case of mkfs.
++               */
++              if (prev_rq)
++                      bio_get_first_bvec(prev_rq->bio, &pb);
++              else
++                      bio_get_first_bvec(prev, &pb);
++              if (pb.bv_offset)
++                      return true;
++
++              /*
++               * We don't need to worry about the situation that the
++               * merged segment ends in unaligned virt boundary:
++               *
++               * - if 'pb' ends aligned, the merged segment ends aligned
++               * - if 'pb' ends unaligned, the next bio must include
++               *   one single bvec of 'nb', otherwise the 'nb' can't
++               *   merge with 'pb'
++               */
+               bio_get_last_bvec(prev, &pb);
+               bio_get_first_bvec(next, &nb);
+@@ -1690,12 +1714,12 @@ static inline bool bio_will_gap(struct request_queue *q, struct bio *prev,
+ static inline bool req_gap_back_merge(struct request *req, struct bio *bio)
+ {
+-      return bio_will_gap(req->q, req->biotail, bio);
++      return bio_will_gap(req->q, req, req->biotail, bio);
+ }
+ static inline bool req_gap_front_merge(struct request *req, struct bio *bio)
+ {
+-      return bio_will_gap(req->q, bio, req->bio);
++      return bio_will_gap(req->q, NULL, bio, req->bio);
+ }
+ int kblockd_schedule_work(struct work_struct *work);
+-- 
+2.11.0
+
index 0e744f5bd9b88777e19b0b4cf6807da95bc37bb2..6da6708050b910096867465cd5d70c439092214f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -250,6 +250,7 @@ ${KERNEL_SRC}/README: ${KERNEL_SRC_SUBMODULE} | submodules
        cd ${KERNEL_SRC}; patch -p1 < ../CVE-2017-1000365-fs-exec.c-account-for-argv-envp-pointers.patch
        cd ${KERNEL_SRC}; patch -p1 < ../CVE-2017-10810-drm-virtio-don-t-leak-bo-on-drm_gem_object_init-fail.patch
        cd ${KERNEL_SRC}; patch -p1 < ../CVE-2017-7482-rxrpc-Fix-several-cases-where-a-padded-len-isn-t-che.patch
+       cd ${KERNEL_SRC}; patch -p1 < ../0001-block-fix-bio_will_gap-for-first-bvec-with-offset.patch
        sed -i ${KERNEL_SRC}/Makefile -e 's/^EXTRAVERSION.*$$/EXTRAVERSION=${EXTRAVERSION}/'
        touch $@