fix for DF-5831: nlookup() retry path NULL-derefs nd->nl_basench for nlookup_init_raw()/nlookup_init_root()-initialized nd's (NFS server name lookups via nfs_namei(), webnfs public handle, early-boot mountroot) -- any doretry (ncp generation change from a concurrent rename, ESTALE, destroyed parent) runs cache_copy(NULL, &nd->nl_nch) at sys/kern/vfs_nlookup.c:1380 -> Fatal trap 12 at 0x0 in the nfsd process. Fix: give init_raw/init_root a private, ref-held retry base. The caller's ncstart handle cannot be used (nfs_namei drops it immediately after init), so store a copy in a new nlookupdata field and point nl_basench at it. nlookup_done() releases it. Verified in-guest: baseline panics in nfsd within ~2 minutes of the rig; patched kernel survives the identical rig for the full 300s window twice. diff --git a/sys/sys/nlookup.h b/sys/sys/nlookup.h index 1111111..2222222 100644 --- a/sys/sys/nlookup.h +++ b/sys/sys/nlookup.h @@ -74,6 +74,7 @@ */ struct nchandle nl_nch; /* result */ struct nchandle *nl_basench; /* start-point directory */ + struct nchandle nl_basench_store; /* private base (init_raw/_root) */ struct nchandle nl_rootnch; /* root directory */ struct nchandle nl_jailnch; /* jail directory */ diff --git a/sys/kern/vfs_nlookup.c b/sys/kern/vfs_nlookup.c index 1111111..2222222 100644 --- a/sys/kern/vfs_nlookup.c +++ b/sys/kern/vfs_nlookup.c @@ -280,6 +280,9 @@ nlookup_init_raw(struct nlookupdata *nd, if (error == 0) { cache_copy(ncstart, &nd->nl_nch); + cache_copy(ncstart, &nd->nl_basench_store); + nd->nl_basench = &nd->nl_basench_store; + cache_copy(&rootnch, &nd->nl_rootnch); cache_copy(&rootnch, &nd->nl_jailnch); nd->nl_cred = crhold(cred); @@ -324,6 +327,9 @@ nlookup_init_root(struct nlookupdata *nd, if (error == 0) { cache_copy(ncstart, &nd->nl_nch); + cache_copy(ncstart, &nd->nl_basench_store); + nd->nl_basench = &nd->nl_basench_store; + cache_copy(ncroot, &nd->nl_rootnch); cache_copy(ncroot, &nd->nl_jailnch); nd->nl_cred = crhold(cred); @@ -373,6 +379,10 @@ nlookup_done(struct nlookupdata *nd) if (nd->nl_rootnch.ncp) cache_drop_and_cache(&nd->nl_rootnch, 0); if (nd->nl_jailnch.ncp) cache_drop_and_cache(&nd->nl_jailnch, 0); + if (nd->nl_basench_store.ncp) { + cache_drop_and_cache(&nd->nl_basench_store, 0); + nd->nl_basench = NULL; + } if ((nd->nl_flags & NLC_HASBUF) && nd->nl_path) { objcache_put(namei_oc, nd->nl_path); nd->nl_path = NULL;