Skip to content

linux: put the service user in the render group, so the engine can open an AMD or Intel GPU (#1535) - #1537

Merged
gen16k merged 1 commit into
mainfrom
fix/1535-linux-service-user-render-group
Sep 22, 2026
Merged

gen16k merged 1 commit into
mainfrom
fix/1535-linux-service-user-render-group

Conversation

@gen16k

@gen16k gen16k commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Why

The inference engine is started by the daemon as its child (internal/runtime/spawner_unix.go, with no credential change), so on Linux it runs as waired.

On Debian and Ubuntu, /dev/dri/renderD* and /dev/kfd are 0660 root:render. Both distributions build systemd with -Dgroup-render-mode=0660; upstream's default is 0666. The engine needs these nodes for AMD GPUs (ROCm or Vulkan) and Intel GPUs (Vulkan). Without the render group it cannot see such a GPU, and it runs on the CPU without saying why.

#1466 (for #459) had decided not to grant the group, so as not to add a standing privilege for a fact that never changes. That decision considered only the profiler's reading; the engine needs the node for every computation.

What changes

  • Install paths
    • packaging/debian/waired/postinst runs usermod -a -G render waired on every configure, when the group exists. An upgrade therefore fixes an existing install; the existing restart picks the group up.
    • waired-agent install does the same through ensureGPUGroups (internal/platform/service/service_linux.go). Which groups to join, and how, are both passed in, so the table test drives the real function.
    • usermod is declared in scripts/ci/lookpathguard/exemptions.go.
  • render only, never video (owner decision, 2026-09-22). video also opens cameras (/dev/video*) and the display (/dev/dri/card*), and computing does not need it on the supported distributions.
  • No SupplementaryGroups= in the unit.
    • Naming a group the host lacks stops the unit from starting (exit 216/GROUP).
    • systemd applies a User='s groups from the group database (systemd.exec(5)).
    • Comments in both unit sources say so, and a test keeps both units free of the directive.
  • The sudo waired init reading (gpu-topology.json) stays as the floor for a host whose service user is not in the group. With the group, the daemon reads the FUSION bit and an Intel card's memory itself, and a live reading already wins. The product string unreadIntelMemoryReason is unchanged: it now shows only when the live read fails.
  • Records
    • New decision docs/decisions/20260922/1430-linux-service-user-joins-render.md. It partly supersedes 20260920/2000 (only the "do not grant render" sentence), with links both ways.
    • Corrections in place in knowledge notes 2100, 1600 and 1700.
    • Comments corrected in internal/hardware, internal/runtime/state/gpu_topology.go, and both gpu_topology.go files under cmd/.
  • Docs (en/ja)
    • troubleshooting/slow-or-wrong.md: the Linux paragraph now names the group, with id waired to check it and usermod to fix it. It replaces "memory can only be read with administrator rights".
    • getting-started/install/linux.mdx: a "Service user" row.
  • installtest
    • assert_tier1 checks render membership where the guest has the group, and that video is absent.
    • assert_postinst_selfheal removes the group before dpkg-reconfigure and checks that it comes back.

Verification

Other operating systems (cross-OS parity)

Found alongside, not fixed here

Both are recorded in #1535 and #1534.

Fixes #1535

🤖 Generated with Claude Code

https://claude.ai/code/session_01BviBGHJqCeM88hxCRYrtAg

…en an AMD or Intel GPU (#1535)

The inference engine is the daemon's child and runs as `waired`. On
Debian and Ubuntu, /dev/dri/renderD* and /dev/kfd are 0660 root:render,
because both distributions build systemd with group-render-mode=0660.
So without the group the engine cannot see an AMD GPU (ROCm or Vulkan)
or an Intel GPU (Vulkan), and it runs on the CPU without saying why.
#1466 had chosen not to grant the group, but that choice considered
only the profiler's reading.

- The .deb postinst runs `usermod -a -G render waired` on every
  configure, when the group exists, so an upgrade fixes an existing
  install. `waired-agent install` does the same through
  ensureGPUGroups.
- `video` is left out (owner decision): it also opens cameras and the
  display, and computing does not need it.
- The unit keeps no SupplementaryGroups=, because naming an absent group
  stops the unit (216/GROUP). systemd applies a User='s groups from the
  group database.
- The gpu-topology.json reading from `sudo waired init` stays, as the
  floor for a host whose service user is not in the group.
- The new decision record partly supersedes the 2000 decision. The
  notes and comments that said the service has no groups are corrected.
- The troubleshooting and Linux install pages (en/ja) now name the
  group, with how to check it.

Checked on a Linux host with an NVIDIA card and an AMD iGPU:
- Without the group, the product's ollama does not list the iGPU at all.
- With the group, it finds the iGPU through Vulkan. With default
  settings it then drops the iGPU and serves on CUDA, as it does today.
- The postinst (run twice, as an upgrade) adds the group, and the
  restarted daemon runs with it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BviBGHJqCeM88hxCRYrtAg
Signed-off-by: gen16k <gen16k@users.noreply.github.com>
@github-actions

github-actions Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

📘 Docs preview — the preview channel for this PR has been deleted now that it is closed.

@gen16k
gen16k merged commit 742429d into main Sep 22, 2026
35 of 36 checks passed
@gen16k
gen16k deleted the fix/1535-linux-service-user-render-group branch September 22, 2026 05:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Linux: the service user is not in the render group, so the engine cannot reach an AMD or Intel GPU

1 participant