DF-4532 / trigger.sh
#!/bin/sh # DF-4532 — device_busy() leak in drm_open() blocks driver detach forever # # drm_file.c:351 calls device_busy(dev->dev->bsddev) on every successful # open, but NO live path ever calls device_unbusy(): drm_close() lacks it, # and the only device_unbusy() in sys/dev/drm (drm_drv.c:1230) sits in # drm_cdevpriv_dtor(), which is never registered (no devfs_set_cdevpriv() # caller exists anywhere in the tree). device_busy() increments # dev->busy and forces dev->state = DS_BUSY (subr_bus.c:1844-1853); # device_detach() refuses to run for DS_BUSY devices (subr_bus.c:2129ff). # Net effect: after the FIRST open of /dev/dri/cardN, the drm device (and # its recursively-busied PCI parent) can never detach or kldunload again. # # This script demonstrates the observable half (needs a DRM device): # 1. baseline: kldunload of the drm driver succeeds before any open # 2. open /dev/dri/cardN once, close it # 3. kldunload now fails EBUSY forever despite zero open fds # # Hardware-gated on the QEMU audit guest (no /dev/dri). Run as root on a # system with a DRM device. set -e DRIVER=${1:-i915} echo "== baseline detach attempt (no drm fd ever opened) ==" kldunload "$DRIVER" 2>&1 || true kldload "$DRIVER" 2>&1 || true echo "== single open/close of /dev/dri/card0 ==" perl -e 'open(F, "</dev/dri/card0") or die "no drm device: $!\n"; close(F)' \ || true echo "== detach attempt after the one open/close ==" if kldunload "$DRIVER" 2>&1; then echo "UNEXPECTED: unloaded (bug not reproduced)" else echo "REPRODUCED: kldunload fails (device wedged in DS_BUSY forever)" fi |