git: e9f9e3f4086f - stable/13 - nfsd: Continue adding macros so nfsd can run in a vnet prison

From: Rick Macklem <rmacklem_at_FreeBSD.org>
Date: Tue, 16 May 2023 14:30:35 UTC
The branch stable/13 has been updated by rmacklem:

URL: https://cgit.FreeBSD.org/src/commit/?id=e9f9e3f4086fe4ed15cffa1cceee454bd2995230

commit e9f9e3f4086fe4ed15cffa1cceee454bd2995230
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2023-02-14 21:33:35 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2023-05-16 14:29:25 +0000

    nfsd: Continue adding macros so nfsd can run in a vnet prison
    
    Commit 7344856e3a6d added a lot of macros that will front end
    vnet macros so that nfsd(8) can run in vnet prison.
    This patch adds some more, to allow the nfsuserd(8) daemon to
    run in vnet prison, once the macros map to vnet ones.
    This is the last commit for NFSD_VNET_xxx macros, but there are
    still some for KRPC_VNET_xxx and KGSS_VNET_xx to allow the
    rpc.tlsservd(8) and gssd(8) daemons to run in a vnet prison.
    
    (cherry picked from commit f0db2b6022dfa15f375f5fcdd278b9df21cb88f5)
---
 sys/fs/nfs/nfs_commonport.c |  14 ++-
 sys/fs/nfs/nfs_commonsubs.c | 289 ++++++++++++++++++++++++--------------------
 2 files changed, 169 insertions(+), 134 deletions(-)

diff --git a/sys/fs/nfs/nfs_commonport.c b/sys/fs/nfs/nfs_commonport.c
index def18522104d..7fdcdf967fff 100644
--- a/sys/fs/nfs/nfs_commonport.c
+++ b/sys/fs/nfs/nfs_commonport.c
@@ -56,8 +56,6 @@ __FBSDID("$FreeBSD$");
 #include <vm/uma.h>
 
 extern int nfscl_ticks;
-extern nfsuserd_state nfsrv_nfsuserd;
-extern struct nfssockreq nfsrv_nfsuserdsock;
 extern void (*nfsd_call_recall)(struct vnode *, int, struct ucred *,
     struct thread *);
 extern int nfsrv_useacl;
@@ -77,6 +75,9 @@ uint32_t nfs_srvmaxio = NFS_SRVMAXIO;
 
 NFSD_VNET_DEFINE(struct nfsstatsv1 *, nfsstatsv1_p);
 
+NFSD_VNET_DECLARE(struct nfssockreq, nfsrv_nfsuserdsock);
+NFSD_VNET_DECLARE(nfsuserd_state, nfsrv_nfsuserd);
+
 int nfs_pnfsio(task_fn_t *, void *);
 
 static int nfs_realign_test;
@@ -876,6 +877,7 @@ nfs_clean(struct prison *pr)
 {
 
 	NFSD_CURVNET_SET(pr->pr_vnet);
+	mtx_destroy(&NFSD_VNET(nfsrv_nfsuserdsock).nr_mtx);
 	if (pr != &prison0)
 		free(NFSD_VNET(nfsstatsv1_p), M_TEMP);
 	/* Clean out the name<-->id cache. */
@@ -895,6 +897,8 @@ nfs_vnetinit(const void *unused __unused)
 	else
 		NFSD_VNET(nfsstatsv1_p) = malloc(sizeof(struct nfsstatsv1),
 		    M_TEMP, M_WAITOK | M_ZERO);
+	mtx_init(&NFSD_VNET(nfsrv_nfsuserdsock).nr_mtx, "nfsuserd",
+	    NULL, MTX_DEF);
 }
 SYSINIT(nfs_vnetinit, SI_SUB_VNET_DONE, SI_ORDER_ANY,
     nfs_vnetinit, NULL);
@@ -919,8 +923,6 @@ nfscommon_modevent(module_t mod, int type, void *data)
 		mtx_init(&nfs_sockl_mutex, "nfs_sockl_mutex", NULL, MTX_DEF);
 		mtx_init(&nfs_slock_mutex, "nfs_slock_mutex", NULL, MTX_DEF);
 		mtx_init(&nfs_req_mutex, "nfs_req_mutex", NULL, MTX_DEF);
-		mtx_init(&nfsrv_nfsuserdsock.nr_mtx, "nfsuserd", NULL,
-		    MTX_DEF);
 		mtx_init(&nfsrv_dslock_mtx, "nfs4ds", NULL, MTX_DEF);
 		TAILQ_INIT(&nfsrv_devidhead);
 		newnfs_init();
@@ -929,7 +931,8 @@ nfscommon_modevent(module_t mod, int type, void *data)
 		break;
 
 	case MOD_UNLOAD:
-		if (newnfs_numnfsd != 0 || nfsrv_nfsuserd != NOTRUNNING ||
+		if (newnfs_numnfsd != 0 ||
+		    NFSD_VNET(nfsrv_nfsuserd) != NOTRUNNING ||
 		    nfs_numnfscbd != 0) {
 			error = EBUSY;
 			break;
@@ -945,7 +948,6 @@ nfscommon_modevent(module_t mod, int type, void *data)
 		mtx_destroy(&nfs_sockl_mutex);
 		mtx_destroy(&nfs_slock_mutex);
 		mtx_destroy(&nfs_req_mutex);
-		mtx_destroy(&nfsrv_nfsuserdsock.nr_mtx);
 		mtx_destroy(&nfsrv_dslock_mtx);
 		loaded = 0;
 		break;
diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c
index fe961d17453f..00cc8c68e9bf 100644
--- a/sys/fs/nfs/nfs_commonsubs.c
+++ b/sys/fs/nfs/nfs_commonsubs.c
@@ -66,17 +66,10 @@ enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
 struct timeval nfsboottime;	/* Copy boottime once, so it never changes */
 int nfscl_ticks;
 int nfsrv_useacl = 1;
-struct nfssockreq nfsrv_nfsuserdsock;
-nfsuserd_state nfsrv_nfsuserd = NOTRUNNING;
-static int nfsrv_userdupcalls = 0;
 struct nfsreqhead nfsd_reqq;
-uid_t nfsrv_defaultuid = UID_NOBODY;
-gid_t nfsrv_defaultgid = GID_NOGROUP;
 int nfsrv_lease = NFSRV_LEASE;
 int ncl_mbuf_mlen = MLEN;
-int nfsd_enable_stringtouid = 0;
 int nfsrv_doflexfile = 0;
-static int nfs_enable_uidtostring = 0;
 NFSNAMEIDMUTEX;
 NFSSOCKMUTEX;
 extern int nfsrv_lughashsize;
@@ -87,9 +80,20 @@ extern struct nfsdevicehead nfsrv_devidhead;
 extern struct nfsstatsv1 nfsstatsv1;
 extern uint32_t nfs_srvmaxio;
 
+NFSD_VNET_DEFINE(int, nfsd_enable_stringtouid) = 0;
+NFSD_VNET_DEFINE(struct nfssockreq, nfsrv_nfsuserdsock);
+NFSD_VNET_DEFINE(nfsuserd_state, nfsrv_nfsuserd) = NOTRUNNING;
+NFSD_VNET_DEFINE(uid_t, nfsrv_defaultuid) = UID_NOBODY;
+NFSD_VNET_DEFINE(gid_t, nfsrv_defaultgid) = GID_NOGROUP;
+
+NFSD_VNET_DEFINE_STATIC(int, nfsrv_userdupcalls) = 0;
+
 SYSCTL_DECL(_vfs_nfs);
-SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW,
-    &nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names");
+
+NFSD_VNET_DEFINE_STATIC(int, nfs_enable_uidtostring) = 0;
+SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring,
+    CTLFLAG_NFSD_VNET | CTLFLAG_RW, &NFSD_VNET_NAME(nfs_enable_uidtostring), 0,
+    "Make nfs always send numeric owner_names");
 
 int nfsrv_maxpnfsmirror = 1;
 SYSCTL_INT(_vfs_nfs, OID_AUTO, pnfsmirror, CTLFLAG_RD,
@@ -192,18 +196,19 @@ struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = {
 };
 
 static int ncl_mbuf_mhlen = MHLEN;
-static int nfsrv_usercnt = 0;
-static int nfsrv_dnsnamelen;
-static u_char *nfsrv_dnsname = NULL;
-static int nfsrv_usermax = 999999999;
 struct nfsrv_lughash {
 	struct mtx		mtx;
 	struct nfsuserhashhead	lughead;
 };
-static struct nfsrv_lughash	*nfsuserhash;
-static struct nfsrv_lughash	*nfsusernamehash;
-static struct nfsrv_lughash	*nfsgrouphash;
-static struct nfsrv_lughash	*nfsgroupnamehash;
+
+NFSD_VNET_DEFINE_STATIC(int, nfsrv_usercnt) = 0;
+NFSD_VNET_DEFINE_STATIC(int, nfsrv_dnsnamelen) = 0;
+NFSD_VNET_DEFINE_STATIC(int, nfsrv_usermax) = 999999999;
+NFSD_VNET_DEFINE_STATIC(struct nfsrv_lughash *, nfsuserhash) = NULL;
+NFSD_VNET_DEFINE_STATIC(struct nfsrv_lughash *, nfsusernamehash) = NULL;
+NFSD_VNET_DEFINE_STATIC(struct nfsrv_lughash *, nfsgrouphash) = NULL;
+NFSD_VNET_DEFINE_STATIC(struct nfsrv_lughash *, nfsgroupnamehash) = NULL;
+NFSD_VNET_DEFINE_STATIC(u_char *, nfsrv_dnsname) = NULL;
 
 /*
  * This static array indicates whether or not the RPC generates a large
@@ -1247,6 +1252,7 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
 #endif
 
 	CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
+	NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
 	if (compare) {
 		retnotsup = 0;
 		error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
@@ -1872,7 +1878,8 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
 			    }
 			} else if (nap != NULL) {
 				if (nfsv4_strtouid(nd, cp, j, &uid))
-					nap->na_uid = nfsrv_defaultuid;
+					nap->na_uid =
+					    NFSD_VNET(nfsrv_defaultuid);
 				else
 					nap->na_uid = uid;
 			}
@@ -1905,7 +1912,8 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
 			    }
 			} else if (nap != NULL) {
 				if (nfsv4_strtogid(nd, cp, j, &gid))
-					nap->na_gid = nfsrv_defaultgid;
+					nap->na_gid =
+					    NFSD_VNET(nfsrv_defaultgid);
 				else
 					nap->na_gid = gid;
 			}
@@ -2268,6 +2276,7 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
 			error = nfsm_advance(nd, attrsize - attrsum, -1);
 	}
 nfsmout:
+	NFSD_CURVNET_RESTORE();
 	NFSEXITCODE2(error, nd);
 	return (error);
 }
@@ -3146,14 +3155,16 @@ nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp)
 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
 	struct nfsrv_lughash *hp;
 
+	NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
 	cnt = 0;
 tryagain:
-	if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
+	if (NFSD_VNET(nfsrv_dnsnamelen) > 0 &&
+	    !NFSD_VNET(nfs_enable_uidtostring)) {
 		/*
 		 * Always map nfsrv_defaultuid to "nobody".
 		 */
-		if (uid == nfsrv_defaultuid) {
-			i = nfsrv_dnsnamelen + 7;
+		if (uid == NFSD_VNET(nfsrv_defaultuid)) {
+			i = NFSD_VNET(nfsrv_dnsnamelen) + 7;
 			if (i > len) {
 				if (len > NFSV4_SMALLSTR)
 					free(cp, M_NFSSTRING);
@@ -3165,7 +3176,9 @@ tryagain:
 			*retlenp = i;
 			NFSBCOPY("nobody@", cp, 7);
 			cp += 7;
-			NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
+			NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
+			    NFSD_VNET(nfsrv_dnsnamelen));
+			NFSD_CURVNET_RESTORE();
 			return;
 		}
 		hasampersand = 0;
@@ -3189,7 +3202,7 @@ tryagain:
 					i = usrp->lug_namelen;
 				else
 					i = usrp->lug_namelen +
-					    nfsrv_dnsnamelen + 1;
+					    NFSD_VNET(nfsrv_dnsnamelen) + 1;
 				if (i > len) {
 					mtx_unlock(&hp->mtx);
 					if (len > NFSV4_SMALLSTR)
@@ -3204,12 +3217,14 @@ tryagain:
 				if (!hasampersand) {
 					cp += usrp->lug_namelen;
 					*cp++ = '@';
-					NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
+					NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
+					    NFSD_VNET(nfsrv_dnsnamelen));
 				}
 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
 				    lug_numhash);
 				mtx_unlock(&hp->mtx);
+				NFSD_CURVNET_RESTORE();
 				return;
 			}
 		}
@@ -3237,6 +3252,7 @@ tryagain:
 		*cp-- = '0' + (tmp % 10);
 		tmp /= 10;
 	}
+	NFSD_CURVNET_RESTORE();
 	return;
 }
 
@@ -3257,7 +3273,7 @@ nfsrv_getgrpscred(struct ucred *oldcred)
 	cnt = 0;
 	uid = oldcred->cr_uid;
 tryagain:
-	if (nfsrv_dnsnamelen > 0) {
+	if (NFSD_VNET(nfsrv_dnsnamelen) > 0) {
 		hp = NFSUSERHASH(uid);
 		mtx_lock(&hp->mtx);
 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
@@ -3304,6 +3320,7 @@ nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
 	uid_t tuid;
 	struct nfsrv_lughash *hp, *hp2;
 
+	NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
 	if (len == 0) {
 		error = NFSERR_BADOWNER;
 		goto out;
@@ -3315,7 +3332,7 @@ nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
 		/* A numeric string. */
 		if ((nd->nd_flag & ND_KERBV) == 0 &&
 		    ((nd->nd_flag & ND_NFSCL) != 0 ||
-		      nfsd_enable_stringtouid != 0))
+		      NFSD_VNET(nfsd_enable_stringtouid) != 0))
 			*uidp = tuid;
 		else
 			error = NFSERR_BADOWNER;
@@ -3332,7 +3349,7 @@ nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
 
 	cnt = 0;
 tryagain:
-	if (nfsrv_dnsnamelen > 0) {
+	if (NFSD_VNET(nfsrv_dnsnamelen) > 0) {
 		/*
 		 * If an '@' is found and the domain name matches, search for
 		 * the name with dns stripped off.
@@ -3340,9 +3357,10 @@ tryagain:
 		 * all upper case will not.
 		 */
 		if (cnt == 0 && i < len && i > 0 &&
-		    (len - 1 - i) == nfsrv_dnsnamelen &&
-		    !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
-			len -= (nfsrv_dnsnamelen + 1);
+		    (len - 1 - i) == NFSD_VNET(nfsrv_dnsnamelen) &&
+		    !nfsrv_cmpmixedcase(cp,
+		     NFSD_VNET(nfsrv_dnsname), NFSD_VNET(nfsrv_dnsnamelen))) {
+			len -= (NFSD_VNET(nfsrv_dnsnamelen) + 1);
 			*(cp - 1) = '\0';
 		}
 
@@ -3350,7 +3368,7 @@ tryagain:
 		 * Check for the special case of "nobody".
 		 */
 		if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
-			*uidp = nfsrv_defaultuid;
+			*uidp = NFSD_VNET(nfsrv_defaultuid);
 			error = 0;
 			goto out;
 		}
@@ -3384,6 +3402,7 @@ tryagain:
 	error = NFSERR_BADOWNER;
 
 out:
+	NFSD_CURVNET_RESTORE();
 	NFSEXITCODE(error);
 	return (error);
 }
@@ -3405,14 +3424,16 @@ nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp)
 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
 	struct nfsrv_lughash *hp;
 
+	NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
 	cnt = 0;
 tryagain:
-	if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
+	if (NFSD_VNET(nfsrv_dnsnamelen) > 0 &&
+	    !NFSD_VNET(nfs_enable_uidtostring)) {
 		/*
 		 * Always map nfsrv_defaultgid to "nogroup".
 		 */
-		if (gid == nfsrv_defaultgid) {
-			i = nfsrv_dnsnamelen + 8;
+		if (gid == NFSD_VNET(nfsrv_defaultgid)) {
+			i = NFSD_VNET(nfsrv_dnsnamelen) + 8;
 			if (i > len) {
 				if (len > NFSV4_SMALLSTR)
 					free(cp, M_NFSSTRING);
@@ -3424,7 +3445,9 @@ tryagain:
 			*retlenp = i;
 			NFSBCOPY("nogroup@", cp, 8);
 			cp += 8;
-			NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
+			NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
+			    NFSD_VNET(nfsrv_dnsnamelen));
+			NFSD_CURVNET_RESTORE();
 			return;
 		}
 		hasampersand = 0;
@@ -3448,7 +3471,7 @@ tryagain:
 					i = usrp->lug_namelen;
 				else
 					i = usrp->lug_namelen +
-					    nfsrv_dnsnamelen + 1;
+					    NFSD_VNET(nfsrv_dnsnamelen) + 1;
 				if (i > len) {
 					mtx_unlock(&hp->mtx);
 					if (len > NFSV4_SMALLSTR)
@@ -3463,12 +3486,14 @@ tryagain:
 				if (!hasampersand) {
 					cp += usrp->lug_namelen;
 					*cp++ = '@';
-					NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
+					NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
+					    NFSD_VNET(nfsrv_dnsnamelen));
 				}
 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
 				    lug_numhash);
 				mtx_unlock(&hp->mtx);
+				NFSD_CURVNET_RESTORE();
 				return;
 			}
 		}
@@ -3496,6 +3521,7 @@ tryagain:
 		*cp-- = '0' + (tmp % 10);
 		tmp /= 10;
 	}
+	NFSD_CURVNET_RESTORE();
 	return;
 }
 
@@ -3518,6 +3544,7 @@ nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
 	gid_t tgid;
 	struct nfsrv_lughash *hp, *hp2;
 
+	NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
 	if (len == 0) {
 		error =  NFSERR_BADOWNER;
 		goto out;
@@ -3529,7 +3556,7 @@ nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
 		/* A numeric string. */
 		if ((nd->nd_flag & ND_KERBV) == 0 &&
 		    ((nd->nd_flag & ND_NFSCL) != 0 ||
-		      nfsd_enable_stringtouid != 0))
+		      NFSD_VNET(nfsd_enable_stringtouid) != 0))
 			*gidp = tgid;
 		else
 			error = NFSERR_BADOWNER;
@@ -3546,15 +3573,16 @@ nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
 
 	cnt = 0;
 tryagain:
-	if (nfsrv_dnsnamelen > 0) {
+	if (NFSD_VNET(nfsrv_dnsnamelen) > 0) {
 		/*
 		 * If an '@' is found and the dns name matches, search for the
 		 * name with the dns stripped off.
 		 */
 		if (cnt == 0 && i < len && i > 0 &&
-		    (len - 1 - i) == nfsrv_dnsnamelen &&
-		    !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
-			len -= (nfsrv_dnsnamelen + 1);
+		    (len - 1 - i) == NFSD_VNET(nfsrv_dnsnamelen) &&
+		    !nfsrv_cmpmixedcase(cp,
+		     NFSD_VNET(nfsrv_dnsname), NFSD_VNET(nfsrv_dnsnamelen))) {
+			len -= (NFSD_VNET(nfsrv_dnsnamelen) + 1);
 			*(cp - 1) = '\0';
 		}
 
@@ -3562,7 +3590,7 @@ tryagain:
 		 * Check for the special case of "nogroup".
 		 */
 		if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
-			*gidp = nfsrv_defaultgid;
+			*gidp = NFSD_VNET(nfsrv_defaultgid);
 			error = 0;
 			goto out;
 		}
@@ -3596,6 +3624,7 @@ tryagain:
 	error = NFSERR_BADOWNER;
 
 out:
+	NFSD_CURVNET_RESTORE();
 	NFSEXITCODE(error);
 	return (error);
 }
@@ -3646,12 +3675,12 @@ nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
 	int error;
 
 	NFSLOCKNAMEID();
-	if (nfsrv_nfsuserd != NOTRUNNING) {
+	if (NFSD_VNET(nfsrv_nfsuserd) != NOTRUNNING) {
 		NFSUNLOCKNAMEID();
 		error = EPERM;
 		goto out;
 	}
-	nfsrv_nfsuserd = STARTSTOP;
+	NFSD_VNET(nfsrv_nfsuserd) = STARTSTOP;
 	/*
 	 * Set up the socket record and connect.
 	 * Set nr_client NULL before unlocking, just to ensure that no other
@@ -3659,7 +3688,7 @@ nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
 	 * occur if the use of the nameid lock to protect nfsrv_nfsuserd is
 	 * broken.
 	 */
-	rp = &nfsrv_nfsuserdsock;
+	rp = &NFSD_VNET(nfsrv_nfsuserdsock);
 	rp->nr_client = NULL;
 	NFSUNLOCKNAMEID();
 	rp->nr_sotype = SOCK_DGRAM;
@@ -3700,12 +3729,12 @@ nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
 		    &rp->nr_client);
 	if (error == 0) {
 		NFSLOCKNAMEID();
-		nfsrv_nfsuserd = RUNNING;
+		NFSD_VNET(nfsrv_nfsuserd) = RUNNING;
 		NFSUNLOCKNAMEID();
 	} else {
 		free(rp->nr_nam, M_SONAME);
 		NFSLOCKNAMEID();
-		nfsrv_nfsuserd = NOTRUNNING;
+		NFSD_VNET(nfsrv_nfsuserd) = NOTRUNNING;
 		NFSUNLOCKNAMEID();
 	}
 out:
@@ -3721,20 +3750,20 @@ nfsrv_nfsuserddelport(void)
 {
 
 	NFSLOCKNAMEID();
-	if (nfsrv_nfsuserd != RUNNING) {
+	if (NFSD_VNET(nfsrv_nfsuserd) != RUNNING) {
 		NFSUNLOCKNAMEID();
 		return;
 	}
-	nfsrv_nfsuserd = STARTSTOP;
+	NFSD_VNET(nfsrv_nfsuserd) = STARTSTOP;
 	/* Wait for all upcalls to complete. */
-	while (nfsrv_userdupcalls > 0)
-		msleep(&nfsrv_userdupcalls, NFSNAMEIDMUTEXPTR, PVFS,
+	while (NFSD_VNET(nfsrv_userdupcalls) > 0)
+		msleep(&NFSD_VNET(nfsrv_userdupcalls), NFSNAMEIDMUTEXPTR, PVFS,
 		    "nfsupcalls", 0);
 	NFSUNLOCKNAMEID();
-	newnfs_disconnect(NULL, &nfsrv_nfsuserdsock);
-	free(nfsrv_nfsuserdsock.nr_nam, M_SONAME);
+	newnfs_disconnect(NULL, &NFSD_VNET(nfsrv_nfsuserdsock));
+	free(NFSD_VNET(nfsrv_nfsuserdsock).nr_nam, M_SONAME);
 	NFSLOCKNAMEID();
-	nfsrv_nfsuserd = NOTRUNNING;
+	NFSD_VNET(nfsrv_nfsuserd) = NOTRUNNING;
 	NFSUNLOCKNAMEID();
 }
 
@@ -3754,7 +3783,7 @@ nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
 	int error;
 
 	NFSLOCKNAMEID();
-	if (nfsrv_nfsuserd != RUNNING) {
+	if (NFSD_VNET(nfsrv_nfsuserd) != RUNNING) {
 		NFSUNLOCKNAMEID();
 		error = EPERM;
 		goto out;
@@ -3763,9 +3792,9 @@ nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
 	 * Maintain a count of upcalls in progress, so that nfsrv_X()
 	 * can wait until no upcalls are in progress.
 	 */
-	nfsrv_userdupcalls++;
+	NFSD_VNET(nfsrv_userdupcalls)++;
 	NFSUNLOCKNAMEID();
-	KASSERT(nfsrv_userdupcalls > 0,
+	KASSERT(NFSD_VNET(nfsrv_userdupcalls) > 0,
 	    ("nfsrv_getuser: non-positive upcalls"));
 	nd = &nfsd;
 	cred = newnfs_getcred();
@@ -3783,11 +3812,13 @@ nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
 		len = strlen(name);
 		(void) nfsm_strtom(nd, name, len);
 	}
-	error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
-		cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
+	error = newnfs_request(nd, NULL, NULL, &NFSD_VNET(nfsrv_nfsuserdsock),
+	    NULL, NULL, cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0,
+	    NULL, NULL);
 	NFSLOCKNAMEID();
-	if (--nfsrv_userdupcalls == 0 && nfsrv_nfsuserd == STARTSTOP)
-		wakeup(&nfsrv_userdupcalls);
+	if (--NFSD_VNET(nfsrv_userdupcalls) == 0 &&
+	    NFSD_VNET(nfsrv_nfsuserd) == STARTSTOP)
+		wakeup(&NFSD_VNET(nfsrv_userdupcalls));
 	NFSUNLOCKNAMEID();
 	NFSFREECRED(cred);
 	if (!error) {
@@ -3827,7 +3858,8 @@ nfssvc_idname(struct nfsd_idargs *nidp)
 			free(cp, M_NFSSTRING);
 			goto out;
 		}
-		if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
+		if (atomic_cmpset_acq_int(&NFSD_VNET(nfsrv_dnsnamelen), 0, 0) ==
+		    0) {
 			/*
 			 * Free up all the old stuff and reinitialize hash
 			 * lists.  All mutexes for both lists must be locked,
@@ -3835,80 +3867,81 @@ nfssvc_idname(struct nfsd_idargs *nidp)
 			 * ones, to avoid a LOR.
 			 */
 			for (i = 0; i < nfsrv_lughashsize; i++)
-				mtx_lock(&nfsusernamehash[i].mtx);
+				mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx);
 			for (i = 0; i < nfsrv_lughashsize; i++)
-				mtx_lock(&nfsuserhash[i].mtx);
+				mtx_lock(&NFSD_VNET(nfsuserhash)[i].mtx);
 			for (i = 0; i < nfsrv_lughashsize; i++)
 				TAILQ_FOREACH_SAFE(usrp,
-				    &nfsuserhash[i].lughead, lug_numhash, nusrp)
+				    &NFSD_VNET(nfsuserhash)[i].lughead, lug_numhash, nusrp)
 					nfsrv_removeuser(usrp, 1);
 			for (i = 0; i < nfsrv_lughashsize; i++)
-				mtx_unlock(&nfsuserhash[i].mtx);
+				mtx_unlock(&NFSD_VNET(nfsuserhash)[i].mtx);
 			for (i = 0; i < nfsrv_lughashsize; i++)
-				mtx_unlock(&nfsusernamehash[i].mtx);
+				mtx_unlock(&NFSD_VNET(nfsusernamehash)[i].mtx);
 			for (i = 0; i < nfsrv_lughashsize; i++)
-				mtx_lock(&nfsgroupnamehash[i].mtx);
+				mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
 			for (i = 0; i < nfsrv_lughashsize; i++)
-				mtx_lock(&nfsgrouphash[i].mtx);
+				mtx_lock(&NFSD_VNET(nfsgrouphash)[i].mtx);
 			for (i = 0; i < nfsrv_lughashsize; i++)
 				TAILQ_FOREACH_SAFE(usrp,
-				    &nfsgrouphash[i].lughead, lug_numhash,
+				    &NFSD_VNET(nfsgrouphash)[i].lughead, lug_numhash,
 				    nusrp)
 					nfsrv_removeuser(usrp, 0);
 			for (i = 0; i < nfsrv_lughashsize; i++)
-				mtx_unlock(&nfsgrouphash[i].mtx);
+				mtx_unlock(&NFSD_VNET(nfsgrouphash)[i].mtx);
 			for (i = 0; i < nfsrv_lughashsize; i++)
-				mtx_unlock(&nfsgroupnamehash[i].mtx);
-			free(nfsrv_dnsname, M_NFSSTRING);
-			nfsrv_dnsname = NULL;
+				mtx_unlock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
+			free(NFSD_VNET(nfsrv_dnsname), M_NFSSTRING);
+			NFSD_VNET(nfsrv_dnsname) = NULL;
 		}
-		if (nfsuserhash == NULL) {
+		if (NFSD_VNET(nfsuserhash) == NULL) {
 			/* Allocate the hash tables. */
-			nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
+			NFSD_VNET(nfsuserhash) = malloc(sizeof(struct nfsrv_lughash) *
 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
 			    M_ZERO);
 			for (i = 0; i < nfsrv_lughashsize; i++)
-				mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
+				mtx_init(&NFSD_VNET(nfsuserhash)[i].mtx, "nfsuidhash",
 				    NULL, MTX_DEF | MTX_DUPOK);
-			nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
+			NFSD_VNET(nfsusernamehash) = malloc(sizeof(struct nfsrv_lughash) *
 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
 			    M_ZERO);
 			for (i = 0; i < nfsrv_lughashsize; i++)
-				mtx_init(&nfsusernamehash[i].mtx,
+				mtx_init(&NFSD_VNET(nfsusernamehash)[i].mtx,
 				    "nfsusrhash", NULL, MTX_DEF |
 				    MTX_DUPOK);
-			nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
+			NFSD_VNET(nfsgrouphash) = malloc(sizeof(struct nfsrv_lughash) *
 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
 			    M_ZERO);
 			for (i = 0; i < nfsrv_lughashsize; i++)
-				mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
+				mtx_init(&NFSD_VNET(nfsgrouphash)[i].mtx, "nfsgidhash",
 				    NULL, MTX_DEF | MTX_DUPOK);
-			nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
+			NFSD_VNET(nfsgroupnamehash) = malloc(sizeof(struct nfsrv_lughash) *
 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
 			    M_ZERO);
 			for (i = 0; i < nfsrv_lughashsize; i++)
-			    mtx_init(&nfsgroupnamehash[i].mtx,
+			    mtx_init(&NFSD_VNET(nfsgroupnamehash)[i].mtx,
 			    "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
 		}
 		/* (Re)initialize the list heads. */
 		for (i = 0; i < nfsrv_lughashsize; i++)
-			TAILQ_INIT(&nfsuserhash[i].lughead);
+			TAILQ_INIT(&NFSD_VNET(nfsuserhash)[i].lughead);
 		for (i = 0; i < nfsrv_lughashsize; i++)
-			TAILQ_INIT(&nfsusernamehash[i].lughead);
+			TAILQ_INIT(&NFSD_VNET(nfsusernamehash)[i].lughead);
 		for (i = 0; i < nfsrv_lughashsize; i++)
-			TAILQ_INIT(&nfsgrouphash[i].lughead);
+			TAILQ_INIT(&NFSD_VNET(nfsgrouphash)[i].lughead);
 		for (i = 0; i < nfsrv_lughashsize; i++)
-			TAILQ_INIT(&nfsgroupnamehash[i].lughead);
+			TAILQ_INIT(&NFSD_VNET(nfsgroupnamehash)[i].lughead);
 
 		/*
 		 * Put name in "DNS" string.
 		 */
-		nfsrv_dnsname = cp;
-		nfsrv_defaultuid = nidp->nid_uid;
-		nfsrv_defaultgid = nidp->nid_gid;
-		nfsrv_usercnt = 0;
-		nfsrv_usermax = nidp->nid_usermax;
-		atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
+		NFSD_VNET(nfsrv_dnsname) = cp;
+		NFSD_VNET(nfsrv_defaultuid) = nidp->nid_uid;
+		NFSD_VNET(nfsrv_defaultgid) = nidp->nid_gid;
+		NFSD_VNET(nfsrv_usercnt) = 0;
+		NFSD_VNET(nfsrv_usermax) = nidp->nid_usermax;
+		atomic_store_rel_int(&NFSD_VNET(nfsrv_dnsnamelen),
+		    nidp->nid_namelen);
 		goto out;
 	}
 
@@ -3935,7 +3968,7 @@ nfssvc_idname(struct nfsd_idargs *nidp)
 			cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
 			crsetgroups(cr, nidp->nid_ngroup, grps);
 			cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
-			cr->cr_prison = &prison0;
+			cr->cr_prison = curthread->td_ucred->cr_prison;
 			prison_hold(cr->cr_prison);
 #ifdef MAC
 			mac_cred_associate_nfsd(cr);
@@ -3967,7 +4000,7 @@ nfssvc_idname(struct nfsd_idargs *nidp)
 	if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
 		/* Must lock all username hash lists first, to avoid a LOR. */
 		for (i = 0; i < nfsrv_lughashsize; i++)
-			mtx_lock(&nfsusernamehash[i].mtx);
+			mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx);
 		username_locked = 1;
 		hp_idnum = NFSUSERHASH(nidp->nid_uid);
 		mtx_lock(&hp_idnum->mtx);
@@ -3996,7 +4029,7 @@ nfssvc_idname(struct nfsd_idargs *nidp)
 	} else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
 		/* Must lock all groupname hash lists first, to avoid a LOR. */
 		for (i = 0; i < nfsrv_lughashsize; i++)
-			mtx_lock(&nfsgroupnamehash[i].mtx);
+			mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
 		groupname_locked = 1;
 		hp_idnum = NFSGROUPHASH(nidp->nid_gid);
 		mtx_lock(&hp_idnum->mtx);
@@ -4039,7 +4072,7 @@ nfssvc_idname(struct nfsd_idargs *nidp)
 		thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
 		mtx_assert(&thp->mtx, MA_OWNED);
 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
-		atomic_add_int(&nfsrv_usercnt, 1);
+		atomic_add_int(&NFSD_VNET(nfsrv_usercnt), 1);
 	} else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
 		newusrp->lug_gid = nidp->nid_gid;
 		thp = NFSGROUPHASH(newusrp->lug_gid);
@@ -4048,7 +4081,7 @@ nfssvc_idname(struct nfsd_idargs *nidp)
 		thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
 		mtx_assert(&thp->mtx, MA_OWNED);
 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
-		atomic_add_int(&nfsrv_usercnt, 1);
+		atomic_add_int(&NFSD_VNET(nfsrv_usercnt), 1);
 	} else {
 		if (newusrp->lug_cred != NULL)
 			crfree(newusrp->lug_cred);
@@ -4077,17 +4110,17 @@ nfssvc_idname(struct nfsd_idargs *nidp)
 		    NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
 			if (username_locked == 0) {
 				for (i = 0; i < nfsrv_lughashsize; i++)
-					mtx_lock(&nfsusernamehash[i].mtx);
+					mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx);
 				username_locked = 1;
 			}
 			KASSERT(user_locked == 0,
 			    ("nfssvc_idname: user_locked"));
 			for (i = 0; i < nfsrv_lughashsize; i++)
-				mtx_lock(&nfsuserhash[i].mtx);
+				mtx_lock(&NFSD_VNET(nfsuserhash)[i].mtx);
 			user_locked = 1;
 			for (i = 0; i < nfsrv_lughashsize; i++) {
 				TAILQ_FOREACH_SAFE(usrp,
-				    &nfsuserhash[i].lughead, lug_numhash,
+				    &NFSD_VNET(nfsuserhash)[i].lughead, lug_numhash,
 				    nusrp)
 					if (usrp->lug_expiry < NFSD_MONOSEC)
 						nfsrv_removeuser(usrp, 1);
@@ -4098,26 +4131,26 @@ nfssvc_idname(struct nfsd_idargs *nidp)
 				 * algorithm.  This code deletes the least
 				 * recently used entry on each hash list.
 				 */
-				if (nfsrv_usercnt <= nfsrv_usermax)
+				if (NFSD_VNET(nfsrv_usercnt) <= NFSD_VNET(nfsrv_usermax))
 					break;
-				usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
+				usrp = TAILQ_FIRST(&NFSD_VNET(nfsuserhash)[i].lughead);
 				if (usrp != NULL)
 					nfsrv_removeuser(usrp, 1);
 			}
 		} else {
 			if (groupname_locked == 0) {
 				for (i = 0; i < nfsrv_lughashsize; i++)
-					mtx_lock(&nfsgroupnamehash[i].mtx);
+					mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
 				groupname_locked = 1;
 			}
 			KASSERT(group_locked == 0,
 			    ("nfssvc_idname: group_locked"));
 			for (i = 0; i < nfsrv_lughashsize; i++)
-				mtx_lock(&nfsgrouphash[i].mtx);
+				mtx_lock(&NFSD_VNET(nfsgrouphash)[i].mtx);
 			group_locked = 1;
 			for (i = 0; i < nfsrv_lughashsize; i++) {
 				TAILQ_FOREACH_SAFE(usrp,
-				    &nfsgrouphash[i].lughead, lug_numhash,
+				    &NFSD_VNET(nfsgrouphash)[i].lughead, lug_numhash,
 				    nusrp)
 					if (usrp->lug_expiry < NFSD_MONOSEC)
 						nfsrv_removeuser(usrp, 0);
@@ -4128,9 +4161,9 @@ nfssvc_idname(struct nfsd_idargs *nidp)
 				 * algorithm.  This code deletes the least
 				 * recently user entry on each hash list.
 				 */
-				if (nfsrv_usercnt <= nfsrv_usermax)
+				if (NFSD_VNET(nfsrv_usercnt) <= NFSD_VNET(nfsrv_usermax))
 					break;
-				usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
+				usrp = TAILQ_FIRST(&NFSD_VNET(nfsgrouphash)[i].lughead);
 				if (usrp != NULL)
 					nfsrv_removeuser(usrp, 0);
 			}
@@ -4146,16 +4179,16 @@ nfssvc_idname(struct nfsd_idargs *nidp)
 		mtx_unlock(&hp_name->mtx);
 	if (user_locked != 0)
 		for (i = 0; i < nfsrv_lughashsize; i++)
-			mtx_unlock(&nfsuserhash[i].mtx);
+			mtx_unlock(&NFSD_VNET(nfsuserhash)[i].mtx);
 	if (username_locked != 0)
 		for (i = 0; i < nfsrv_lughashsize; i++)
-			mtx_unlock(&nfsusernamehash[i].mtx);
+			mtx_unlock(&NFSD_VNET(nfsusernamehash)[i].mtx);
 	if (group_locked != 0)
 		for (i = 0; i < nfsrv_lughashsize; i++)
-			mtx_unlock(&nfsgrouphash[i].mtx);
+			mtx_unlock(&NFSD_VNET(nfsgrouphash)[i].mtx);
 	if (groupname_locked != 0)
 		for (i = 0; i < nfsrv_lughashsize; i++)
-			mtx_unlock(&nfsgroupnamehash[i].mtx);
+			mtx_unlock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
 out:
 	NFSEXITCODE(error);
 	return (error);
@@ -4184,7 +4217,7 @@ nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
 		mtx_assert(&hp->mtx, MA_OWNED);
 		TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
 	}
-	atomic_add_int(&nfsrv_usercnt, -1);
+	atomic_add_int(&NFSD_VNET(nfsrv_usercnt), -1);
 	if (usrp->lug_cred != NULL)
 		crfree(usrp->lug_cred);
 	free(usrp, M_NFSUSERGROUP);
@@ -4194,7 +4227,7 @@ nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
  * Free up all the allocations related to the name<-->id cache.
  * This function should only be called when the nfsuserd daemon isn't
  * running, since it doesn't do any locking.
- * This function is meant to be used when the nfscommon module is unloaded.
+ * This function is meant to be called when a vnet jail is destroyed.
  */
 void
 nfsrv_cleanusergroup(void)
@@ -4203,11 +4236,11 @@ nfsrv_cleanusergroup(void)
 	struct nfsusrgrp *nusrp, *usrp;
 	int i;
 
-	if (nfsuserhash == NULL)
+	if (NFSD_VNET(nfsuserhash) == NULL)
 		return;
 
 	for (i = 0; i < nfsrv_lughashsize; i++) {
-		hp = &nfsuserhash[i];
+		hp = &NFSD_VNET(nfsuserhash)[i];
 		TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
 			TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
 			hp2 = NFSUSERNAMEHASH(usrp->lug_name,
@@ -4217,7 +4250,7 @@ nfsrv_cleanusergroup(void)
 				crfree(usrp->lug_cred);
 			free(usrp, M_NFSUSERGROUP);
 		}
-		hp = &nfsgrouphash[i];
+		hp = &NFSD_VNET(nfsgrouphash)[i];
 		TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
 			TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
 			hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
@@ -4227,16 +4260,16 @@ nfsrv_cleanusergroup(void)
 				crfree(usrp->lug_cred);
 			free(usrp, M_NFSUSERGROUP);
 		}
-		mtx_destroy(&nfsuserhash[i].mtx);
-		mtx_destroy(&nfsusernamehash[i].mtx);
-		mtx_destroy(&nfsgroupnamehash[i].mtx);
-		mtx_destroy(&nfsgrouphash[i].mtx);
+		mtx_destroy(&NFSD_VNET(nfsuserhash)[i].mtx);
+		mtx_destroy(&NFSD_VNET(nfsusernamehash)[i].mtx);
+		mtx_destroy(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
+		mtx_destroy(&NFSD_VNET(nfsgrouphash)[i].mtx);
 	}
-	free(nfsuserhash, M_NFSUSERGROUP);
-	free(nfsusernamehash, M_NFSUSERGROUP);
-	free(nfsgrouphash, M_NFSUSERGROUP);
-	free(nfsgroupnamehash, M_NFSUSERGROUP);
-	free(nfsrv_dnsname, M_NFSSTRING);
+	free(NFSD_VNET(nfsuserhash), M_NFSUSERGROUP);
+	free(NFSD_VNET(nfsusernamehash), M_NFSUSERGROUP);
+	free(NFSD_VNET(nfsgrouphash), M_NFSUSERGROUP);
+	free(NFSD_VNET(nfsgroupnamehash), M_NFSUSERGROUP);
+	free(NFSD_VNET(nfsrv_dnsname), M_NFSSTRING);
 }
 
 /*