From nobody Tue Apr 7 15:53:23 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4fqrMR3f12z6YTYq for ; Tue, 07 Apr 2026 15:53:23 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4fqrMR1hLBz3vVN for ; Tue, 07 Apr 2026 15:53:23 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1775577203; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=KH3Zk00vO1wlWXkCUSPkU9LoH+P+EMaaYJQ58+4cRKs=; b=nULEqhEDlUfyb2b9h8ufagNcqfbcueXowa2In+31YaK53NZC1CBYDcNlJdJ+NkrrvyXoQA bBDv4+BXUXA4zdZ1IqY3zLApuLl6WIzpuc0WxV6pO+3L7ZIYfMHOs334pNMBjlboecOCZr ayQV+nSRa/erio+t13y6FoasKLDXJ/gm7tkHKcE7BgLpZiXPpN42WnUCy2vj4H7RK3c/6k Q37ZCmHeaipYpuHfNVmvD7QTCGqP3rT/NbadU0D4BsEFOSXXVZ1IkP7Uop8DHfaVhGTJXa UNaQLVc1ENvDYzR6gE/8zRzvhiWKeOg0jdYTZrtYxqQmwSTRTG9D4uq1IycynQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1775577203; a=rsa-sha256; cv=none; b=LY6Tn0YjnVk7BWqjrQpHLHTZUe4DZe/yvLiO3vZ7H6lu4IfKsZSxDUCfta1HHY6ZYNpLdy biWCuZAfcFOYAl0lrQg0EhavtqoCafuozU17WAEO1xgmlpnUGo/WfvyFrHvYaOD21TpSkj Osoi0HjGlYv7Y1ZCSjq8M3Pl1BvVjcF4uzO3a1oWVSspXTIbYEobfpUCTSJLhLivcMBopi 2YVV630k5KxjFzB1F/ETzk/fr7Jz8IK35+DfZc1FLMXVtbR7ULpmlN5PAGMmT6w8kesHX9 yPvGF++GdHB2/FsZiPdpCELjeFPv+4Qm5PEe0mwBx4fJ0CjgMJcUHejW6Dag7w== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1775577203; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=KH3Zk00vO1wlWXkCUSPkU9LoH+P+EMaaYJQ58+4cRKs=; b=C71yV9ufiQqijyHF7MTFsSc4+IMFYwn9n4eaFajK90m7mPZEkxbswRZBqDIUKhfU6ZJTIo dTUU+jmmJMkvIc0nwhOCPZuo6uvRbjbwnuJ/2xvoCwinPbWMCZSXlIZIWdHfGIPAjkCByg YY4VNDvzhcVpMX+9j8JmomF7+rctq2hqOz7yKCC914exlCCxMJeUw1jC77ZWWspLnzXv1z 9BzU0kzzLowRZUBVUAS6xrKumXPBqUhIt/PAbmKqyD4UmAdIzGnW4oyOagP0C/7wm3Hppw NKcOsaHzitsSTnaBNr4/vb9XE57TIW8mcZ/L24mJI2m9WgLsdvBbC0KpA+X2vw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4fqrMR1FWmzn0h for ; Tue, 07 Apr 2026 15:53:23 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 44567 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Tue, 07 Apr 2026 15:53:23 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Rick Macklem Subject: git: 53b4ae3bf0f7 - main - nfs_diskless: Fix handling of nfsuserd case for NFSv4 List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: rmacklem X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 53b4ae3bf0f7e625d51fa263a5bd3859792d61e3 Auto-Submitted: auto-generated Date: Tue, 07 Apr 2026 15:53:23 +0000 Message-Id: <69d52873.44567.319317b4@gitrepo.freebsd.org> The branch main has been updated by rmacklem: URL: https://cgit.FreeBSD.org/src/commit/?id=53b4ae3bf0f7e625d51fa263a5bd3859792d61e3 commit 53b4ae3bf0f7e625d51fa263a5bd3859792d61e3 Author: Rick Macklem AuthorDate: 2026-04-07 15:50:21 +0000 Commit: Rick Macklem CommitDate: 2026-04-07 15:50:21 +0000 nfs_diskless: Fix handling of nfsuserd case for NFSv4 Commit 8b9775912cbc added support for an NFSv4 mounted root file system, but only if the NFSv4 configuration used id numbers in the strings. This patch adds support for the case where the NFSv4 configuration uses name<-->id mappings via nfsuserd(8) by priming the mapping cache with just enough entries so that it works until the nfsuserd(8) is running. They are listed in nfs_prime_userd[] in sys/fs/nfs/nfs_commonsubs.c. The entries in nfs_prime_userd[] are also wired into the kernel's cache for name<-->id mappings when nfsuserd(8) starts up. This is necessary, since an upcall to the nfsuserd(8) daemon for a mapping when looking up the path to the passwd/group database files (/etc) will hang the system, due to a vnode lock being held on the entry in the path which blocks nfsuserd(8) from accessing files. To enable this case, the following must be put in the NFS root file system's /boot/loader.conf: boot.nfsroot.options="nfsv4" boot.nfsroot.user_domain="" where must be the same as nfsuserd uses (usually set via the -domain flag). If boot.nfsroot.user_domain does not exist or is the empty string, ids is strings is configured. MFC after: 1 week Requested by: Dan Shelton Fixes: 8b9775912cbc ("nfs_diskless: Add support for an NFSv4 root fs") --- sys/fs/nfs/nfs_commonsubs.c | 76 +++++++++++++++++++++++++++++++++++++++------ sys/fs/nfs/nfsid.h | 13 ++++++++ sys/fs/nfs/nfsrvstate.h | 1 + sys/nfs/nfs_diskless.c | 44 ++++++++++++++++++++++++++ 4 files changed, 124 insertions(+), 10 deletions(-) diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c index 78e2fbb72bdb..39d7cb447d6a 100644 --- a/sys/fs/nfs/nfs_commonsubs.c +++ b/sys/fs/nfs/nfs_commonsubs.c @@ -70,6 +70,7 @@ struct nfsreqhead nfsd_reqq; int nfsrv_lease = NFSRV_LEASE; int ncl_mbuf_mlen = MLEN; int nfsrv_doflexfile = 0; +bool nfs_nfsv4root = false; NFSNAMEIDMUTEX; NFSSOCKMUTEX; extern int nfsrv_lughashsize; @@ -80,6 +81,21 @@ extern struct nfsdevicehead nfsrv_devidhead; extern struct nfsstatsv1 nfsstatsv1; extern uint32_t nfs_srvmaxio; +/* + * Define just enough NFSv4 id<-->name mappings to make things work + * until the nfsuserd(8) is running. + * XXX These name/ids must be kept the same as what is in /etc/passwd + * and /etc/group. + */ +struct nfs_prime_userd nfs_prime_userd[] = { + { NFSID_INITIALIZE, UID_NOBODY, GID_NOGROUP, NULL }, + { NFSID_ADDUID, UID_ROOT, GID_NOGROUP, "root" }, + { NFSID_ADDUID, UID_BIN, GID_NOGROUP, "bin" }, + { NFSID_ADDGID, UID_NOBODY, GID_WHEEL, "wheel" }, + { NFSID_ADDGID, UID_NOBODY, GID_OPERATOR, "operator" }, + { 0, 0, 0, NULL }, +}; + NFSD_VNET_DEFINE(int, nfsd_enable_stringtouid) = 0; NFSD_VNET_DEFINE(struct nfssockreq, nfsrv_nfsuserdsock); NFSD_VNET_DEFINE(nfsuserd_state, nfsrv_nfsuserd) = NOTRUNNING; @@ -233,6 +249,7 @@ static int nfsrv_skipace(struct nfsrv_descript *nd, acl_type_t, int *acesizep); static void nfsv4_wanted(struct nfsv4lock *lp); static uint32_t nfsv4_filesavail(struct statfs *, struct mount *); static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name); +static bool nfs_in_prime(int flag, uid_t uid, gid_t gid); static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser); static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **, int *, int *); @@ -3667,7 +3684,8 @@ tryagain: mtx_lock(&hp->mtx); TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { if (usrp->lug_uid == uid) { - if (usrp->lug_expiry < NFSD_MONOSEC) + if (!usrp->lug_wired && + usrp->lug_expiry < NFSD_MONOSEC) break; /* * If the name doesn't already have an '@' @@ -3759,7 +3777,8 @@ tryagain: mtx_lock(&hp->mtx); TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { if (usrp->lug_uid == uid) { - if (usrp->lug_expiry < NFSD_MONOSEC) + if (!usrp->lug_wired && + usrp->lug_expiry < NFSD_MONOSEC) break; if (usrp->lug_cred != NULL) { newcred = crhold(usrp->lug_cred); @@ -3859,7 +3878,8 @@ tryagain: TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { if (usrp->lug_namelen == len && !NFSBCMP(usrp->lug_name, str, len)) { - if (usrp->lug_expiry < NFSD_MONOSEC) + if (!usrp->lug_wired && + usrp->lug_expiry < NFSD_MONOSEC) break; hp2 = NFSUSERHASH(usrp->lug_uid); mtx_lock(&hp2->mtx); @@ -3936,7 +3956,8 @@ tryagain: mtx_lock(&hp->mtx); TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { if (usrp->lug_gid == gid) { - if (usrp->lug_expiry < NFSD_MONOSEC) + if (!usrp->lug_wired && + usrp->lug_expiry < NFSD_MONOSEC) break; /* * If the name doesn't already have an '@' @@ -4081,7 +4102,8 @@ tryagain: TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { if (usrp->lug_namelen == len && !NFSBCMP(usrp->lug_name, str, len)) { - if (usrp->lug_expiry < NFSD_MONOSEC) + if (!usrp->lug_wired && + usrp->lug_expiry < NFSD_MONOSEC) break; hp2 = NFSGROUPHASH(usrp->lug_gid); mtx_lock(&hp2->mtx); @@ -4282,6 +4304,23 @@ out: return (error); } +/* Check to see if the uid/gid is in the nfs_prime_userd list. */ +static bool +nfs_in_prime(int flag, uid_t uid, gid_t gid) +{ + int i; + + for (i = 0; nfs_prime_userd[i].flag != 0; i++) { + if ((nfs_prime_userd[i].flag & flag) == NFSID_ADDUID && + nfs_prime_userd[i].uid == uid) + return (true); + if ((nfs_prime_userd[i].flag & flag) == NFSID_ADDGID && + nfs_prime_userd[i].gid == gid) + return (true); + } + return (false); +} + /* * This function is called from the nfssvc(2) system call, to update the * kernel user/group name list(s) for the V4 owner and ownergroup attributes. @@ -4305,7 +4344,11 @@ nfssvc_idname(struct nfsd_idargs *nidp) } if (nidp->nid_flag & NFSID_INITIALIZE) { cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK); - error = copyin(nidp->nid_name, cp, nidp->nid_namelen); + error = 0; + if ((nidp->nid_flag & NFSID_SYSSPACE) == 0) + error = copyin(nidp->nid_name, cp, nidp->nid_namelen); + else + NFSBCOPY(nidp->nid_name, cp, nidp->nid_namelen); if (error != 0) { free(cp, M_NFSSTRING); goto out; @@ -4403,8 +4446,12 @@ nfssvc_idname(struct nfsd_idargs *nidp) */ newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK | M_ZERO); - error = copyin(nidp->nid_name, newusrp->lug_name, - nidp->nid_namelen); + error = 0; + if ((nidp->nid_flag & NFSID_SYSSPACE) == 0) + error = copyin(nidp->nid_name, newusrp->lug_name, + nidp->nid_namelen); + else + NFSBCOPY(nidp->nid_name, newusrp->lug_name, nidp->nid_namelen); if (error == 0 && nidp->nid_ngroup > 0 && (nidp->nid_flag & NFSID_ADDUID) != 0) { grps = NULL; @@ -4522,7 +4569,11 @@ nfssvc_idname(struct nfsd_idargs *nidp) newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout; else newusrp->lug_expiry = NFSD_MONOSEC + 5; + newusrp->lug_wired = false; if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) { + if (nfs_nfsv4root && nfs_in_prime(NFSID_ADDUID, nidp->nid_uid, + nidp->nid_gid)) + newusrp->lug_wired = true; newusrp->lug_uid = nidp->nid_uid; thp = NFSUSERHASH(newusrp->lug_uid); mtx_assert(&thp->mtx, MA_OWNED); @@ -4532,6 +4583,9 @@ nfssvc_idname(struct nfsd_idargs *nidp) TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); atomic_add_int(&NFSD_VNET(nfsrv_usercnt), 1); } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) { + if (nfs_nfsv4root && nfs_in_prime(NFSID_ADDGID, nidp->nid_uid, + nidp->nid_gid)) + newusrp->lug_wired = true; newusrp->lug_gid = nidp->nid_gid; thp = NFSGROUPHASH(newusrp->lug_gid); mtx_assert(&thp->mtx, MA_OWNED); @@ -4580,7 +4634,8 @@ nfssvc_idname(struct nfsd_idargs *nidp) TAILQ_FOREACH_SAFE(usrp, &NFSD_VNET(nfsuserhash)[i].lughead, lug_numhash, nusrp) - if (usrp->lug_expiry < NFSD_MONOSEC) + if (!usrp->lug_wired && + usrp->lug_expiry < NFSD_MONOSEC) nfsrv_removeuser(usrp, 1); } for (i = 0; i < nfsrv_lughashsize; i++) { @@ -4610,7 +4665,8 @@ nfssvc_idname(struct nfsd_idargs *nidp) TAILQ_FOREACH_SAFE(usrp, &NFSD_VNET(nfsgrouphash)[i].lughead, lug_numhash, nusrp) - if (usrp->lug_expiry < NFSD_MONOSEC) + if (!usrp->lug_wired && + usrp->lug_expiry < NFSD_MONOSEC) nfsrv_removeuser(usrp, 0); } for (i = 0; i < nfsrv_lughashsize; i++) { diff --git a/sys/fs/nfs/nfsid.h b/sys/fs/nfs/nfsid.h index bd9807ca1acc..349fdecfc596 100644 --- a/sys/fs/nfs/nfsid.h +++ b/sys/fs/nfs/nfsid.h @@ -61,6 +61,19 @@ struct nfsd_idargs { #define NFSID_SYSSPACE 0x0200 #if defined(_KERNEL) || defined(KERNEL) +/* + * Define just enough NFSv4 id<-->name mappings to make things work + * until the nfsuserd(8) is running. + * XXX These name/ids must be kept the same as what is in /etc/passwd + * and /etc/group. + */ +struct nfs_prime_userd { + int flag; + uid_t uid; + gid_t gid; + char *nam; +}; + int nfssvc_idname(struct nfsd_idargs *); #endif diff --git a/sys/fs/nfs/nfsrvstate.h b/sys/fs/nfs/nfsrvstate.h index cc19ed6fa1d2..858c52ec6218 100644 --- a/sys/fs/nfs/nfsrvstate.h +++ b/sys/fs/nfs/nfsrvstate.h @@ -317,6 +317,7 @@ struct nfsusrgrp { } lug_un; struct ucred *lug_cred; /* Cred. with groups list */ int lug_namelen; /* Name length */ + bool lug_wired; /* Wired into cache */ u_char lug_name[1]; /* malloc'd correct length */ }; #define lug_uid lug_un.un_uid diff --git a/sys/nfs/nfs_diskless.c b/sys/nfs/nfs_diskless.c index d5278612d8d9..32dd7f3e997f 100644 --- a/sys/nfs/nfs_diskless.c +++ b/sys/nfs/nfs_diskless.c @@ -54,6 +54,7 @@ #include #include #include +#include #define NFS_IFACE_TIMEOUT_SECS 10 /* Timeout for interface to appear. */ @@ -70,6 +71,9 @@ struct nfs_diskless nfs_diskless = { { { 0 } } }; struct nfsv3_diskless nfsv3_diskless = { { { 0 } } }; int nfs_diskless_valid = 0; +extern struct nfs_prime_userd nfs_prime_userd[]; +extern bool nfs_nfsv4root; + /* * Validate/sanity check a rsize/wsize parameter. */ @@ -292,11 +296,51 @@ match_done: return; } } else { + struct nfsd_idargs nid; + int ret; + /* * For NFSv4, the file handle is derived from the * boot.nfsroot.path during mounting by NFSv4. */ nd3->root_fhsize = 0; + nfs_nfsv4root = true; + + /* + * Prime the id<-->name mappings just enough to + * make things work until the nfsuserd(8) daemon + * is started, if the nfsuserd_domain is set to a + * non-empty string. + */ + if ((cp = kern_getenv("boot.nfsroot.user_domain")) != + NULL) { + for (cnt = 0; *cp != '\0' && + nfs_prime_userd[cnt].flag != 0; cnt++) { + nid.nid_flag = + nfs_prime_userd[cnt].flag | + NFSID_SYSSPACE; + if (nfs_prime_userd[cnt].flag == + NFSID_INITIALIZE) { + nid.nid_name = cp; + nid.nid_usermax = 10; + } else { + nid.nid_name = + nfs_prime_userd[cnt].nam; + nid.nid_usertimeout = 3600; + } + nid.nid_namelen = strlen(nid.nid_name); + nid.nid_uid = nfs_prime_userd[cnt].uid; + nid.nid_gid = nfs_prime_userd[cnt].gid; + nid.nid_ngroup = 0; + nid.nid_grps = NULL; + ret = nfssvc_idname(&nid); + if (ret != 0) + printf("nfs_diskless: " + "nfssvc_idname failed %d\n", + ret); + } + freeenv(cp); + } } if ((cp = kern_getenv("boot.nfsroot.path")) != NULL) { strncpy(nd3->root_hostnam, cp, MNAMELEN - 1);