R5b: public-layout base objects (facade 1.0): Linux fence semantics, GEM refcount, drmm, drm_printer, handle walk #13
Loading…
Reference in a new issue
No description provided.
Delete branch "r5b-layouts"
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: R5b
01a0f883-25ff-7b12-8b49-25aab381eec5Public-layout base objects in the Rust DRM core (facade 1.0): the public fields of
dma_fence,drm_gem_objectanddrm_deviceare now the objects' state, as Linux v7.2 drivers (first target: modern i915, headless) use them, plus foreign fence ops, managed resources,drm_printerand a handle walk.Base:
g8-reimport(#11). The first commit on top is a merge ofg7-coexist(#10,98ea76c, no conflicts), as the work item asked; both pin illumos-ddi6e65077(g7-module-busy), unchanged here. Review91482f3..501c309.Layouts (Linux v7.2 names and order; MIT reimplementations, D7)
drm_devicemanaged.*)include/drm/drm_device.h:managed{resources, final_kfree, lock} afterdma_dev,open_countafterunique(i915/xe/amdgpu field sets, analysis §2.3)drm_filedrm_file.h;object_idr/table_lockreplaced bydrm_illumos_gem_for_each_handle()drm_gem_objectgpuva.*)drm_gem.h;refcountis the object's only countdma_fencedma-fence.h; every field is state; flag bits now v7.2's (SEQNO64=2, SIGNALED=3; 0.1 had SIGNALED=2)dma_fence_ops/dma_fence_cbcb_listis a real listdma_resv/dma_bufdrm_printer/va_formatdrm_print.h, newThe tails are in the version handshake (
DRM_FACADE_TAILS, appended after the struct sizes;drm_facade_versionkeeps its size so an older driver still reads the refusal).gen_facade.pynow follows anonymous members (fence lock/list unions,managed.*,gpuva.*): 40 sizes, 256 offsets.What changed
drm_core::cfence, host-tested): Linux's rules on the structure — the lock (extern or inline) protectscb_list; signalling sets the bit, replaces the list by the timestamp and runs callbacks under the lock;enable_signalingonce,signaledpolled,wait,set_deadline, names; by-hand signalling (i915 breadcrumbs) works. The core's view: a driver fence has a shadow core fence signalled by a bridge callback on itscb_list(added when the core first takes the fence; holds a reference until it ran); a core fence handed out is a proxy with core ops whoseenable_signalingarms a relay (takes a reference only while the count is non-zero; the release removes it, waiting for a running one). Last-reference release runs inline only in thread context, without the fence's lock, and not for a proxy with an armed relay; otherwise it is parked through a node in the tail on the module domain's raw list (no allocation) and run by its task queue — this fixes R5a's same-CPU spin. Unsignalled fences released with callbacks signal them with-EDEADLK(Linux). New:dma_fence_init64,signal_locked,signal_timestamp(_locked),check_and_signal(_locked),enable_sw_signaling,default_wait,set_deadline,driver_name,timeline_name,drm_illumos_fence_put_deferred,drm_illumos_fence_barrier(drains serialised, so the barrier waits for one in progress); inline helpers (dma_fence_spinlock, lock macros,is_later,get_status_locked, ...). A detach runs parked releases before counting the device's fences.drm_gem_object.refcountis the only count (GemObject::ext_count,drm_core::refcount: everyGemRefcounts there; no resurrection; upgrades under the offset lock).kref_read/kref_get/kref_get_unless_zeroindrm_facade_types.h(lists whose lock keeps the memory; no RCU grace period).drm_illumos_gem_for_each_handle(file, fn, arg)walks a file's handles under the G8 hook lock over a snapshot;drm_gem_object_lookupworks from the callback.drm_managed.h,drm_core::managed):drmm_add_action(_or_reset),drmm_release_action,drmm_kmalloc/kzalloc/kmalloc_array/kcalloc,drmm_kstrdup,drmm_kfree; released newest first at the lastdrm_dev_put(), after unregister and the driver'srelease, before free.gfp_tbits are the facade's. Not provided:drmm_mutex_init,drmm_alloc_ordered_workqueue(need R5c).drm_print.h,drm_core::print): v7.2 categories (bit numbers),drm_printerwith info/dbg/err printers,drm_printf/vprintf/puts,drm_err/warn/notice/info(_once),drm_dbg_*,DRM_DEV_*,DRM_*; variadic entry points are header statics ending indrm_illumos_vprintk()(vsnprintf into 512 B, cut with "...",dev_err/cmn_err; errors/warnings console+log, notices both, info/debug log only). Knob:set drm_core:drm_debug = 0x6(R5a's header named the wrong module) orecho 'drm_debug/W 0x6' | mdb -kw.signaledpolls; driver lock at softint priority; second context),FENCE_OPS_SELFTEST(15 checks),HANDLES,PRINT_SELFTEST, drmm order check,_finibarrier.FENCE_SELFTESTRELEASED/QUEUED now check Linux's release rules.tools/test/drm_r5b_test.c,run-r5b-test.sh;run-r5a-test.shmismatch probes now cover any major and a same-sizedrm_devicewith a smaller tail (and the script is executable).Evidence
cargo test -p drm-core -p drm-uapi -p drm-facade154 + 2 + 1 (new: 14 cfence tests with a mock driver and threads, relay/release races forced with test hooks, sibling-proxy last put; raw deferral list; refcount incl. upgrade-vs-last-put and underflow; managed order/early release/add_or_reset/misuse/4 threads; print rules; handle walk vs 4 threads closing/creating),virtio_gpu --no-default-features6; clippy-D warnings, fmt,cargo doc -D warnings,check-generated.shclean.golden-20260930(illumos7e802e88a3), libdrm 2.4.134 p5p in the overlay, 2 vCPU / 3 GiB, one guest at a time:r5b-run2atc24a58e(kernel code identical to HEAD):run-r5b-test.shPASS —run-r5a-test.shPASS (168 passing checks: R0–R4 on all three drivers, R5a cross-driver ×4, G6, R1 two cdrmnull, mismatch probes incl. tail), drmm reverse order at 7/7 cdrmnull detaches,drm_r5b_test47/0 (15 fence-ops checks incl. 200 interrupt-race rounds; array of two driver fences, chain out of order, EIO sync file, 3000 walks vs 1592 concurrent handles, refcount 1→2→3→4→3→2), all log paths withdrm_debug0 and 0x6, 0 timeline releases in interrupt context,run-g8-test.sh kernelPASS. Logslogs/hephaistos/illumos-drm/20261003-r5b-run2-*-c24a58e.log.20261003-r5b-facade-check.log; committedfacade_layout.illumos.out). kernel-check withmisc/drm_core(+CTF) loaded: ddi-sys 53/60, 185/185, 984/984; drm-facade-sys sizes 40/45, offsets 244/256 (rest are members of anonymous types, checked via parents), symbols 123/123; private 3/3, 46/46, 15/15 (20261003-r5b-run2-kernel-check-c24a58e.log).r5b-run3atb3fab03:run-g7-test.shall 13 phases PASS (81 checks, gfx-drm combo p5p with the reverse guard), then with the new stack selectedrun-r5a-test.sh LEGACY_GUARD=skip: first run failed the unprivileged opens of cdrmnull's stale0600nodes left by the uninstalled package (the known G7 open issue; identical failure set to G7's run), second run PASS (76). Logs20261003-r5b-run3-g7-*.log.r5b-run1(earlier iteration ata94a69c/0ca2fae): found the same-context merge test bug (fixed by the second timeline context). No panic in any run; consoles inlogs/hephaistos/illumos-drm/r5b-console/.artifacts/illumos-drm-r5b/drm_facade_ctf.o).Review
Two rounds against the anima-review bar (Opus). Round 1 rejected: relay/release race test did not reach the paths (now forced and asserted), a sibling proxy's callback could make an inline release wait for its own queued relay (armed proxies now always release on the task queue; regression test), GEM external count logic untested (moved to
refcount, host-tested), barrier vs concurrent drain (drain lock), kref/RCU doc claims (helpers added, docs limited), drmm log baseline. Round 2 approved; its notes (serialise relay-hook tests, barrier context doc, test count) are fixed inb3fab03.Deviations / open issues
opskept after signalling;release == NULLfrees nothing (dma_fence_freeneeds R5c's kfree); the core enables signalling when it takes a fence; sync objects return proxies (no pointer identity with the driver's fence).dma_fence_array_create,dma_fence_chain_*walkers,dma_resviterators and acquire contexts (lockstays a placeholder),drm_dev_enter/exit,drmm_mutex_init,drm_WARN*, line/coredump/seq_file printers; GEMhandle_count/name/dma_bufstay in the core; no Rust wrapper for the handle walk (no Rust user).drmm_kmalloc(dev, 0, …)returns NULL; messages logged in interrupt context are cut by illumos at 200 bytes.0600nodes (G7 open issue) remain.facade_layout.illumos.out.The test timeline's fences now behave as a GPU driver's do with Linux's fence ops: the soft interrupt completes a due fence ("hardware" done, which ops->signaled reports) and signals it only if somebody enabled signalling (ops->enable_signaling: a callback, a wait, or the core taking the fence into a sync object, reservation or sync file); the fences use a driver lock at the soft interrupt's priority. Releases are counted (none may run in interrupt context), _fini waits for queued releases (drm_illumos_fence_barrier) and refuses while a timeline fence lives, and the device's release barriers before its locks go. New test ioctls: FENCE_OPS_SELFTEST (15 checks: enable once and false, polling, the wait op, the default wait and polling-only completion on the timeline, deferred release from the soft interrupt, last puts from a callback and under the fence's lock, EDEADLK, i915-style signalling by hand reaching a sync object, names and deadlines, 64-bit sequence numbers, callbacks under the lock, a relay between two structures, and an add/remove/signal race against the soft interrupt), HANDLES (the handle walk with lookups and early stop, the live GEM reference count and a kref_get_unless_zero round trip) and PRINT_SELFTEST (drm_printer with a driver printer, the drm_* and DRM_* macros, printers, once, a cut message). Each device registers managed resources at attach and checks their release order when it goes. drm-facade gains gem::for_each_handle, the safe walk for Rust drivers.- A proxy whose relay is armed is always released by the task queue: a callback on another proxy of the same core fence could drop its last reference while its relay is queued behind that callback on the same thread, and the inline release would wait for the relay for ever (host test a_sibling_proxys_callback_drops_the_last_reference). - proxy_release_races_the_relay forces each path with test hooks (relay started but not holding a reference: the release waits and the relay finds zero; relay holding the last reference; free races) and asserts every path was taken and each callback ran once with the right error. - FenceDomain drains are serialised by a lock that barrier takes, so a barrier no longer returns while another drain still runs a release. - The external GEM count's KArc logic moves to drm_core::refcount (clone_ref, release, upgrade over ExtCounted), host-tested with upgrades under a table lock racing clones and the last put, and an underflow; GemRef uses it. - drm_facade_types.h provides kref_read, kref_get and kref_get_unless_zero; drm_gem.h and the README limit lockless use to driver lists whose lock keeps the memory (no RCU grace period); cdrmnull uses the facade's helpers. - A driver fence that dma_fence_init signalled for lack of memory reaches sync objects and sync files as a signalled fence with -ENOMEM. - Locked::snapshot allocates before taking the handle table's lock. - run-r5b-test.sh counts the drmm messages of its own run only. - drm_facade:💎:for_each_handle is gone (no caller, no test).