Hannes Reinecke 696f5f
From: Eduard Hasenleithner <eduard@hasenleithner.at>
Hannes Reinecke 696f5f
Date: Tue, 12 Nov 2019 21:55:01 +0100
Hannes Reinecke 696f5f
Subject: [PATCH] nvme: Discard workaround for non-conformant devices
Hannes Reinecke 696f5f
Git-commit: 530436c45ef2e446c12538a400e465929a0b3ade
Hannes Reinecke 696f5f
Patch-mainline: v5.5-rc1
Hannes Reinecke 696f5f
References: bsc#1169045
Hannes Reinecke 696f5f
Hannes Reinecke 696f5f
Users observe IOMMU related errors when performing discard on nvme from
Hannes Reinecke 696f5f
non-compliant nvme devices reading beyond the end of the DMA mapped
Hannes Reinecke 696f5f
ranges to discard.
Hannes Reinecke 696f5f
Hannes Reinecke 696f5f
Two different variants of this behavior have been observed: SM22XX
Hannes Reinecke 696f5f
controllers round up the read size to a multiple of 512 bytes, and Phison
Hannes Reinecke 696f5f
E12 unconditionally reads the maximum discard size allowed by the spec
Hannes Reinecke 696f5f
(256 segments or 4kB).
Hannes Reinecke 696f5f
Hannes Reinecke 696f5f
Make nvme_setup_discard unconditionally allocate the maximum DSM buffer
Hannes Reinecke 696f5f
so the driver DMA maps a memory range that will always succeed.
Hannes Reinecke 696f5f
Hannes Reinecke 696f5f
Link: https://bugzilla.kernel.org/show_bug.cgi?id=202665 many
Hannes Reinecke 696f5f
Signed-off-by: Eduard Hasenleithner <eduard@hasenleithner.at>
Hannes Reinecke 696f5f
[changelog, use existing define, kernel coding style]
Hannes Reinecke 696f5f
Signed-off-by: Keith Busch <kbusch@kernel.org>
Hannes Reinecke 696f5f
Acked-by: Hannes Reinecke <hare@suse.com>
Hannes Reinecke 696f5f
---
Hannes Reinecke 696f5f
 drivers/nvme/host/core.c | 12 +++++++++---
Hannes Reinecke 696f5f
 1 file changed, 9 insertions(+), 3 deletions(-)
Hannes Reinecke 696f5f
Hannes Reinecke 696f5f
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
Hannes Reinecke 696f5f
index 4be64703aa47..9696404a6182 100644
Hannes Reinecke 696f5f
--- a/drivers/nvme/host/core.c
Hannes Reinecke 696f5f
+++ b/drivers/nvme/host/core.c
Hannes Reinecke 696f5f
@@ -574,8 +574,14 @@ static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req,
Hannes Reinecke 696f5f
 	struct nvme_dsm_range *range;
Hannes Reinecke 696f5f
 	struct bio *bio;
Hannes Reinecke 696f5f
 
Hannes Reinecke 696f5f
-	range = kmalloc_array(segments, sizeof(*range),
Hannes Reinecke 696f5f
-				GFP_ATOMIC | __GFP_NOWARN);
Hannes Reinecke 696f5f
+	/*
Hannes Reinecke 696f5f
+	 * Some devices do not consider the DSM 'Number of Ranges' field when
Hannes Reinecke 696f5f
+	 * determining how much data to DMA. Always allocate memory for maximum
Hannes Reinecke 696f5f
+	 * number of segments to prevent device reading beyond end of buffer.
Hannes Reinecke 696f5f
+	 */
Hannes Reinecke 696f5f
+	static const size_t alloc_size = sizeof(*range) * NVME_DSM_MAX_RANGES;
Hannes Reinecke 696f5f
+
Hannes Reinecke 696f5f
+	range = kzalloc(alloc_size, GFP_ATOMIC | __GFP_NOWARN);
Hannes Reinecke 696f5f
 	if (!range) {
Hannes Reinecke 696f5f
 		/*
Hannes Reinecke 696f5f
 		 * If we fail allocation our range, fallback to the controller
Hannes Reinecke 696f5f
@@ -615,7 +621,7 @@ static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req,
Hannes Reinecke 696f5f
 
Hannes Reinecke 696f5f
 	req->special_vec.bv_page = virt_to_page(range);
Hannes Reinecke 696f5f
 	req->special_vec.bv_offset = offset_in_page(range);
Hannes Reinecke 696f5f
-	req->special_vec.bv_len = sizeof(*range) * segments;
Hannes Reinecke 696f5f
+	req->special_vec.bv_len = alloc_size;
Hannes Reinecke 696f5f
 	req->rq_flags |= RQF_SPECIAL_PAYLOAD;
Hannes Reinecke 696f5f
 
Hannes Reinecke 696f5f
 	return BLK_STS_OK;
Hannes Reinecke 696f5f
-- 
Hannes Reinecke 696f5f
2.16.4
Hannes Reinecke 696f5f