# DF-4212 — mpt_raid_attach error paths: MPT_UNLOCK on a lock it never took (guaranteed panic) + CCB leak

- **File**: `sys/dev/disk/mpt/mpt_raid.c`
- **Lines**: 283–287, 288, 311, 314–317
- **Class**: error-path lock protocol violation (CWE-667) → kernel panic; memory leak (CWE-401)
- **Hardware gate**: LSI MPT Fusion RAID controller, attach-time error (kthread_create ENOMEM)

## Bug 1 — unlock without lock (panic)

`mpt_raid_attach()`:

```c
	error = mpt_spawn_raid_thread(mpt);          /* 283 */
	if (error != 0) {
		mpt_prt(mpt, "Unable to spawn RAID thread!\n");
		goto cleanup;                        /* 286: MPT_LOCK NOT held */
	}
	csa = &xpt_alloc_ccb()->csa;                 /* 288 */
	MPT_LOCK(mpt);                               /* 290 */
	...
cleanup:                                             /* 314 */
	MPT_UNLOCK(mpt);                             /* 315: LK_RELEASE */
	mpt_raid_detach(mpt);
	return (error);
```

If `mpt_spawn_raid_thread()` fails (`kthread_create` ENOMEM,
`mpt_raid.c:645`), control reaches `cleanup` without ever executing
`MPT_LOCK` (taken only at line 290). `MPT_UNLOCK` is
`lockmgr(&mpt->mpt_lock, LK_RELEASE)` (`sys/dev/disk/mpt/mpt.h:763-764`), and
DragonFly's lockmgr panics on releasing an unheld lock:
`panic("lockmgr: LK_RELEASE: no lock held")` (`sys/kern/kern_lock.c:761-768`).
So the error path converts a recoverable ENOMEM into a **guaranteed kernel
panic** during device attach (boot or kldload under memory pressure).

## Bug 2 — CCB leak on the other error path

If `mpt_register_handler` fails (line 292–297), the `csa` CCB allocated at
line 288 is never freed — `cleanup` only calls `mpt_raid_detach()`, which
allocates and frees **its own** CCB (`mpt_raid.c:333, 349`). One
`xpt_alloc_ccb()` leaks per failed attach.

## Verification status

**untested — hardware-gated** (no MPT HBA on the guest, see `env.txt`; also
requires kthread_create failure). Source-certain: the lock-state arithmetic
is two lines apart and `kern_lock.c:768` makes the panic deterministic.

## Fix

`fix.diff`: return directly on spawn failure (nothing to unwind); free `csa`
before calling `mpt_raid_detach` on the handler-registration failure.
