From: Daniel Gomez <[email protected]>

Commit 53493c1f83 ("hw/nvme: cap MDTS value for internal limitation")
capped MDTS so the worst-case PRP count would fit in IOV_MAX, leaving
transfers limited to 2 MiB.

Now that dma_blk_cb() can batch IOs up to IOV_MAX instead of limiting
to IOV_MAX, remove it, except for CMB/PMR-only where the limit still
applies.

In addition, fix UB when mdts >= 31 by calculating the worst-case iovec
count with a width-bounded shift helper. Fixes error with ubsan:
    ../hw/nvme/ctrl.c:8638:33: runtime error: shift exponent 32 is too
    large for 32-bit type 'int'

Suggested-by: Klaus Jensen <[email protected]>
Reviewed-by: Keith Busch <[email protected]>
Signed-off-by: Daniel Gomez <[email protected]>
---
 hw/nvme/ctrl.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index 7861d8f2521..f219bf524dd 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -8720,6 +8720,11 @@ static const MemoryRegionOps nvme_cmb_ops = {
     },
 };
 
+static inline uint64_t nvme_mdts_max_iovs(uint8_t mdts)
+{
+    return mdts >= 64 ? UINT64_MAX : (1ULL << mdts) + 1;
+}
+
 static bool nvme_check_params(NvmeCtrl *n, Error **errp)
 {
     NvmeParams *params = &n->params;
@@ -8802,8 +8807,9 @@ static bool nvme_check_params(NvmeCtrl *n, Error **errp)
         host_memory_backend_set_mapped(n->pmr.dev, true);
     }
 
-    if (!n->params.mdts || ((1 << n->params.mdts) + 1) > IOV_MAX) {
-        error_setg(errp, "mdts exceeds IOV_MAX");
+    if ((params->cmb_size_mb || n->pmr.dev) &&
+        (!params->mdts || nvme_mdts_max_iovs(params->mdts) > IOV_MAX)) {
+        error_setg(errp, "mdts=%u is incompatible with CMB/PMR", params->mdts);
         return false;
     }
 

-- 
2.55.0


Reply via email to