G8: a re-import or second handle no longer detaches a buffer (GEM hooks once per file and object) #11
Loading…
Reference in a new issue
No description provided.
Delete branch "g8-reimport"
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: G8
01a102ed-3645-7ce3-a093-c9d22212d5d1Stacked on #9 (
r5a-facade@2306e85). Importing or opening an object that a file already holds no longer detaches it from the GPU.Root cause
GemCore::handle_find_or_create(thePRIME_FD_TO_HANDLEpath) called the driver'shandle_openedhook before looking for the file's handle. When it found one, it undid the hook withhandle_closed(gem.rsat2306e85, lines 1838–1863). On virtio_gpu these hooks areCTX_ATTACH_RESOURCEandCTX_DETACH_RESOURCE, and the host does not count attachments. So re-importing a buffer the file already held detached the resource from that file's virgl context while its existing handle was still using it. That is G3's DTrace finding (attach then detach for the same context) and G4's black screen: after Xorg's DRI3 PixmapFromBuffer of its own front buffer, glamor's context lost the buffer ("Illegal resource").Linux's per-handle callbacks would have the same effect in one more case: a second handle from
GEM_OPENorMODE_GETFB, closed again (Linux's virtio-gpu detaches on every close).Fix
drm_core::objects::FileTable/Locked. A file's handle table now calls the driver's open hook when the file gets its first handle to an object, and the close hook when its last handle goes. A per-file hook lock is held across the decision, the hook and the table change; it plays the role of Linux's per-file PRIME lock. Lock order: hook lock, thennames, then the file's handle table.GemCore::import_handlereplaceshandle_find_or_create. It looks for the file's handle under the hook lock first and runs no hook if it finds one. This covers same-device buffers and another driver's buffers (R5a). For another driver's buffer, the import (gem_prime_import) now also happens under the lock, so two threads of one file importing the same buffer get one import (before, this was a documented race).GEM_OPEN,MODE_GETFBanddrm_gem_handle_create()still create a second handle, but run no hook for it, so closing that handle leaves the attachment alone.GEM_OPENreturns the existing handle. It does not.drm_gem_open_ioctlgoes throughdrm_gem_handle_create_tail, which always allocates a new handle.drm_r1_test.c:687).funcs->openandfuncs->close(and drm-facade'sGemObject::open/close) now run once per file and object; this is documented ininclude/drm/drm_gem.hand in the README as an R5a deviation. Drivers that count their calls, as Linux's amdgpu, radeon, nouveau and cdrmnull do, see the same balance.FileHooks::closed, called byLocked::add's undo (only after its own open) orLocked::released(only once the file holds no handle to the object). The GETFB2 error path closes only handles that the same call created.handle_find_or_createis gone.gemkstat gainsattached(file and object pairs currently open) andopens(open-hook calls so far).Tests
crates/drm-core/src/objects.rs):reimport_and_second_handles_keep_the_attachmentfailed_creation_undoes_only_its_own_openconcurrent_hooks_follow_the_handles: 8 threads and 4 files. The threads import shared buffers (twice in a row, as DRI3 does), open them by name, create and close handles, with hooks that yield and assert that open and close alternate. A checker holds every hook lock and verifies that a file has an object open exactly while it holds a handle to it.cargo test -p drm-core -p drm-uapi -p drm-facade: 127 + 2 + 1 pass.virtio_gpu --no-default-features: 6 pass. clippy-D warnings, fmt and rustdoc-D warningsare clean.tools/test/drm_g8_test.c,run-g8-test.sh kernel|reproducer|cleanup). On cdrmnull, rdrmnull and virtio_gpu:GEM_OPENandMODE_GETFBgive a second handle with no attachment or open; closing it leaves the attachment.TRANSFER_FROM_HOST;TRANSFER_TO_HOSTreads back;ADDFB2+SETCRTC+DIRTYFB(RESOURCE_FLUSH) shows it, and a screendump confirms it.tools/test/dmabuf_import_test.c, unchanged apart from a provenance header andDRM_RENDER.Evidence (hephaistos, guest
g8-run1, port 2440, fresh overlay ofgolden-20260930.qcow2, QEMU 6.2virtio-gpu-gl-pci+ egl-headless, virglrenderer 0.9.1, 2 vCPUs, 3 GiB; logs in the workspace underlogs/hephaistos/illumos-drm/20261003-g8-run1-*)drm_g8_test, archives of base2306e85Illegal resource 2,Illegal command buffer. Missingattached/openskstats account for the other failures. (-baseline2-2306e85.log)drm_g8_testatc2ea15b/etcand/devicesunchanged after unload (-fix-c2ea15b.log; first round-fix-f614b7a.logwas also 143/0)run-r5a-test.shatc2ea15b-r5a-suite-c2ea15b.log)drm_g8_testatc2ea15bafterpkg updateto osnet 23298-23298-fix-kernel.log)dmabuf_import_test, G3 Mesa 25.3.6 (p5p sha25651e7de0e…6a), base archivesIllegal resource(-23298-old-reproducer.log)dmabuf_import_testatc2ea15b-23298-fix-reproducer.log)Screendumps are in the workspace under
artifacts/g8-reimport/. G4'sdri3_probeagainst a glamor Xorg could not be run: OI's xorg-server 1.19.7 glamor requiresEGL_MESA_drm_image, which Mesa removed in 25.2. The two-process reproducer, and the kernel test's DRI3 sequence, are the end-to-end evidence. No panic. The guest was shut down and its overlay deleted.Review
One review round under the Anima rules (round 1: approve, non-blocking findings), all addressed in
c2ea15b:openscounter, so the null-driver checks catch an open-then-close re-import;SET_MASTERreporting, and a reproducer guard in the script.Importing an object a file holds already (PRIME_FD_TO_HANDLE) ran the driver's open hook before looking for the file's handle and, finding one, undid the hook with the close hook. virtio_gpu's hooks attach the resource to the file's virgl context and detach it, and the host does not count attachments, so the undo detached the resource that the existing handle still used: after Xorg's DRI3 PixmapFromBuffer of its own front buffer, glamor's context lost the buffer ("Illegal resource") and the screen stayed black (G3, G4). The handle table of a file (objects::FileTable) now calls the driver's open hook when the file gets its first handle to an object and its close hook when the last one goes, with a per-file hook lock held across the decision, the hook and the table change (Linux's per-file PRIME lock). PRIME_FD_TO_HANDLE looks for the file's handle under that lock first and runs no hook when it finds one, for same-device buffers and for another driver's (whose import is now also made under the lock, so two threads of one file get one import). GEM_OPEN and MODE_GETFB still make a second handle, as in Linux, but run no hook for it, and closing it leaves the attachment alone. A failed handle creation undoes only the open hook it ran itself. The gem kstat counts the file and object pairs whose open hook ran (attached). Host tests: re-import and second handles keep the attachment, a failed creation undoes only its own open, and eight threads importing (twice, as DRI3 does), opening by name and closing in four files with yielding hooks keep "attached exactly while held" (both fail on the old behaviour and without the hook lock). Guest tests: tools/test/ drm_g8_test.c and run-g8-test.sh; G3's two-process reproducer as tools/test/dmabuf_import_test.c.c2ea15b