--- a/sys/vfs/nfs/nfs_subs.c 2026-09-05 19:46:34.336135611 +0000 +++ b/sys/vfs/nfs/nfs_subs.c 2026-09-05 19:46:38.808078445 +0000 @@ -1001,9 +1001,22 @@ * Check retry case */ if (nd->nl_flags & NLC_HASBUF) { + /* + * Retry case (nfsrv_rename "goto again"): the caller is + * re-using an nlookupdata that may still hold live state + * from the previous iteration -- an exclusively locked and + * held nl_nch, held root/jail nchandle refs, a crhold'd + * nl_cred and possibly nl_dvp/nl_open_vp. + * + * Rescue the path buffer, then tear the remaining state + * down properly. nlookup_init_raw() below unconditionally + * bzero()s nd; without this release every retry leaks the + * ncp lock, cache refs and the credential reference. + */ namebuf = nd->nl_path; nd->nl_flags &= ~NLC_HASBUF; nd->nl_path = NULL; + nlookup_done(nd); /* NLC_HASBUF clear: buffer kept */ isretry = 1; } else { namebuf = objcache_get(namei_oc, M_WAITOK); --- a/sys/vfs/nfs/nfs_serv.c 2026-09-05 19:46:34.336135611 +0000 +++ b/sys/vfs/nfs/nfs_serv.c 2026-09-05 19:46:45.843988501 +0000 @@ -2257,10 +2257,20 @@ (tond.nl_nch.ncp->nc_flag & (NCF_DESTROYED | NCF_UNRESOLVED))) { cache_put(&fnchd); cache_put(&tnchd); + /* + * The handles/dirs above are now released; reset the + * cleanup status and pointers so a failure in the second + * nfs_namei() pass cannot double-put/double-vrele them + * from the nfsmout cleanup path. + */ + fnchd_status = 0; + tnchd_status = 0; if (tdirp) vrele(tdirp); if (fdirp) vrele(fdirp); + tdirp = NULL; + fdirp = NULL; kprintf("nfs - retry rename %s to %s\n", fromnd.nl_path, tond.nl_path); goto again;