# DF-3161 — umount -f force-close never balances fifo reader/writer counts (fip + socket pair leaked)

## Root cause
`vclean_vxlocked()` (`sys/kern/vfs_subr.c:1341-1352`) force-closes a vnode
with open descriptors by looping `VOP_CLOSE()` until `v_opencount == 0`,
but it only ever passes `FWRITE|FNONBLOCK` (when `v_writecount`) or bare
`FNONBLOCK` — **never FREAD**.  `fifo_close()`
(`sys/vfs/fifofs/fifo_vnops.c:610-614`) decrements `fi_readers` only when
FREAD is passed, so after a forced unmount the reader count can never
reach 0, the `fi_readers == 0 && fi_writers == 0` destroy condition
(fifo_vnops.c:620-622) never fires, and the `fifoinfo` plus its connected
AF_LOCAL socket pair (`socreate` x2 + `unp_connect2`, fifo_vnops.c:188-222)
leak permanently.  The later userspace `close()` goes to `dead_close()`
(sys/vfs/deadfs/dead_vnops.c:118-133), which never touches the fifo
counters.

## Reaching the force-close path
`dounmount(MNT_FORCE)` first tries to make holders exit: it SIGINTs
(retry 3) then SIGKILLs (retry 7) every process using the mount
(sys/kern/vfs_syscalls.c:929-946) and waits up to 50 retries x 0.25 s.
An open fifo that **no process owns** — e.g. an fd passed over a
unix-domain socket (SCM_RIGHTS) and never received — is pinned by the
socket buffer, invisible to the kill protocol, so the retries exhaust and
the mount is ripped with the fifo still open (console warns
`forced umount of ... - N namecache refs`), running the force-close loop.

## PoC
`umount_fifoleak_scmrights.c` (deterministic; the one that reproduces):
open a fifo O_RDWR on a tmpfs, hide the fd inside a socketpair via
SCM_RIGHTS, `umount -f`, drop the socket, count connected unix-domain
stream sockets with `netstat -f unix`.

`umount_fifoleak.sh` + `fifo_hold.c`: first attempt (process-held fd) —
does NOT leak because dounmount's SIGINT kills the holder cleanly;
kept as the control/characterization run.

## Build / run (as root on the guest)
    cc -O -Wall -o leak_scm umount_fifoleak_scmrights.c
    ./leak_scm

## Expected output (bug present)
    baseline: 4 stream sockets
    fifo-open (+2 expected): 6 stream sockets
    ...
    umount rc=0            (after ~13 s of exhausted retries; console warns)
    after umount -f + close (leak: stays +2): 6 stream sockets   <-- LEAK

## Expected output (fixed kernel)
    after umount -f + close ...: 4 stream sockets   (back to baseline)
