# DF-2994 — WebNFS public-filehandle LOOKUP: vput() on unlocked vnode → guaranteed kernel panic

## Build
```
cc -O -o /root/nfspoc nfspoc.c      # in-guest
```

## Setup (root in guest)
/etc/exports:
```
/tmp/nfsroot -maproot=root
/ -public -index=missing.html -maproot=root
```
Start rpcbind, mountd, nfsd.

## Run
```
NFSPOC_SRCPORT=831 NFSPOC_TIMEOUT=5 /root/nfspoc lookup0 /
```
(v3 LOOKUP, public filehandle encoded as fhlen=0, name "/")

## Expected
Kernel panic within milliseconds:
```
panic: lockmgr: LK_RELEASE: no lock held
 vput() at vput+0x11
 nfsrv_lookup() at nfsrv_lookup+0x35b
 sys_nfssvc() ...
```
Guest drops to DDB (`db>`); ssh dies; `vm.sh status` => down.

## Root cause
`nfsrv_lookup` sys/vfs/nfs/nfs_serv.c:
- nfs_namei() returns the target vp **LK_EXCLUSIVE locked** (cache_vget,
  nfs_subs.c:1183).
- Public-filehandle + VDIR + configured index file (nfs_pub.np_index, set by
  mountd from `index=` via vfs_setpublicfs, vfs_subr.c:2266-2293):
  line 565 `vn_unlock(vp)` before looking up the index.
- If the index lookup fails (index file absent — the common case), the vp is
  **never re-locked** and never moved to dirp (line 574-589 skipped).
- Line 599-604 or line 643 then calls `vput(vp)` on the unlocked vnode.
- vput() = vn_unlock()+vrele() (vfs_lock.c:703-707) → lockmgr LK_RELEASE on
  an unheld lock → unconditional panic (kern_lock.c:767-768).

## Preconditions
* NFS server exporting a filesystem with `-public` **and** `index=<file>`
  (WebNFS with index, RFC 2054/2055 style).
* The LOOKUP target resolves to a directory that does not contain the index
  file.
* The public filehandle is by definition pre-authenticated (that is its
  purpose), so no valid fh or credential is needed — only network reachability
  (and a reserved source port when vfs.nfs.nfs_privport=1).
