Skip to content

[26.04_linux-nvidia] NVIDIA: SAUCE: nvme-rdma: size NVFS SGL for GPU pages - #634

Closed
sourabgupta3 wants to merge 2 commits into
NVIDIA:26.04_linux-nvidiafrom
sourabgupta3:sg_26.04_linux-nvidia-nvfs-sgl-fix
Closed

sourabgupta3 wants to merge 2 commits into
NVIDIA:26.04_linux-nvidiafrom
sourabgupta3:sg_26.04_linux-nvidia-nvfs-sgl-fix

Conversation

@sourabgupta3

@sourabgupta3 sourabgupta3 commented Oct 7, 2026 •

Copy link
Copy Markdown

NVMe/RDMA sizes the request scatterlist from the block layer physical segment count. For GDS I/O, contiguous proxy pages do not guarantee that the corresponding 64K GPU pages are physically contiguous, so the NVFS mapper can require more entries than the block layer reports.

Classify requests using the first page and, for GPU I/O, allocate enough entries for each 64K GPU page plus a possible boundary crossing. Track whether NVFS allocated the table so CPU requests continue to use the existing allocation and mapping path without a second allocation.

LP: https://bugs.launchpad.net/ubuntu/+source/linux-nvidia-bos/+bug/2170268

@sourabgupta3 sourabgupta3 changed the title NVIDIA: SAUCE: nvme-rdma: size NVFS SGL for GPU pages [26.04_linux-nvidia] NVIDIA: SAUCE: nvme-rdma: size NVFS SGL for GPU pages Oct 7, 2026
@nirmoy nirmoy added the help wanted Extra attention is needed label Oct 7, 2026
@nirmoy

nirmoy commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

BaseOS Kernel Review

Warning

⚠️ Review needs attention

NVFS SGL sizing undercounts independently aligned merged bios, allowing GPU range mapping to overrun the allocated scatterlist and corrupt kernel memory during GDS I/O.

Findings: Critical 0 · High 1 · Medium 0 · Low 0

🔍 Review artifacts

📦 Build checks — 🟢 4/4 passed

Note

Build reports and debs are retained for 10 days after the PR closes.

  • ⚪ PR explanation: inactive
Review metadata
  • Reviewed head: c2b29e13246d
  • Overall status: attention needed
  • Build checks: 4/4 passed

This comment is maintained by BaseOS Reviewer and updated when the GitHub watcher publishes a newer review.

@github-actions

github-actions Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

PR Validation Report

Patchscan ✅ No Missing Fixes

All cherry-picked commits checked — no missing upstream fixes found.

PR Lint ✅ All checks passed

Details
Checking 2 commits...

Cherry-pick digest:
┌──────────────┬──────────────────────────────────────────────────────────────────┬────────────┬─────────┬───────────────────────────┐
│ Local        │ Referenced upstream / Patch subject                              │ Patch-ID   │ Subject │ SoB chain                 │
├──────────────┼──────────────────────────────────────────────────────────────────┼────────────┼─────────┼───────────────────────────┤
│ c2b29e13246d │ [SAUCE] nvme-rdma: size nvfs sgl per bio                         │ N/A        │ N/A     │ sougupta                  │
├──────────────┼──────────────────────────────────────────────────────────────────┼────────────┼─────────┼───────────────────────────┤
│ ca0c528404d0 │ [SAUCE] nvme-rdma: size nvfs sgl for gpu pages                   │ N/A        │ N/A     │ sougupta                  │
└──────────────┴──────────────────────────────────────────────────────────────────┴────────────┴─────────┴───────────────────────────┘

Lint: all checks passed.

@clsotog

clsotog commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator

These are my codex findings:
[P1] NV-Kernels/drivers/nvme/host/nvfs-rdma.h:83 SGL sizing can still underallocate for sparse GPU requests.
DIV_ROUND_UP(blk_rq_payload_bytes(rq), 64K) + 1 only bounds a dense contiguous GPU range. A request can contain multiple small bvecs that land in different 64K GPU pages while the proxy pages are physically contiguous enough for blk_rq_nr_phys_segments(rq) to be small. Example: several 4K GPU bvecs from different 64K GPU pages can need one NVFS SGE per bvec, but this code may allocate only 2-3 entries. Since nvfs_blk_rq_map_sg() gets no table size, that can overrun the chained sg table. Size by walking request segments and summing a per-segment GPU-page upper bound, or use an NVFS helper that returns the required SGL count before mapping.

[P1] NV-Kernels/drivers/nvme/host/nvfs-rdma.h:69 First-page classification can misroute mixed CPU/GPU requests to the CPU DMA path. When the first bvec is not a GPU page, the code returns before calling the NVFS mapper. The block layer can merge adjacent bios without knowing this memory-type distinction, so a CPU-first request containing later GPU pages would skip NVFS validation/mapping and go through blk_rq_map_sg() plus ib_dma_map_sg(). That risks DMA against GPU proxy pages as if they were normal CPU memory. If mixed requests are intended to be impossible, this needs an explicit merge barrier or invariant; otherwise scan all request segments for any GPU page before deciding to bypass NVFS.

@jamieNguyenNVIDIA

Copy link
Copy Markdown
Collaborator

In addition to the findings left by Carol (Codex) and the PR validation report:

1. NULL dereference on discard with nvidia-fs loaded (nvfs-rdma.h:40-47, :69-71)

nvme_rdma_nvfs_first_page_is_gpu() now runs rq_for_each_segment() before anything filters the request type. A discard reaches nvme_rdma_dma_map_req() because RQF_SPECIAL_PAYLOAD makes blk_rq_nr_phys_segments() return 1. Its bio has bi_io_vec == NULL and a nonzero bi_size, so bio_iter_iovec() dereferences NULL. Before this change, nvfs_blk_rq_map_sg() called nvfs_blk_rq_check() first, and that returns early for any op other than READ/WRITE. Triggered by fstrim or discard mounts on an NVMe-oF/RDMA namespace while nvidia-fs is registered. The classifier needs the same guard: req_op() is READ or WRITE, and RQF_SPECIAL_PAYLOAD is not set.

2. CPU I/O gets the GPU-sized table when FT_GPU_PAGE is not advertised (nvfs-rdma.h:69)

Without nvfs_ft_is_gpu_page, the classifier is skipped. Every CPU request then allocates ceil(payload / 64K) + 1 entries, which for 1 MiB is a chained GFP_ATOMIC mempool allocation instead of the inline 2. It also walks the mapper before falling back. That contradicts "CPU requests continue to use the existing allocation" in the commit message.

Minor: NVFS_GPU_PAGE_SIZE duplicates pci.c:48 and could move to nvfs.h. The if (!sg_allocated) { block opens inside one #ifdef CONFIG_NVFS and closes in another. A helper returning the entry count (e.g. nvme_rdma_nvfs_nr_sg(rq)) would keep the single upstream sg_alloc_table_chained() call and drop sg_allocated.

@sourabgupta3
sourabgupta3 force-pushed the sg_26.04_linux-nvidia-nvfs-sgl-fix branch from ccdf6f0 to b086492 Compare October 8, 2026 18:43
NVMe/RDMA sizes the request scatterlist from the block layer physical
segment count. For GDS I/O, contiguous proxy pages do not guarantee
that the corresponding 64K GPU pages are physically contiguous, so
the NVFS mapper can require more entries than the block layer reports.

Use the first request page only to select the allocation size. GPU
requests receive enough entries for each 64K GPU page plus a possible
boundary crossing, while CPU requests retain the normal physical
segment count. All eligible requests still pass through the NVFS
mapper so mixed CPU/GPU requests are rejected.

Keep integrity, special-payload, and non-read/write requests on the
normal block mapping path before inspecting request segments. This
ensures data-less discard bios use their NVMe DSM special payload.

Signed-off-by: Sourab Gupta <sougupta@nvidia.com>
@sourabgupta3
sourabgupta3 force-pushed the sg_26.04_linux-nvidia-nvfs-sgl-fix branch from b086492 to ca0c528 Compare October 8, 2026 19:12
@jamieNguyenNVIDIA

Copy link
Copy Markdown
Collaborator

Re-reviewed ca0c528. The discard and mixed CPU/GPU issues are fixed. Carol's first P1 is still open.

@clsotog

clsotog commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator

Like Jamie said there still some pending.
This is the feedback from Codex:

Sparse GPU SGL sizing: not addressed. PR head ca0c528 still sizes GPU-capable requests with DIV_ROUND_UP(blk_rq_payload_bytes(rq), 64K) + 1 in drivers/nvme/host/nvfs-rdma.h:95-97. That is still a dense-range bound, so the sparse case from the comment can still need more NVFS SGEs than allocated. The callback still gets only sglist, not a capacity, and the NVFS mapper can create a new SGE for each non-contiguous GPU physical page.

@sourabgupta3

Copy link
Copy Markdown
Author

Yes, that is valid feedback but the possibilty of such a scenario happening is very remote for GDS where a sparse file needs is read and the physical addresses on the GPU are also completely non-contiguous. In such scenarios, we if the SG list is underallocated, then we can run into this. Since we have never run into such a situation today as well with the buggy NVMeoF driver as well(current one that already underallocates), I think a conservative solution would be in nvidia-fs to just fail such IOs, rather than corrupting the memory(working on it currently).

@jamieNguyenNVIDIA

Copy link
Copy Markdown
Collaborator

It does seem unlikely, but the result is serious: a silent memory corruption. nvfs_extend_sg_markers() writes past the end marker rather than failing. A request that fits the 2 inline entries has no slack, so the overflow lands in the neighbouring request's PDU.

Fixing it in nvidia-fs alone would need an interface change, because the mapper isn't given the table size.

Claude suggests the following kernel-side change:

+/*
+ * nvidia-fs issues each I/O from a single iovec, so every bio covers one
+ * contiguous range of a GPU buffer and maps to at most one entry per 64K
+ * GPU page it touches, plus one when it starts inside a GPU page.  A request
+ * can merge bios from unrelated ranges, so bound each bio separately.
+ */
+static unsigned int nvme_rdma_nvfs_gpu_nr_sg(struct request *rq)
+{
+	unsigned int nr_sg = 0;
+	struct bio *bio;
+
+	__rq_for_each_bio(bio, rq)
+		nr_sg += DIV_ROUND_UP(bio->bi_iter.bi_size,
+				      NVFS_GPU_PAGE_SIZE) + 1;
+
+	return nr_sg;
+}
+
 static int nvme_rdma_nvfs_map_data(struct ib_device *ibdev,
 				   struct request *rq, bool *is_nvfs_io,
 				   bool *sg_allocated, int *count)
 {
 	struct nvme_rdma_request *req = blk_mq_rq_to_pdu(rq);
 	enum dma_data_direction dma_dir = rq_dma_dir(rq);
-	unsigned int nr_sg, gpu_nr_sg;
+	unsigned int nr_sg;
 	int ret = 0;
@@
 			/*
 			 * The block layer may merge physically contiguous proxy pages
 			 * into fewer segments.  GPU physical pages need not have the
-			 * same contiguity.  Allow one entry per 64K GPU page, plus one
-			 * for a request that starts at an offset within a GPU page.
+			 * same contiguity.
 			 */
-			gpu_nr_sg = DIV_ROUND_UP(blk_rq_payload_bytes(rq),
-						 NVFS_GPU_PAGE_SIZE);
-			nr_sg = max_t(unsigned int, nr_sg, gpu_nr_sg + 1);
+			nr_sg = max(nr_sg, nvme_rdma_nvfs_gpu_nr_sg(rq));
 		}

For a single-bio request this gives the same count as today, so the common path is unchanged. Build-tested on arm64 with W=1 only.

nvidia-fs submits each I/O from one iovec, but the block layer can
merge bios from separate GPU ranges into one request. A request-wide
payload bound loses the independent 64K alignment of each bio and can
underallocate the NVFS scatterlist.

Compute the GPU-page upper bound for every bio and sum the results.
Continue taking the maximum with blk_rq_nr_phys_segments(), preserving
the existing CPU and single-bio paths.

Signed-off-by: Sourab Gupta <sougupta@nvidia.com>
@jamieNguyenNVIDIA

Copy link
Copy Markdown
Collaborator

Acked-by: Jamie Nguyen <jamien@nvidia.com>

@clsotog

clsotog commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator

Acked-by: Carol L Soto <csoto@nvidia.com>
Now that this PR has the 2 acks can we create for 26.04_linux-nvidia-bos

@nirmoy nirmoy added has_2_acks and removed help wanted Extra attention is needed has_1_ack labels Oct 9, 2026
@sourabgupta3

Copy link
Copy Markdown
Author

Carol, here is the PR for bos branch: #642

@jamieNguyenNVIDIA

Copy link
Copy Markdown
Collaborator

Applied to canonical-resolute main-next:

  • 6090037f8249 NVIDIA: SAUCE: nvme-rdma: size NVFS SGL for GPU pages
  • e18b29451692 NVIDIA: SAUCE: nvme-rdma: size NVFS SGL per bio

Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants