|
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 |
|