# DF-3861 — amdgpu never unregisters the fictitious VRAM range at teardown (slot + memory leak in the DRM shim)

File: `sys/dev/drm/amd/amdgpu/amdgpu_device.c`

## Root cause

- `amdgpu_device_init()` registers the visible-VRAM aperture as a DragonFly
  fictitious physical range (amdgpu_device.c:2648-2658):

```c
	r = vm_phys_fictitious_reg_range(
	    adev->gmc.aper_base,
	    adev->gmc.aper_base + adev->gmc.visible_vram_size,
	    VM_MEMATTR_WRITE_COMBINING);
	...
	adev->fictitious_range_registered = true;
```

- `amdgpu_device_fini()` clears the flag but never unregisters
  (amdgpu_device.c:2751-2753):

```c
#ifdef __DragonFly__
	adev->fictitious_range_registered = false;
#endif
```

- The sibling driver does it correctly — radeon_device.c:1565-1567:

```c
	if (rdev->fictitious_range_registered) {
		vm_phys_fictitious_unreg_range(...);
```

- The DFly DRM shim backing this call (sys/dev/drm/drm_vm.c:141-227) keeps a
  static table of only `VM_PHYS_FICTITIOUS_NSEGS = 8` segments, does NOT
  deduplicate ranges, and leaks the whole `page_count * sizeof(struct vm_page)`
  allocation when a segment is abandoned: reg_range (drm_vm.c:173-204)
  kmallocs `visible_vram_size / PAGE_SIZE` fake vm_page structs and only
  unreg_range (drm_vm.c:206-227) frees them.

## Impact

Every amdgpu driver load/attach consumes one of the 8 global slots and pins
`(visible_vram_size/4096) * sizeof(struct vm_page)` bytes of kernel memory
forever (e.g. 8 GB visible VRAM ≈ 2M pages ≈ ~200 MB). After 8 attach/detach
cycles (module reload, repeated failed probes on flaky hardware, PCI
hotplug events) `vm_phys_fictitious_reg_range()` returns EBUSY — the shim is
exhausted for *every* DRM driver, including i915 (i915_gem_gtt.c:2968 uses
the same table) → driver load DoS. Stale segments also keep translating the
phys addresses of a detached device's BAR via
`vm_phys_fictitious_to_vm_page()`.

Trigger requires root (kldload/kldunload) or hardware-level re-probe events,
hence Low severity — but it is a guaranteed leak, not a race.

## Trigger

`leak_fictitious.sh` cycles `kldload amdgpu`/`kldunload amdgpu` on a host
with AMD hardware and shows the slot count decreasing in `vmstat -m`/dmesg
(the shim has no user-visible counter; the observable is the kmalloc'd
`M_DRM` zone size growth and, after 8 cycles, `amdgpu_device_init` failing
with "Failed to register fictitious range ... (16)" = EBUSY).

## Fix

`fix.diff` mirrors the radeon teardown (git-apply-able, validated).
