Re: [PATCH v7 1/1] vfio/nvgrace-gpu: Add Blackwell-Next GPU readiness check via CXL DVSEC
From: Alex Williamson
Date: Thu May 28 2026 - 13:56:34 EST
On Thu, 28 May 2026 09:38:40 +0000
Ankit Agrawal <ankita@xxxxxxxxxx> wrote:
...
> drivers/vfio/pci/nvgrace-gpu/main.c | 144 ++++++++++++++++++++++++++--
> include/uapi/linux/pci_regs.h | 1 +
Bjorn, I assume you don't object to this trivial addition:
> diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
> index 14f634ab9350..718fb630f5bb 100644
> --- a/include/uapi/linux/pci_regs.h
> +++ b/include/uapi/linux/pci_regs.h
> @@ -1357,6 +1357,7 @@
> #define PCI_DVSEC_CXL_RANGE_SIZE_LOW(i) (0x1C + (i * 0x10))
> #define PCI_DVSEC_CXL_MEM_INFO_VALID _BITUL(0)
> #define PCI_DVSEC_CXL_MEM_ACTIVE _BITUL(1)
> +#define PCI_DVSEC_CXL_MEM_ACTIVE_TIMEOUT __GENMASK(15, 13)
> #define PCI_DVSEC_CXL_MEM_SIZE_LOW __GENMASK(31, 28)
> #define PCI_DVSEC_CXL_RANGE_BASE_HIGH(i) (0x20 + (i * 0x10))
> #define PCI_DVSEC_CXL_RANGE_BASE_LOW(i) (0x24 + (i * 0x10))
> 2 files changed, 136 insertions(+), 9 deletions(-)
Replying to the sashiko comments in thread to keep all the reviewers in
the loop...
On Thu, 28 May 2026 10:22:14 +0000
sashiko-bot@xxxxxxxxxx wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [High] TOCTOU race in lockless device readiness checks causes unexpected -EAGAIN or VM_FAULT_SIGBUS errors instead of waiting for the device.
> - [High] The 256-second device readiness polling uses uninterruptible `msleep()` loops, which can trigger hung task panics and renders user tasks unkillable.
> --
>
> commit a85819b2171b67b275d15e9b87eb7447b4dd63a4
> Author: Ankit Agrawal <ankita@xxxxxxxxxx>
>
> vfio/nvgrace-gpu: Add Blackwell-Next GPU readiness check via CXL DVSEC
>
> Adds a CXL DVSEC-based readiness check for Blackwell-Next GPUs in addition
> to the existing legacy BAR0 polling. The device readiness is determined by
> polling the Memory_Active bit outside the memory lock for up to 256 seconds.
>
> > diff --git a/drivers/vfio/pci/nvgrace-gpu/main.c b/drivers/vfio/pci/nvgrace-gpu/main.c
> > index fa056b69f899a..04fcc0d088f54 100644
> > --- a/drivers/vfio/pci/nvgrace-gpu/main.c
> > +++ b/drivers/vfio/pci/nvgrace-gpu/main.c
>
> [ ... ]
>
> > +static int nvgrace_gpu_wait_device_ready_cxl(struct nvgrace_gpu_pci_core_device *nvdev)
> > +{
> > + unsigned long deadline = jiffies + msecs_to_jiffies(POLL_QUANTUM_MS);
> > + bool active_phase = false;
> > + u32 status;
> > + int ret;
> > +
> > + for (;;) {
>
> [ ... ]
>
> > + if (time_after(jiffies, deadline))
> > + return -ETIME;
> > +
> > + msleep(POLL_QUANTUM_MS);
> > + }
> > +}
>
> [Severity: High]
> Will this uninterruptible sleep trigger hung task panics?
>
> Since the CXL device readiness can take up to 256 seconds and msleep() places
> the task in the TASK_UNINTERRUPTIBLE state, processes accessing the device
> during a reset will become unresponsive and immune to signals (including
> SIGKILL) for up to 4 minutes.
>
> With the default Linux hung_task_timeout_secs at 120 seconds, blocking here
> is highly likely to trigger the hung task detector and cause a kernel panic
> on systems with hung_task_panic enabled. Would it be better to use an
> interruptible sleep and abort on pending fatal signals?
The legacy path already has this same issue, but the timeout is 30s
rather than 256s. Both locations could pretty trivially change to:
msleep_interruptible(POLL_QUANTUM_MS);
if (fatal_signal_pending(current))
return -EINTR;
It's maybe worth a follow-up to address both for a little more
robustness.
> > @@ -313,6 +399,21 @@ static vm_fault_t nvgrace_gpu_vfio_pci_huge_fault(struct vm_fault *vmf,
> > pfn = PHYS_PFN(memregion->memphys) + addr_to_pgoff(vma, addr);
> >
> > if (is_aligned_for_order(vma, addr, pfn, order)) {
> > + /*
> > + * Exit early under memory_lock to avoid a potentially lengthy
> > + * device readiness wait on a runtime-suspended device. Any
> > + * race after the lock is dropped is benign as the re-check
> > + * inside the scoped guard below catches it.
> > + */
> > + scoped_guard(rwsem_read, &vdev->memory_lock) {
> > + if (vdev->pm_runtime_engaged)
> > + return VM_FAULT_SIGBUS;
> > + }
> > +
> > + if (nvdev->cxl_dvsec && READ_ONCE(nvdev->reset_done) &&
> > + nvgrace_gpu_wait_device_ready_cxl(nvdev))
> > + return VM_FAULT_SIGBUS;
>
> [Severity: High]
> Can this lockless check race with a concurrent device reset and bypass the
> intended polling mechanism?
>
> If a concurrent device reset finishes and sets reset_done = true right after
> this lockless check evaluates to false, the thread proceeds without polling
> and blocks waiting for memory_lock.
>
> Once the lock is acquired, the thread calls nvgrace_gpu_check_device_ready()
> which observes reset_done == true and invokes the fallback
> nvgrace_gpu_test_device_ready_cxl() under the lock. Because this CXL test is
> non-blocking, it immediately returns -EAGAIN, causing
> nvgrace_gpu_vfio_pci_huge_fault() to return VM_FAULT_SIGBUS and crash user
> applications instead of waiting.
This doesn't really seem to break our contract with userspace, they're
issuing a reset while the device is taking a fault, reset necessarily
disables memory, therefore a sigbus is a valid outcome. We could make
this a bit more robust to such a race with a retry, but it would be
contingent on the interruptible msleep above or else the user could
potentially trigger endless resets during fault. Something like this:
diff --git a/drivers/vfio/pci/nvgrace-gpu/main.c b/drivers/vfio/pci/nvgrace-gpu/main.c
index 01b819156c03..9e7f8a7e1abc 100644
--- a/drivers/vfio/pci/nvgrace-gpu/main.c
+++ b/drivers/vfio/pci/nvgrace-gpu/main.c
@@ -415,14 +415,21 @@ static vm_fault_t nvgrace_gpu_vfio_pci_huge_fault(struct vm_fault *vmf,
if (vdev->pm_runtime_engaged)
return VM_FAULT_SIGBUS;
}
-
+retry:
if (nvdev->cxl_dvsec && READ_ONCE(nvdev->reset_done) &&
nvgrace_gpu_wait_device_ready_cxl(nvdev))
return VM_FAULT_SIGBUS;
scoped_guard(rwsem_read, &vdev->memory_lock) {
- if (vdev->pm_runtime_engaged ||
- nvgrace_gpu_check_device_ready(nvdev))
+ int rc;
+
+ if (vdev->pm_runtime_engaged)
+ return VM_FAULT_SIGBUS;
+
+ rc = nvgrace_gpu_check_device_ready(nvdev);
+ if (rc == -EAGAIN)
+ goto retry;
+ if (rc)
return VM_FAULT_SIGBUS;
ret = vfio_pci_vmf_insert_pfn(vdev, vmf, pfn, order);
Note that the read/write paths also have this gap where we can wait for
the device to be ready, but the check under memory_lock returns
-EAGAIN. The difference is that userspace will already automatically
handle the -EAGAIN vs the SIGBUS could be fatal.
I think both of the above would be good improvements, though I don't
think either is strictly necessary. I don't spot any other must-fix
issues, any concerns from others? Thanks,
Alex