G6: one DRM device numbering across drivers (misc/drm_minor) and Linux's ioctl size rule #8

Merged
toasterson merged 7 commits from g6-minors into main 2026-10-05 16:46:39 +00:00
Owner

Anima work item: G6 01a0f442-2d58-7593-9ed4-ccb0a7ba22a9

Stacked on #7 (r4-virtio-gpu, itself on #6 and #5). Two things: one DRM device numbering for every driver built on the core, and Linux's drm_ioctl() argument size rule for the core and mode-setting ioctls.

What was built

misc/drm_minor (modules/drm-minor, bindings in crates/drm-minor-sys)

  • A small misc kernel module that owns the table of DRM device numbers for the whole system.
  • It exports two C functions, drm_minor_alloc(owner) and drm_minor_free(id, owner).
  • The table is 64 atomic owner words. Allocation is lock-free and never blocks or allocates.
  • A free that does not match the owner changes nothing and is logged. An id_space(9F) id_free of an unallocated id would panic instead.
  • _fini refuses while a number is taken.
  • The module is linked with an exports mapfile and ld -B reduce, so only _init, _fini, _info and the two functions are global. CI and the test scripts check this.
  • Threaded host tests cover the table.
  • Packaged by packaging/drm-minor.p5m (lints clean; published to a scratch repo on oibldofgate). virtio-gpu.p5m now depends on it.
  • CI builds and links it.

Numbering

  • A device takes the lowest free number N when it attaches and gives it back when it detaches. Its nodes are card<N> and renderD<128+N>, with node minors N and 128+N.
  • Each driver module records which of its instances holds which number (drm::minor::bind). instance_of_minor reads that record, so the instance number is no longer limited to 63.
  • drm-minor-sys declares depends = ["misc/drm_minor"], so cargo xtask link adds -N misc/drm_minor and kernel-check covers both symbols.

Argument sizes

  • Core and mode-setting commands now match on group, number and direction. The caller's size U comes from the command.
  • drm::ioctl::SizePlan is the Linux computation. drm::uaccess::CoreArg applies it. CoreArg deliberately does not dereference to IoctlArg, so a core handler cannot fall back to an exact-size copy by accident.
  • Unknown numbers stay ENOTTY, and ILP32 callers still get ENOTSUP.
  • Driver-private commands keep the exact match, and drivers list each size they accept.

Numbering: the decision and the alternatives

(a) A separate misc module with a C ABI: chosen.

  • The kernel loads it before any driver that names it with -N, and keeps it loaded while such a driver is loaded. So the table outlives every number in it, for any load and unload order.
  • It is also where Linux keeps the numbers (drm.ko), and it is the first piece of the R5 C interface.

(b) A registry that the first driver creates behind a well-known symbol: rejected.

  • krtld resolves a module's symbols only from unix, genunix, the module itself and its -N dependencies (illumos-ddi DESIGN §4). The other drivers would need ddi_modopen at run time.
  • The registry would die with the module that created it while other modules still hold numbers from it.

(c) Stateless schemes: rejected.

  • Fixed ranges per driver waste the 64 numbers and collide with the next driver.
  • Scanning the device tree for existing card<N> names races with concurrent attaches.

Deviations from Linux 7.3's drm_minor_alloc

  • Linux allocates primary and render numbers independently, and has an extended range from 192. Here one number serves both nodes, capped at 64, because the clone layout gives a node minor 9 bits.
  • gfx-drm's C drm/i915 still number their nodes by instance (open issue below).

The Linux size rule matched (drm_ioctl(), read at v7.3-rc5)

Linux uses these sizes:

  • in = U if both commands have IOC_IN, otherwise 0.
  • out = U if both have IOC_OUT, otherwise 0.
  • The buffer is max(in, out, K) bytes, where K is the kernel's size.

It copies in bytes in, zeroes the rest, hands the handler K bytes, and copies out bytes back. So:

  • Shorter caller structure: zero-extended, and only U bytes come back.
  • Longer caller structure: not refused, whatever the extra bytes hold. They are copied in (an unreadable byte gives EFAULT) and copied back unchanged by _IOWR commands, come back as zeros from _IOR commands, and are ignored by _IOW commands.

The core now does exactly this. A host test checks it against a restatement of Linux's code for every table entry, all four directions and every size from 0 to 255.

Remaining differences, documented in the README:

  • A command with another direction is ENOTTY. Linux uses the intersection of both directions.
  • An unused number is ENOTTY. Linux returns EINVAL.
  • Handlers copy out explicitly. Linux copies its buffer back even after a failed call.

The four grown commands are served at both sizes with equal results: SYNCOBJ_HANDLE_TO_FD and FD_TO_HANDLE (16 → 24 bytes), WAIT (32 → 40) and TIMELINE_WAIT (40 → 48). The added point and deadline_nsec fields are carried through unread. Their flags are unknown flags (EINVAL), as on a Linux kernel from before them.

Test evidence

Host (macOS, Rust 1.97.1 and nightly-2026-04-16)

  • cargo test -p drm -p drm-uapi -p drm_minor: 115 + 1 + 4 passed.
  • cargo test -p virtio_gpu --no-default-features: 5 passed.
  • clippy -D warnings is clean, including with the panic-drill feature.
  • fmt, cargo doc -D warnings, uapi-check: 0 differences.
  • cargo xtask build drm_minor rdrmnull virtio_gpu succeeds, and all three link with ld on illumos cda5b9a49f (oibldofgate).

Guest (hephaistos, fresh overlay of golden-20260930: illumos 7e802e88a3, osnet 23295, QEMU 6.2 virtio-gpu-gl-pci, 2 vCPUs, 3 GiB, port 2410)

  • gfx-drm's libdrm 2.4.134 p5p (#8, 1e68727) is installed in the overlay only.
  • tools/test/run-g6-test.sh passed: 354 PASS, 0 FAIL. Log: logs/hephaistos/illumos-drm/20261001-g6-run1.log. Per-test outputs: artifacts/g6-minors/run1-outputs/. Kernel archives built from 0155ded, scripts at bc5b0d4.
  • Order A (virtio_gpu first, then two rdrmnull devices): card0/renderD128 (virtio), card1/renderD129 and card2/renderD130 (rdrmnull@0 and @1). The minors match.
  • Order B (rdrmnull first): rdrmnull gets 0 and 1, virtio gets 2.
  • Listing: drmdevice reports 3 devices, and getsundev passes 73 checks, 0 failed. It reports 2 and 1 devices after unloads.
  • Suites with all three attached:
    • R0: 106 and 107 checks.
    • R1: 153 checks per device.
    • R2: 216 checks per device, including cross-device between the two rdrmnull devices.
    • R3: 184 checks per device.
    • The 32-bit probes pass on both rdrmnull devices.
    • drm_r4_test passes on virtio as card0 and as card2 (63 checks each).
    • drm_g6_test passes on every device (27 checks each).
    • modetest lists every display.
  • Unload orders:
    • rdrmnull first, then virtio; virtio first, then rdrmnull. A device keeps its number while the other driver unloads.
    • A reload gets the same numbers back, and a driver loaded into a gap gets the lowest free number.
    • misc/drm_minor refuses to unload while any driver is loaded, and unloads after both. Loading rdrmnull loads it.
    • No panic; the console log shows one boot.
  • truss: libdrm 2.4.134 sends each grown command once at its new size, the kernel answers 0, and there are 0 calls at the old size. The retry never runs.
  • Milestone scripts beside an attached virtio_gpu: run-r4-test.sh (KEEP=1, 72 checks), run-r1-test.sh with two rdrmnull devices (513) and run-r3-test.sh (477) all pass. /etc, /devices and their /dev/dri links are unchanged.
  • Attempt 1: 20261001-g6-run1-attempt1.log has the same kernel results. Its failures were script bugs, fixed in bc5b0d4.

Also fixed: the run-r1-test.sh/run-r3-test.sh race. They grepped /var/adm/messages for "detach refused" before syslogd had written it. They now poll with a bounded wait (wait_log, up to 15 s).

Review

The Anima review bar, applied locally (anima-review), approved round 1 with non-blocking items. All were addressed in b7c94e7:

  • The GEM registry entry is now recorded as the last fallible step of attach. Before, a failed attach left a stale entry, and global lowest-free numbers made that block the next attach.
  • The size tests check each handler's structure against its command.
  • The anonymous-file id space is named consistently.
  • README note on re-attach.
  • Test script nits.

Round 2 on b7c94e7: approve. It asked that the scope of the guest evidence be stated plainly (done in cc3f1ac and below).

Open issues / not done

  • Guest verification of b7c94e7 is deferred: the attach ordering change and the anon id-space name. The test host was taken down right after the run. These changes are covered only by host tests, the cross-build and illumos linking.
  • cargo xtask kernel-check was not run against a kernel with drm_minor loaded. The guest run's ::whatis shows both functions resolving from drm_minor.
  • Collision with gfx-drm's C drivers: drm/i915 still name nodes after their instance number, so an i915 device and an illumos-drm device can both claim card0 until gfx-drm uses drm_minor_alloc (R5).
  • Renumbering after re-attach: a device auto-detached and re-attached in another order can swap numbers until devfsadm runs; this is documented. Whether to set ddi-no-autodetach is open.
  • Driver-private ioctls keep the exact-size match. Linux applies the size rule to them too.
  • Pre-existing, not changed: cargo xtask deps rdrmnull lists misc/virtio, because cargo unifies the features of ddi across the workspace. CI and the scripts link with explicit flags.

Resume the guest verification

# on the Mac: build the archives and assemble the payload
cd worktrees/illumos-drm/g6-minors
for p in drm_minor rdrmnull virtio_gpu; do cargo xtask build $p; done
#   payload as in artifacts/g6-minors/guest/ (archives, drm_minor.mapfile, confs,
#   tests, drm-test-lib.sh, run-*.sh, drm/ headers, the libdrm p5p)
# on hephaistos (check free -g and pgrep -a qemu-system first)
cd ~/illumos-drm-test/20260928 && bin/start-guest-gpu.sh g6-run2 $PWD/g6-run2.qcow2 2411 3h gl egl
# in the guest: install libdrm 2.4.134 from the p5p (logs/.../20261001-g6-run1-install.log), then
cd /root/g6 && ./run-g6-test.sh > run-g6.log 2>&1
# kernel-check with drm_minor loaded:
cargo xtask kernel-check --emit | guest-ssh 2411 'modload -p misc/drm_minor; mdb -k' | cargo xtask kernel-check --verify -

Verification of the final head

1 October 2026, at cc3f1ac (the kernel code of b7c94e7; archive SHA-256 drm_minor.a 2e115b53…, rdrmnull.a ab88f310…, virtio_gpu.a 51785d75…), on a fresh overlay of golden-20260930 (illumos 7e802e88a3), guest g6-run2 on port 2411, gfx-drm's libdrm 2.4.134 (1e68727) installed in the overlay only:

  • run-g6-test.sh passed: 354 PASS, 0 FAIL, with the same results as the earlier run:
    • Numbering: virtio first: card0, card1, card2. rdrmnull first: 0 and 1, then virtio 2.
    • Listing: drmdevice reports 3, 2 and 1 devices; getsundev 73/49/25 passed, 0 failed.
    • Suites: R0 106/107, R1 153, R2 216, R3 184 checks on both rdrmnull devices, plus the 32-bit probes. drm_r4_test passed 63 checks as card0 and as card2. drm_g6_test passed 27 checks on each device.
    • Unloading: both unload orders, reuse after reload, and misc/drm_minor refusing to unload while a driver is loaded.
    • truss: each grown command is sent once at its new size, with no retry.
    • Milestone scripts: run-r4-test.sh (72 checks), run-r1-test.sh (513) and run-r3-test.sh (477) pass beside an attached virtio_gpu; /etc and /devices are unchanged.
    • Stability: one boot, no panic.
  • cargo xtask kernel-check with misc/drm_minor loaded: drm-minor-sys symbols 2/2 (both resolve from drm_minor), ddi-sys symbols 984/984 and offsets 185/185, illumos-kernel-private-sys 13/13 symbols and 21/21 offsets, illumos-kernel-private-virtio-sys 48/48 symbols. No errors.
  • Logs:
    • logs/hephaistos/illumos-drm/20261001-g6-run2.log
    • logs/hephaistos/illumos-drm/20261001-g6-run2-install.log
    • logs/hephaistos/illumos-drm/20261001-g6-run2-kernel-check.log
    • per-test outputs in artifacts/g6-minors/run2-outputs/
    • console in logs/hephaistos/illumos-drm/g6-console/run/g6-run2/
  • Cleanup: the guest is shut down and its overlay deleted.

This closes the two items deferred above: the guest run of the post-review kernel code and kernel-check.

Anima work item: G6 `01a0f442-2d58-7593-9ed4-ccb0a7ba22a9` Stacked on #7 (`r4-virtio-gpu`, itself on #6 and #5). Two things: one DRM device numbering for every driver built on the core, and Linux's `drm_ioctl()` argument size rule for the core and mode-setting ioctls. ## What was built **`misc/drm_minor`** (`modules/drm-minor`, bindings in `crates/drm-minor-sys`) - A small misc kernel module that owns the table of DRM device numbers for the whole system. - It exports two C functions, `drm_minor_alloc(owner)` and `drm_minor_free(id, owner)`. - The table is 64 atomic owner words. Allocation is lock-free and never blocks or allocates. - A free that does not match the owner changes nothing and is logged. An `id_space(9F)` `id_free` of an unallocated id would panic instead. - `_fini` refuses while a number is taken. - The module is linked with an exports mapfile and `ld -B reduce`, so only `_init`, `_fini`, `_info` and the two functions are global. CI and the test scripts check this. - Threaded host tests cover the table. - Packaged by `packaging/drm-minor.p5m` (lints clean; published to a scratch repo on oibldofgate). `virtio-gpu.p5m` now depends on it. - CI builds and links it. **Numbering** - A device takes the lowest free number `N` when it attaches and gives it back when it detaches. Its nodes are `card<N>` and `renderD<128+N>`, with node minors `N` and `128+N`. - Each driver module records which of its instances holds which number (`drm::minor::bind`). `instance_of_minor` reads that record, so the instance number is no longer limited to 63. - `drm-minor-sys` declares `depends = ["misc/drm_minor"]`, so `cargo xtask link` adds `-N misc/drm_minor` and `kernel-check` covers both symbols. **Argument sizes** - Core and mode-setting commands now match on group, number and direction. The caller's size `U` comes from the command. - `drm::ioctl::SizePlan` is the Linux computation. `drm::uaccess::CoreArg` applies it. `CoreArg` deliberately does not dereference to `IoctlArg`, so a core handler cannot fall back to an exact-size copy by accident. - Unknown numbers stay `ENOTTY`, and ILP32 callers still get `ENOTSUP`. - Driver-private commands keep the exact match, and drivers list each size they accept. ## Numbering: the decision and the alternatives **(a) A separate misc module with a C ABI: chosen.** - The kernel loads it before any driver that names it with `-N`, and keeps it loaded while such a driver is loaded. So the table outlives every number in it, for any load and unload order. - It is also where Linux keeps the numbers (`drm.ko`), and it is the first piece of the R5 C interface. **(b) A registry that the first driver creates behind a well-known symbol: rejected.** - krtld resolves a module's symbols only from `unix`, `genunix`, the module itself and its `-N` dependencies (illumos-ddi DESIGN §4). The other drivers would need `ddi_modopen` at run time. - The registry would die with the module that created it while other modules still hold numbers from it. **(c) Stateless schemes: rejected.** - Fixed ranges per driver waste the 64 numbers and collide with the next driver. - Scanning the device tree for existing `card<N>` names races with concurrent attaches. **Deviations from Linux 7.3's `drm_minor_alloc`** - Linux allocates primary and render numbers independently, and has an extended range from 192. Here one number serves both nodes, capped at 64, because the clone layout gives a node minor 9 bits. - gfx-drm's C `drm`/`i915` still number their nodes by instance (open issue below). ## The Linux size rule matched (`drm_ioctl()`, read at v7.3-rc5) Linux uses these sizes: - `in = U` if both commands have `IOC_IN`, otherwise 0. - `out = U` if both have `IOC_OUT`, otherwise 0. - The buffer is `max(in, out, K)` bytes, where `K` is the kernel's size. It copies `in` bytes in, zeroes the rest, hands the handler `K` bytes, and copies `out` bytes back. So: - **Shorter caller structure:** zero-extended, and only `U` bytes come back. - **Longer caller structure:** not refused, whatever the extra bytes hold. They are copied in (an unreadable byte gives `EFAULT`) and copied back unchanged by `_IOWR` commands, come back as zeros from `_IOR` commands, and are ignored by `_IOW` commands. The core now does exactly this. A host test checks it against a restatement of Linux's code for every table entry, all four directions and every size from 0 to 255. Remaining differences, documented in the README: - A command with another direction is `ENOTTY`. Linux uses the intersection of both directions. - An unused number is `ENOTTY`. Linux returns `EINVAL`. - Handlers copy out explicitly. Linux copies its buffer back even after a failed call. The four grown commands are served at both sizes with equal results: `SYNCOBJ_HANDLE_TO_FD` and `FD_TO_HANDLE` (16 → 24 bytes), `WAIT` (32 → 40) and `TIMELINE_WAIT` (40 → 48). The added `point` and `deadline_nsec` fields are carried through unread. Their flags are unknown flags (`EINVAL`), as on a Linux kernel from before them. ## Test evidence **Host** (macOS, Rust 1.97.1 and nightly-2026-04-16) - `cargo test -p drm -p drm-uapi -p drm_minor`: 115 + 1 + 4 passed. - `cargo test -p virtio_gpu --no-default-features`: 5 passed. - clippy `-D warnings` is clean, including with the `panic-drill` feature. - fmt, `cargo doc -D warnings`, `uapi-check`: 0 differences. - `cargo xtask build drm_minor rdrmnull virtio_gpu` succeeds, and all three link with `ld` on illumos `cda5b9a49f` (oibldofgate). **Guest** (hephaistos, fresh overlay of `golden-20260930`: illumos `7e802e88a3`, osnet 23295, QEMU 6.2 `virtio-gpu-gl-pci`, 2 vCPUs, 3 GiB, port 2410) - gfx-drm's libdrm 2.4.134 p5p (#8, `1e68727`) is installed in the overlay only. - `tools/test/run-g6-test.sh` passed: **354 PASS, 0 FAIL**. Log: `logs/hephaistos/illumos-drm/20261001-g6-run1.log`. Per-test outputs: `artifacts/g6-minors/run1-outputs/`. Kernel archives built from `0155ded`, scripts at `bc5b0d4`. - **Order A (`virtio_gpu` first, then two `rdrmnull` devices):** `card0/renderD128` (virtio), `card1/renderD129` and `card2/renderD130` (rdrmnull@0 and @1). The minors match. - **Order B (`rdrmnull` first):** rdrmnull gets 0 and 1, virtio gets 2. - **Listing:** `drmdevice` reports 3 devices, and `getsundev` passes 73 checks, 0 failed. It reports 2 and 1 devices after unloads. - **Suites with all three attached:** - R0: 106 and 107 checks. - R1: 153 checks per device. - R2: 216 checks per device, including cross-device between the two rdrmnull devices. - R3: 184 checks per device. - The 32-bit probes pass on both rdrmnull devices. - `drm_r4_test` passes on virtio as `card0` and as `card2` (63 checks each). - `drm_g6_test` passes on every device (27 checks each). - `modetest` lists every display. - **Unload orders:** - rdrmnull first, then virtio; virtio first, then rdrmnull. A device keeps its number while the other driver unloads. - A reload gets the same numbers back, and a driver loaded into a gap gets the lowest free number. - `misc/drm_minor` refuses to unload while any driver is loaded, and unloads after both. Loading `rdrmnull` loads it. - No panic; the console log shows one boot. - **truss:** libdrm 2.4.134 sends each grown command once at its new size, the kernel answers 0, and there are 0 calls at the old size. The retry never runs. - **Milestone scripts beside an attached `virtio_gpu`:** `run-r4-test.sh` (KEEP=1, 72 checks), `run-r1-test.sh` with two rdrmnull devices (513) and `run-r3-test.sh` (477) all pass. `/etc`, `/devices` and their `/dev/dri` links are unchanged. - **Attempt 1:** `20261001-g6-run1-attempt1.log` has the same kernel results. Its failures were script bugs, fixed in `bc5b0d4`. **Also fixed:** the `run-r1-test.sh`/`run-r3-test.sh` race. They grepped `/var/adm/messages` for "detach refused" before syslogd had written it. They now poll with a bounded wait (`wait_log`, up to 15 s). ## Review The Anima review bar, applied locally (anima-review), approved round 1 with non-blocking items. All were addressed in `b7c94e7`: - The GEM registry entry is now recorded as the last fallible step of attach. Before, a failed attach left a stale entry, and global lowest-free numbers made that block the next attach. - The size tests check each handler's structure against its command. - The anonymous-file id space is named consistently. - README note on re-attach. - Test script nits. Round 2 on `b7c94e7`: approve. It asked that the scope of the guest evidence be stated plainly (done in `cc3f1ac` and below). ## Open issues / not done - **Guest verification of `b7c94e7` is deferred:** the attach ordering change and the anon id-space name. The test host was taken down right after the run. These changes are covered only by host tests, the cross-build and illumos linking. - **`cargo xtask kernel-check` was not run** against a kernel with `drm_minor` loaded. The guest run's `::whatis` shows both functions resolving from `drm_minor`. - **Collision with gfx-drm's C drivers:** `drm`/`i915` still name nodes after their instance number, so an i915 device and an illumos-drm device can both claim `card0` until gfx-drm uses `drm_minor_alloc` (R5). - **Renumbering after re-attach:** a device auto-detached and re-attached in another order can swap numbers until devfsadm runs; this is documented. Whether to set `ddi-no-autodetach` is open. - **Driver-private ioctls** keep the exact-size match. Linux applies the size rule to them too. - **Pre-existing, not changed:** `cargo xtask deps rdrmnull` lists `misc/virtio`, because cargo unifies the features of `ddi` across the workspace. CI and the scripts link with explicit flags. ## Resume the guest verification ```sh # on the Mac: build the archives and assemble the payload cd worktrees/illumos-drm/g6-minors for p in drm_minor rdrmnull virtio_gpu; do cargo xtask build $p; done # payload as in artifacts/g6-minors/guest/ (archives, drm_minor.mapfile, confs, # tests, drm-test-lib.sh, run-*.sh, drm/ headers, the libdrm p5p) # on hephaistos (check free -g and pgrep -a qemu-system first) cd ~/illumos-drm-test/20260928 && bin/start-guest-gpu.sh g6-run2 $PWD/g6-run2.qcow2 2411 3h gl egl # in the guest: install libdrm 2.4.134 from the p5p (logs/.../20261001-g6-run1-install.log), then cd /root/g6 && ./run-g6-test.sh > run-g6.log 2>&1 # kernel-check with drm_minor loaded: cargo xtask kernel-check --emit | guest-ssh 2411 'modload -p misc/drm_minor; mdb -k' | cargo xtask kernel-check --verify - ``` ## Verification of the final head 1 October 2026, at `cc3f1ac` (the kernel code of `b7c94e7`; archive SHA-256 `drm_minor.a` 2e115b53…, `rdrmnull.a` ab88f310…, `virtio_gpu.a` 51785d75…), on a fresh overlay of `golden-20260930` (illumos `7e802e88a3`), guest `g6-run2` on port 2411, gfx-drm's libdrm 2.4.134 (`1e68727`) installed in the overlay only: - **`run-g6-test.sh` passed: 354 PASS, 0 FAIL**, with the same results as the earlier run: - **Numbering:** virtio first: card0, card1, card2. rdrmnull first: 0 and 1, then virtio 2. - **Listing:** `drmdevice` reports 3, 2 and 1 devices; `getsundev` 73/49/25 passed, 0 failed. - **Suites:** R0 106/107, R1 153, R2 216, R3 184 checks on both rdrmnull devices, plus the 32-bit probes. `drm_r4_test` passed 63 checks as card0 and as card2. `drm_g6_test` passed 27 checks on each device. - **Unloading:** both unload orders, reuse after reload, and `misc/drm_minor` refusing to unload while a driver is loaded. - **truss:** each grown command is sent once at its new size, with no retry. - **Milestone scripts:** `run-r4-test.sh` (72 checks), `run-r1-test.sh` (513) and `run-r3-test.sh` (477) pass beside an attached virtio_gpu; `/etc` and `/devices` are unchanged. - **Stability:** one boot, no panic. - **`cargo xtask kernel-check`** with `misc/drm_minor` loaded: `drm-minor-sys` symbols 2/2 (both resolve from `drm_minor`), `ddi-sys` symbols 984/984 and offsets 185/185, `illumos-kernel-private-sys` 13/13 symbols and 21/21 offsets, `illumos-kernel-private-virtio-sys` 48/48 symbols. No errors. - **Logs:** - `logs/hephaistos/illumos-drm/20261001-g6-run2.log` - `logs/hephaistos/illumos-drm/20261001-g6-run2-install.log` - `logs/hephaistos/illumos-drm/20261001-g6-run2-kernel-check.log` - per-test outputs in `artifacts/g6-minors/run2-outputs/` - console in `logs/hephaistos/illumos-drm/g6-console/run/g6-run2/` - **Cleanup:** the guest is shut down and its overlay deleted. This closes the two items deferred above: the guest run of the post-review kernel code and kernel-check.
Core and mode-setting commands are now matched on group, number and
direction, whatever their size bits, and their argument is copied as
Linux's drm_ioctl() copies it (read at v7.3-rc5): with U the caller's
size and K the kernel's, min(U, K) bytes are copied in and the rest of
the kernel structure is zeroed; a longer caller structure has its extra
bytes copied in and copied back unchanged, or as zeros for commands that
only copy out; min(U, K) bytes of the result go back. ioctl::SizePlan is
the computation, checked against a restatement of Linux's code for every
table entry, direction and size; uaccess::CoreArg applies it. A plain
IoctlArg still copies exactly (driver-private ioctls, dma-buf and sync
file ioctls). Unknown numbers and other directions stay ENOTTY, 32-bit
callers ENOTSUP.

libdrm 2.4.134's grown drm_syncobj_handle, drm_syncobj_wait and
drm_syncobj_timeline_wait therefore reach the handlers without its
retry at the 2.4.109 size.
Every driver module links its own copy of the core, and each copy named
its first device card0 and renderD128, so rdrmnull and virtio_gpu
claimed the same /dev/dri links. A device number now comes from one
table for the whole system: the kernel module misc/drm_minor
(modules/drm-minor), a misc module with two C functions,
drm_minor_alloc(owner) and drm_minor_free(id, owner), declared for Rust
by the new crate drm-minor-sys. A device takes the lowest free number of
64 when it attaches (Linux's drm_minor_alloc takes the lowest free index
too) and gives it back when it detaches; number N names card<N> and
renderD<128+N>.

The table is 64 atomic owner words: lock-free, no allocation, and a
free by the wrong owner, of a free number or out of range changes
nothing and is logged (an id_space would panic on such a free). _fini
refuses while a number is taken; the kernel keeps the module loaded
while a dependent is loaded. The module is linked with an exports
mapfile and -B reduce, so only _init, _fini, _info and the two
functions are global (checked with nm on illumos cda5b9a49f).

drm-minor-sys carries depends = ["misc/drm_minor"], so cargo xtask link
adds -N misc/drm_minor to every driver and kernel-check checks both
symbols against the loaded module; xtask link applies the package's
exports mapfile. The core records which instance of the module holds a
number (minor::bind), which instance_of_minor now reads; the instance
number is no longer the device number and no longer limited to 63.
The C tests take their nodes from DRM_CARD, DRM_RENDER, DRM_CARD1 and
DRM_INSTANCE (kstat instance and bus ID) instead of assuming card0 and
renderD128; drm_r4_test takes the render node too. drm_r0_test opens
the card under test after drmOpen by name when another rdrmnull device
comes first, and now expects a 36-byte VERSION to be served (another
direction stays ENOTTY).

drm_g6_test calls the four commands whose structures grew in libdrm
2.4.134 (SYNCOBJ_HANDLE_TO_FD, FD_TO_HANDLE, WAIT, TIMELINE_WAIT) at the
2.4.109 and the 2.4.134 size and compares the results, and checks the
rest of the rule (shorter structures, the zeroed tail of an _IOR
command, EFAULT for an unreadable tail, ENOTTY for another direction);
'drm_g6_test libdrm' makes one libdrm call of each for truss.

drm-test-lib.sh, sourced by the run scripts: installs and removes
misc/drm_minor, finds a device's /dev/dri links, and waits for a line in
/var/adm/messages. run-r0/r1/r3/r4 link with -N misc/drm_minor, find
their nodes, remove only their own links, and run-r1 and run-r3 wait
for syslogd before counting 'detach refused' lines (they counted before
the line was written, a spurious failure seen on the new golden guest).
run-g6-test.sh attaches two rdrmnull devices and virtio_gpu in both
orders and runs everything on every device, then the milestone scripts
beside an attached virtio_gpu.

CI builds and links drm_minor with its exports mapfile and checks its
global symbols; the drivers link with -N misc/drm_minor.
packaging/drm-minor.p5m delivers the module, and virtio-gpu.p5m depends
on it.
dri_link matches a prefix of the device node name (pci1af4,1100@ did not
match pci1af4,1100@10); run-r4-test.sh no longer trips set -u when a
link is missing; run-r1 and run-r3 compare only the /dev/dri links, not
the directory's own line, which changes when another driver's links
share the directory; run-g6-test.sh ignores stdio's TCGETA on fd 1 in
the truss check, leaves /etc/path_to_inst out of the state comparison
(rem_drv keeps the virtio-gpu function's instance, as run-r4-test.sh
notes) and runs devfsadm -C before the last snapshot.
- device.rs: record the GEM state in the devmap registry as the last
  fallible step of attach. A later failure used to leave the entry
  behind; with system-wide lowest-free numbers the next attach of the
  driver is usually handed the same number and was refused as
  registered twice.
- ioctl.rs, kms/ioctl.rs: the size tests compare each handler's
  structure with the size its command carries (exhaustive over the
  operations) instead of checking a masked field against 256.
- anon_fd.rs: the anonymous-file id space is named after the driver
  instance, like the device's other arenas and kstats.
- README: what a detach and re-attach in another order does to the
  numbers; drm_g6_test: the message of the 24-byte WAIT; run-r1-test.sh:
  wait for the cancelled-fence line only when the R2 test ran.
README: what the G6 guest run covered
Some checks failed
ci / check-hosted (pull_request) Failing after 11m4s
ci / kmod-illumos (pull_request) Successful in 16m59s
cc3f1ac8d2
toasterson changed target branch from r4-virtio-gpu to main 2026-10-05 16:46:29 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
illumos/illumos-drm!8
No description provided.