# DF-4870 — r600_dma_ib_test leaks the IB on fence-wait failure/timeout

File: `sys/dev/drm/radeon/r600_dma.c` (pass 2, GLM 5.3)
Severity: Low · CWE-401 (Missing Release of Resource on Effective Error Path)

## What

`r600_dma_ib_test()` acquires an IB with `radeon_ib_get()` (r600_dma.c:351),
schedules it, then waits on its fence. The two fence-wait error paths return
**without** `radeon_ib_free()`:

```c
369:    r = radeon_fence_wait_timeout(ib.fence, false, usecs_to_jiffies(
370:        RADEON_USEC_IB_TEST_TIMEOUT));
371:    if (r < 0) {
372:        DRM_ERROR("radeon: fence wait failed (%d).\n", r);
373:        return r;                       /* <-- ib leaked (no radeon_ib_free) */
374:    } else if (r == 0) {
375:        DRM_ERROR("radeon: fence wait timed out.\n");
376:        return -ETIMEDOUT;              /* <-- ib leaked (no radeon_ib_free) */
377:    }
```

while the *later* `-EINVAL` path does free it (r600_dma.c:391) — proving the
omission on the earlier paths.

`radeon_ib_get()` (radeon_ib.c:57-93) takes a chunk from the IB suballocator
(`radeon_sa_bo_new`, 64 KB GTT slots out of a `RADEON_IB_POOL_SIZE*64 KB` pool)
and `radeon_ib_schedule()` sets `ib.fence`; only `radeon_ib_free()`
(radeon_ib.c:73-81) returns the sa_bo chunk and drops the fence ref.

## Trigger / preconditions

* Caller chain: `radeon_ib_ring_tests()` (radeon_ib.c:257-287) →
  `radeon_ib_test()` → asic `ib_test` = `r600_dma_ib_test` for the DMA rings
  of R600/RV770/evergreen/northern-islands asics (radeon_asic.c:925, 1329,
  1639, 1908). Called from `radeon_device_init/resume/late_init`
  (radeon_device.c:1486, 1748, 1932).
* Fires when the DMA engine fence fails or times out during driver
  init/resume — i.e. a hung/absent DMA engine on real r6xx+ hardware.
* Each occurrence permanently removes one 64 KB IB slot (plus a fence
  reference) from the pool until `radeon_ib_pool_fini()`. Repeated
  suspend/resume cycles with a wedged DMA ring progressively exhaust the IB
  pool → later GEM submissions fail (`-ENOMEM` from `radeon_ib_get`), an
  availability degradation localized to the broken GPU.

## Verdict

Not runtime-verified: this bug requires real r6xx-class Radeon hardware
hung at init. The audit QEMU guest has only a Bochs emulated VGA
(chip 0x1111:1234, see `env.txt`), no `/dev/dri`, and radeon.ko is not
loaded. The defect is unambiguous from source (the sibling error path frees;
these two do not). Status: `untested` (hardware-gated), confidence `certain`
by reading.

## Fix

See `fix.diff` — add `radeon_ib_free(rdev, &ib)` before both returns
(mirrors the existing `-EINVAL` path at r600_dma.c:391). Same shape as the
upstream Linux error handling for `radeon_ib_schedule` failure.
