From nobody Tue Apr 14 03:29:04 2026 X-Original-To: dev-commits-src-all@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 4fvqWV2f8Qz6Z4HY for ; Tue, 14 Apr 2026 03:29:10 +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 4fvqWV1qBhz3rXR for ; Tue, 14 Apr 2026 03:29:10 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1776137350; 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=y/UzqBo+/S/SjnOuCiF98TYC+HHEvUg+OehqztXm7D4=; b=QRC5fwQBB/TX7HmQmwascOukvAKnh01FTsWLRi9kugIdj/xtxCNT/wGTPTn1WYf7xrQQp5 zHnqDnW1rsGqW4hRuGk4/Z3oV2aeQR6BP+u16mbcHo/pnmw7OFSDK2df+LPPGg+QneDovt tfL9V1azLJHVAvo0YaYRHyCizsIRisnIu6MEyGzwlBm6AMiwOywTCBFsl2jwtyp4KtK0l2 I/xnNnTfmVKPj6AMuitJCbiPWTtjbtL/8SahL18nhmTNIu4OBslBGXCsxoTAxM7oA77xTH Lirhe2MsV72a4ZZcwOvQt/npshzk6hfuxJW3u2SIZIgCGWJDm5LtWMnbwsgqOg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1776137350; a=rsa-sha256; cv=none; b=KU2LDhv+BGJYEYP4lHxqIgnDwUl9FbdzX0yBIxIeCzqafYpsofS9/vAWNo9BY4+5IsVeme 5qZ0alilAuszF8qyM7nqWM/EZYNJ2IFhxTi137Vdj6HvJSAwWwx1cGanw/luKCyE+SlK+b JmeJ7Mfy14Wlgema8NxtuZlXuarvEbSa/y+/MAidryhfyWmEwxUdSdJPjgJ6Kn/08Fp6lg Ta0e0C6m0nRRE6ApvMbCFeov1CplyJ5/vxFWk2AXq4O0RhwMWh+/lPGt4ZycAo7ELpCysy m9/fOqXSplPlCPxVnlr/koyyWJicsuWDUGPk+md9xA6mmogzG0TyO9Pf3XjHFw== 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=1776137350; 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=y/UzqBo+/S/SjnOuCiF98TYC+HHEvUg+OehqztXm7D4=; b=cfhyO+L121KdotE+GPV8h/JXRAQtsCAnsBfk/UxzFXZJHwrGfwJ/K2HreVqBxNavf3s6Ni U+E7GAc5GtOO3SxMfLBpvUYs5O1pYT25100wZuQf139tZ5uQ3EWgKtM7QqYvzAVH6F1Xmy WMCy8RcWbGHJmVlcHMuBaqp2iX+oPvnINdh2OXqML1MUGKX1hfIEvPRxpQVGeqQrT0N0mI O81F5nz2YjiN0rxzzU/eZyo/luU8mZPiH10HKIXJP+nw2+oPQrqaaErmN/h5lTTvW3t649 ZsDyNFaI+FFpY8pck75HFpiJbehfAfj0Vi0Z10IJV03iQt+pqTgIuTS6cQUAeA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4fvqWV0wz8zZ8l for ; Tue, 14 Apr 2026 03:29:10 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 2362a by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Tue, 14 Apr 2026 03:29:04 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Rick Macklem Subject: git: 692a289922d2 - stable/15 - nfs_diskless: Fix handling of nfsuserd case for NFSv4 List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@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/stable/15 X-Git-Reftype: branch X-Git-Commit: 692a289922d2a7005357e01d5c770a0abcd777cc Auto-Submitted: auto-generated Date: Tue, 14 Apr 2026 03:29:04 +0000 Message-Id: <69ddb480.2362a.1a80e80b@gitrepo.freebsd.org> The branch stable/15 has been updated by rmacklem: URL: https://cgit.FreeBSD.org/src/commit/?id=692a289922d2a7005357e01d5c770a0abcd777cc commit 692a289922d2a7005357e01d5c770a0abcd777cc Author: Rick Macklem AuthorDate: 2026-04-07 15:50:21 +0000 Commit: Rick Macklem CommitDate: 2026-04-14 03:26:32 +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. (cherry picked from commit 53b4ae3bf0f7e625d51fa263a5bd3859792d61e3) --- 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);