fix: Create NVIDIA control device nodes in nvidia-cdi-refresh.service - #1979
Conversation
There was a problem hiding this comment.
Pull request overview
This PR ensures NVIDIA control device nodes (notably /dev/nvidia-modeset and UVM nodes) are proactively created when missing, so CDI spec generation and legacy graphics injection reliably include the nodes needed for Wayland/KMS/X11 workflows on hosts that don’t auto-create them.
Changes:
- Add an
internal/system/devicenodespackage to best-effort load kernel modules andmknodmissing control device nodes (with per-node error collection and unit tests). - Extend
pkg/nvcdiwith aDeviceNodeCreatorinterface + option, and invoke node creation during NVML-mode common discovery (guarded by a newdisable-device-node-creationfeature flag). - Wire node creation into toolkit entrypoints:
nvidia-ctk cdi generate, jit-CDI modifier, and legacy graphics modifier (adds/dev/nvidia-modesetinjection).
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| pkg/nvcdi/options.go | Adds WithDeviceNodeCreator option and stores creator in library options. |
| pkg/nvcdi/lib.go | Plumbs deviceNodeCreator into the constructed NVCDI library instance. |
| pkg/nvcdi/common-nvml.go | Calls creator during NVML common discovery, gated by feature flag. |
| pkg/nvcdi/api.go | Introduces DeviceNodeCreator interface and disable-device-node-creation feature flag constant. |
| internal/system/devicenodes/devicenodes.go | New implementation for best-effort module load + device-node creation with error aggregation. |
| internal/system/devicenodes/devicenodes_test.go | Unit tests for existence short-circuiting, module mapping, and error collection. |
| internal/modifier/graphics.go | Legacy graphics modifier now attempts to create/discover /dev/nvidia-modeset for Wayland/KMS clients. |
| internal/modifier/cdi.go | Injects a device node creator into NVCDI for automatic (jit) CDI spec modification. |
| cmd/nvidia-ctk/cdi/generate/generate.go | Wires a device node creator into nvidia-ctk cdi generate during run(). |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
f80f7b4 to
734eb98
Compare
|
@cdesiniotis For after v1.20.0. |
|
@ehfd Thanks for putting this PR together. I definitely see why this change is needed. As an alternative, do you think it would be simpler to just add the following directly in |
|
@henry118 It could address it partially, but has some rough spots. Most representatively, the first container injection won't work with |
|
@henry118 The footprint is now reduced greatly. The logic is baked into |
5411ba7 to
b6c028c
Compare
|
Now, this PR also depends on NVIDIA/libnvidia-container#388 merged to be fully fixed in both CDI and legacy pathways. |
c3982f3 to
23ede88
Compare
Could you please explain this a bit more? Is it because of startup races between docker and nvidia-cdi-refresh? |
|
@henry118 I will answer in-depth tomorrow. |
|
At boot, it is exactly a docker to nvidia-cdi-refresh race, but the race is structural, not an ordering oversight. Node absence is not a boot-only condition so that no systemd unit ordering can close it. The below is an AI analysis. The mechanism
Timeline under henry118's original proposal: Not only docker↔refresh-service — that's the boot-time instance of it. The general condition is: any spec generation or container start that happens before some agent has created the control nodes since the driver was last (re)loaded gets a silently degraded spec. Concretely, with the unit-only approach:
One caveat worth adding in review: the boot race for static-spec consumers (docker --device nvidia.com/gpu=…, mode = "cdi") additionally depends on henry118's ExecStart being ordered before the cdi generate line — silent breakage if appended after. In-process creation can't be misordered. |
a6434e4 to
6209540
Compare
|
@henry118 Redesigned the PR based on your suggestions. However, the dependency on NVIDIA/libnvidia-container#388 is now stronger. |
af5f8f5 to
c3f82ff
Compare
henry118
left a comment
There was a problem hiding this comment.
@ehfd This approach LGTM overall.
@cdesiniotis @tariq1890 PTAL.
|
/ok to test c3f82ff |
|
Applied, thank you. @henry118 I used On the fallback: However, if you think this should still be removed after my explanation and the case I am stating is niche, I can remove it. |
|
Additional considerations across all three PRs: NVIDIA/libnvidia-container#388 (comment) |
| ConditionPathExists=/usr/bin/nvidia-ctk | ||
| # Order container engines after this service so that the first container | ||
| # started at boot does not race the device node creation and CDI refresh. | ||
| Before=docker.service containerd.service crio.service |
There was a problem hiding this comment.
Just call out that we've historically had issues with adding dependencies, see #1735 .
So for this case, since it introduced a Before= rather than After=, in order to form a cycle among, say docker, us, other, either
- docker has a
Before=us; or - other has
After=dockerandBefore=us;
The question is how likely are these two cases in practice. They seem unlikely to me.
There was a problem hiding this comment.
I think these two scenarios are unlikely, so I would be open to adding this ordering dependency. However, can we propose this change in a separate PR? I would prefer if this PR was scoped to just addressing the race condition where CDI spec generation occurs before all NVIDIA device nodes exist and / or all NVIDIA driver kernel modules are loaded.
Signed-off-by: Seungmin Kim <8457324+ehfd@users.noreply.github.com>
|
/ok to test 8269969 |
|
/cherry-pick release-1.20 |
|
🤖 Backport PR created for |
Reviewers: @elezar @myeolenv
Associated with NVIDIA/libnvidia-container#388.
Closes #1982
Summary
Re-enables Wayland and associated Vulkan and OpenGL capabilities on the container toolkit without workarounds.
CDI spec generation only discovered NVIDIA control device nodes that already existed on the host; on systems where no host component triggers their creation,
/dev/nvidia-modeset(and, after a reboot, the UVM nodes) were silently omitted from the generated specifications. This change creates missing control device nodes ahead of discovery — the programmatic equivalent of runningnvidia-ctk system create-device-nodes --control-devices --load-kernel-modulesat the points where specifications are produced. The legacy-mode counterpart (mounting the node for thegraphicscapability) is NVIDIA/libnvidia-container#388, keeping each half in the component that owns the behavior.Why This Exists
The NVIDIA driver does not register its device nodes with devtmpfs; nodes such as
/dev/nvidia-modesetare created on demand by userspace driver components. On headless Docker hosts (typical Debian, Ubuntu, and Arch installations) nothing ever triggers modeset creation, so:nvidia-ctk cdi generate, thenvidia-cdi-refreshservice, and jit-cdi mode (the default resolution ofmode = "auto") generated specs without the node, and containers requesting any capability set never received it. Wayland/KMS clients in containers fail as a result.nvidia-container-clicreates the node under--load-kmodsbut mounts it only for thedisplaycapability; fix: Discover/dev/nvidia-modesetinstead of assuming it exists libnvidia-container#388 extends that mount tographics.This closes the device half of the container Wayland/X11 enablement tracked in #1477 and #563.