R2: fences, dma_resv, syncobj, sync_file and PRIME with anonymous fds #6
Loading…
Reference in a new issue
No description provided.
Delete branch "r2-sync"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Anima work item: WI-454
01a0e387-6ec8-7d63-a751-7a2de07be520Milestone R2 of the Rust DRM core: fences, reservations, sync objects with timelines, sync files, and PRIME, with file descriptors handed out from ioctls.
Stacked on PR 5 (
r3-kms, R3's KMS); the base of this PR is that branch. The workspaceCargo.tomlpins illumos-ddir2-private-fdatfaec57598b(illumos-ddi 5 (illumos/illumos-ddi#5), stacked on illumos-ddi PR 4).Cargo.lockwas regenerated from that git dependency without a patch, andcargo check --lockedpasses. Merge order: illumos-ddi PR 4, then the illumos-ddi R2 PR, then PR 5, then this one. After that, move the pin to the illumos-ddi merge commit.Reconciliation with R3
r3-kms. The shared files keep both sides:device.rs: thekmsandsyncfields;clone_opensets up sync, then KMS.closereleases KMS, then GEM, then sync, and frees the clone id last.detachtears down KMS, clears sync, then quiesces GEM and sync.caps.rs,README.md, the R0 test's capability table, andrdrmnull.chpoll(9E)uses R3's API from illumos-ddi (CharDevice::chpoll -> (PollEvents, PollRegistration<'a>)):SyncCore::anon_chpoll. A sync file keeps its head in addi::PollBoxand registers it with theunsafePollHead::registration_unchecked, because the anonymous-file entry, not the instance, owns it.idlehead through the safe API.FENCE=DRM_COMMAND_BASE + 4andBO_WAIT=+ 5, because R3'sSCANOUTtakes+ 3.run-r3-test.shlinks with-N fs/specfslike the other scripts.IN_FENCE_FD/OUT_FENCE_PTRnow says that connecting them to R2's sync files is open.What was built
drm::fence:Fence(Linuxdma_fence) with a context, a wraparound-safe seqno, an error and a timestamp.remove_callbackwaits for a running callback.ETIME,EINTR).Fence::array(all or any, first error) andFence::chain(timeline points, collected as they signal), withchain_find_seqnoandchain_query.FenceDomain: it holds its locks at the driver's interrupt priority and refuses high-level priorities, owns thesynckstat, and parks interrupt-context drops for a task queue, becausemutex_destroy(9F)is thread-context only.drm::wwmuteximplements wait-die, as Linux's reservation class does, withEDEADLK,lock_slow,lock_all,EALREADYandEINTR.drm::resvhas the kernel, write, read and bookkeep usages, adds fences under the ww guard, iterates while locked, waits, and returns a singleton fence. Every GEM object has one.drm::syncobjanddrm::syncobj_ioctl:SYNCOBJ_*ioctls, with Linux's checks and errnosWAIT_ALL,WAIT_FOR_SUBMIT,WAIT_AVAILABLE, timelines andTRANSFEREXPORT_SYNC_FILE,IMPORT_SYNC_FILE)drm::sync_file:poll(2)(pollwakeup(9F)from the signaller's context),SYNC_IOC_MERGEandSYNC_IOC_FILE_INFO.drm::anon_fdanddrm::prime:docs/anon-fd.md)PRIME_HANDLE_TO_FD(DRM_CLOEXEC,DRM_RDWR, one dma-buf per object)PRIME_FD_TO_HANDLE(returns the existing handle or a new one)mmap(2), andDMA_BUF_IOCTL_SYNC, which waits for the reservation at the start of CPU accessGET_CAPreportsPRIME= import|export for GEM drivers, andSYNCOBJ/SYNCOBJ_TIMELINEaccording to the newFeatures::SYNCOBJandFeatures::SYNCOBJ_TIMELINE.rdrmnullhas a test timeline that a soft interrupt signals;timeout(9F)triggers it (Driver::fence_priority). It adds the test-only ioctlsFENCEandBO_WAITin the driver range, and signals pending fences withECANCELEDat detach.tools/test/drm_r2_test.c;tools/test/rdrmnull-two.conf.run-r1-test.shruns them.Decisions
pipe(2)and LDI do (makespecvp,VOP_OPEN,falloc,setf). The alternatives were a clone-open pseudo driver or a private vnode type. Close, poll, mmap,fstatand detach safety come from specfs. Seedocs/anon-fd.md.Ctxtokens, waits takeSleepable, and locks sit at the driver's declared interrupt priority.reservation_ww_class, with a real two-thread deadlock-avoidance test.ENOTSUP). A dma-buf of another device givesENOTSUP, and another driver's file givesEINVAL, because each module links its own core until R5.segmap(9E)with Linux's errnos (EINVAL,EACCES) instead of theENXIOofdevmap_setup. This also fixes a refused mapping lingering until the process exits; the R1 test expects the new errnos.Deviations
docs/anon-fd.md).ufallocis not bound:falloccalls it, and nothing needs a descriptor without a file.TRANSFERrefuses flags other thanWAIT_FOR_SUBMIT,PRIME_FD_TO_HANDLErefuses a non-zeroflags, and arrays of handles are limited to 65536 entries (EINVAL).EXPORT_SYNC_FILEof an unknown handle givesENOENT(README).poll(2)on a dma-buf (implicit sync through its reservation) answersENOTSUP.ENOTSUP.Verification (after the rebase onto R3)
All runs used a fresh disposable guest
r2-run4on Hephaistos (golden overlay, illumoscda5b9a49f, 2 vCPU, 3 GiB). The module was built fromfc1e54ff2aagainst illumos-ddifaec57598b.run-r1-test.sh, one device: R0 105, R0 probe 5, R1 153, R1 probe 4, R2 206 (including 18 child checks), R2 probe 3, pending-fence cancel PASS. The export-vs-last-close race: 1600 exports of three buffers from four threads, 0 errors./etc,/devicesand/dev/driunchanged, fail=0.run-r1-test.sh, two devices (rdrmnull-two.conf): R0 105, R1 153, R2 216. A dma-buf is refused across devices withENOTSUP; a sync object and a sync file are imported and waited on across devices. Race 0 errors, cancel PASS, state unchanged, fail=0.run-r3-test.sh(R3's suite, with this module): R0 105/5, R1 153/4, R3 184, R3 probe 3, 9 modetest/unload/state PASS lines, vblank 60.07 Hz, fail=0.KM_SLEEP,247bb8b),run-r1-test.shran again with one device: fail=0, race 0 errors, cancel PASS, state unchanged. That log has R2 at 205 PASS lines because one child line is missing: the child'sWAIT_FOR_SUBMITcheck printed at the same moment as the parent's next line, and the two share the log file (writes withoutO_APPEND). The child exited 0, which the parent checks ("the sync object child passed all its checks").rselftestwithprivate-gate: 57/57.kernel-checkof the private tier: 13/13 symbols.pollwakeup(9F)calls in an interrupt thread at PIL 1, from the timeline soft interrupt. The first run panicked insegdev_create; that is fixed in illumos-ddi by the panic-to-type rule (see that PR).--locked, no patch:cargo checkcargo clippy, also withpanic-drillcargo fmtcargo doccargo test -p drm -p drm-uapi: 108 + 1uapi-check: 0 differencesnightly-2026-04-16Logs (workspace):
logs/hephaistos/illumos-drm/20260929-r2-rebased-one.log,20260929-r2-rebased-two.log,20260929-r2-rebased-r3.log,20260929-r2-rebased-final-one.log,20260929-r2-rebased-rselftest-private.log,20260929-r2-rebased-kernel-check.log. Earlier runs:20260929-r2-final-*-device.log,20260929-r2-round2-*.log,20260929-r2-run3-full.log,20260929-r2-panic-console.log,20260929-r2-panic-mdb.log,20260929-r2-softint-pollwakeup-dtrace.log. Notes:notes/illumos-drm-segdev-panic-20260929.md,notes/illumos-gate-segdev-specfind-proposal.md. Dump on Hephaistos:~/illumos-drm-test/20260928/dumps/r2-segdev-20260929/.Review: a separate reviewer applied the Anima rules.
DMA_BUF_IOCTL_SYNC, the pass-through of chpoll events, two errno or documentation points, and per-instance timers.PollBox::new) is fixed.Open issues
IN_FENCE_FD,OUT_FENCE_PTR) need R2 and R3 together; they are follow-up work.detachtears down KMS before the GEM and sync checks. A detach refused because a fence is still pending (new with R2), or because GEM objects remain (already in R3), leaves the device attached with its KMS state gone.segdev_createNULL check;devmap_setupnot unmapping refused mappings) are not filed.Update: restacked on the detach fix
Rebased onto PR 5's detach fix; R2's pending-fence refusal now runs among the checks before any teardown. The pending-fence test confirms that after the refused detach the display (modetest) and the sync paths still work and that the detach cancelled the pending fence. Kernel runs on illumos cda5b9a49f: R0-R2 502 PASS / 0 FAIL, R3 476 PASS / 0 FAIL. The "detach order" open issue is resolved.
11074d036be59b6a8677