From nobody Sun Apr 5 16:04:43 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 4fpcjR5G1Rz6WVfy for ; Sun, 05 Apr 2026 16:04:43 +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 4fpcjR3SxBz3jnB for ; Sun, 05 Apr 2026 16:04:43 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1775405083; 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=MVGRLBzBqKjTHdJO6EbxWVIrvOLi6UluqkvCak94EZ8=; b=SSltwjp1shk6XNNnqNxbKtG56U81QsxuwN/pA6NtbBt+chFYxdVwZCElW/gmwcaJGU2Zjb +9Eo0n/xizM7IPtj5RVk9/B9jZsC9ZUKEiGBfCm+L70cx0cS46RpGKgdHwKmJ2zkQuCuag bIGn3kE2dV4UfloCA5xWUhyF7CAJCfkUKXEjVzF/IuKzngfsS8ad3EKx+fo3mkskpiNUhD 8mYV06P3fd5sYg3FbogUftuQErRDgAT9NqmWi2v4uxnp8n7SZKdxPY1+EqfZxzYYTYkbA8 mgIyRMb+XOX3aw9Mt/lk1ZmnOreoDFSlcUieQJcyRtR74bcF1Jd/cr/CDdT4hw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1775405083; a=rsa-sha256; cv=none; b=O1UfUfoodBceBYKXb5liknMNa6RrdFQIUdorBCZBtNcu9lDMaPEvEGQLNYCpgLXGxZBII4 uax0qW8W7MtSYWdKgllD5sk7h9q7P4hy5Uh7PwFL4BmvbGAuGlURc+FJVS2JmDfLTAoY9q +UmihTH9UhkMuoewSbvnsXBH1eKxGuhqgzWyLsD7E4rkbdgvBhapDMC2FLmUFOuQlDt2yk J1NsjLznjUX2q6Q40MI8CuwiCEVQt4+VPCvXPL6q+RPxjRtt7rzc+Bk0sqpZCa6PtsbktL 41rRhk3+2D9eLvquEYJrYSrhvWSsXIckz3KemzotgWaZEUQ8cSYinbmfuBZ52Q== 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=1775405083; 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=MVGRLBzBqKjTHdJO6EbxWVIrvOLi6UluqkvCak94EZ8=; b=w2qnsw43W1e5YMxR7z686kFcKoapOEJ1PRc4ixCY2mteXaY3MUXVAptupH/eZwhPcnAnsP aB3jgfxr0ynvKhVVE9UMuC21kQw1NtkBIZfMcqtNQOswSZAFDIbU1i8APLhqlQUL58o2xd quxFry26DW/6nNJAftDbmGKOJVl/R1UKU/myztGqj+f06N5RiutoVvfCxd2Dl86TsIB/ZC 5eHSQzQReW9dUkmzalgkmeqOZnpT1RBfo/w/PIfGmNbsL6kR5KsqjIM1dwN5p6qS4NhTlm 68cTQh/AoSXKAR7ABZMT2fAiwghwVEYrKBWCvUNAfehoHtWWqvd3vbPWt3V2EQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4fpcjR2zkFz1Bwb for ; Sun, 05 Apr 2026 16:04:43 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 4511d by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Sun, 05 Apr 2026 16:04:43 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Rick Macklem Subject: git: 8b9775912cbc - main - nfs_diskless: Add support for an NFSv4 root fs 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/main X-Git-Reftype: branch X-Git-Commit: 8b9775912cbc7bb3c05c1fdfc3597dc4b68a9b9e Auto-Submitted: auto-generated Date: Sun, 05 Apr 2026 16:04:43 +0000 Message-Id: <69d2881b.4511d.5f34dcf8@gitrepo.freebsd.org> The branch main has been updated by rmacklem: URL: https://cgit.FreeBSD.org/src/commit/?id=8b9775912cbc7bb3c05c1fdfc3597dc4b68a9b9e commit 8b9775912cbc7bb3c05c1fdfc3597dc4b68a9b9e Author: Rick Macklem AuthorDate: 2026-04-05 16:00:24 +0000 Commit: Rick Macklem CommitDate: 2026-04-05 16:02:39 +0000 nfs_diskless: Add support for an NFSv4 root fs Without this patch, diskless root NFS file systems could only be mounted via NFSv3 (or NFSv2). This patch adds the basic support needed to mount a root fs via NFSv4. At this time, the NFSv4 mount will only work if the following is done on the NFS server configuration: - The root directory specified in the "V4:" line in /etc/exports must be "/". This is needed since the path to mount must be the same for NFSv3 and NFSv4. - The NFS server must be configured to do both NFSv3 and NFSv4, since the bootstrap code still uses NFSv3. - The NFSv4 server must be configured with: vfs.nfs.enable_uidtostring=1 vfs.nfsd.enable_stringtouid=1 since the NFSv4 root fs cannot be running nfsuserd(8) when it is booting. (This limitation may be removed in a future commit by hard-wiring enough id<-->name mapping entries to handle things until the nfsuserd(8) is running.) To enable the root fs to be mounted via NFSv4, it needs: - in the root file system's /boot/loader.conf boot.nfsroot.options="nfsv4" (Additional options like rsize=65536,wsize=65536 can also be specified.) - in the root file system's /etc/sysctl.conf vfs.nfs.enable_uidtostring=1 Requested by: Dan Shelton MFC after: 1 week --- sys/fs/nfs/nfs_var.h | 1 + sys/fs/nfsclient/nfs_clport.c | 31 +++++++++++++++++++++++++++++++ sys/fs/nfsclient/nfs_clrpcops.c | 3 ++- sys/fs/nfsclient/nfs_clstate.c | 17 +++++++++++++++-- sys/fs/nfsclient/nfs_clvfsops.c | 7 +++++-- sys/nfs/nfs_diskless.c | 37 +++++++++++++++++++++++++------------ 6 files changed, 79 insertions(+), 17 deletions(-) diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h index 28088c12d7e7..145cbf984464 100644 --- a/sys/fs/nfs/nfs_var.h +++ b/sys/fs/nfs/nfs_var.h @@ -609,6 +609,7 @@ int nfscl_relbytelock(vnode_t, u_int64_t, u_int64_t, int nfscl_checkwritelocked(vnode_t, struct flock *, struct ucred *, NFSPROC_T *, void *, int); void nfscl_lockrelease(struct nfscllockowner *, int, int); +void nfscl_uuidcheck(char *); void nfscl_fillclid(u_int64_t, char *, u_int8_t *, u_int16_t); void nfscl_filllockowner(void *, u_int8_t *, int); void nfscl_freeopen(struct nfsclopen *, int, bool); diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c index cf163adc02de..d23051058ce4 100644 --- a/sys/fs/nfsclient/nfs_clport.c +++ b/sys/fs/nfsclient/nfs_clport.c @@ -659,6 +659,37 @@ ncl_pager_setsize(struct vnode *vp, u_quad_t *nsizep) return (setnsize); } +/* + * If the uuid passed in is the DEFAULT_UUID, try and find an + * alternate to replace it with. + * If no alternate is available, set uuid to "" so that nfscl_fillclid() + * will use random bytes. + */ +void +nfscl_uuidcheck(char *uuid) +{ + int ucplen, uuidlen; + char *ucp; + + /* + * If the uuid is the DEFAULT_UUID, try and get an alternative. + */ + uuidlen = strlen(uuid); + ucp = NULL; + if (uuidlen == strlen(DEFAULT_HOSTUUID) && + NFSBCMP(uuid, DEFAULT_HOSTUUID, uuidlen) == 0) { + *uuid = '\0'; + /* Use smbios.system.uuid if it exists. */ + if ((ucp = kern_getenv("smbios.system.uuid")) != NULL) { + ucplen = strlen(ucp); + if (ucplen < HOSTUUIDLEN && ucplen > 0) + strlcpy(uuid, ucp, HOSTUUIDLEN); + } + } + if (ucp != NULL) + freeenv(ucp); +} + /* * Fill in the client id name. For these bytes: * 1 - they must be unique diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c index 974d08611a00..130cc4990152 100644 --- a/sys/fs/nfsclient/nfs_clrpcops.c +++ b/sys/fs/nfsclient/nfs_clrpcops.c @@ -67,6 +67,7 @@ SYSCTL_U64(_vfs_nfs, OID_AUTO, maxcopyrange, CTLFLAG_RW, /* * Global variables */ +uint32_t nfs_exchangeboot = 0; extern struct nfsstatsv1 nfsstatsv1; extern int nfs_numnfscbd; extern struct timeval nfsboottime; @@ -5537,7 +5538,7 @@ nfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclclient *clp, nfscl_reqstart(nd, NFSPROC_EXCHANGEID, nmp, NULL, 0, NULL, NULL, NFS_VER4, minorvers, NULL); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); - *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* Client owner */ + *tl++ = txdr_unsigned(nfs_exchangeboot); /* Client owner */ *tl = txdr_unsigned(clp->nfsc_rev); (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen); diff --git a/sys/fs/nfsclient/nfs_clstate.c b/sys/fs/nfsclient/nfs_clstate.c index 6dc97142b77f..a511c31d5202 100644 --- a/sys/fs/nfsclient/nfs_clstate.c +++ b/sys/fs/nfsclient/nfs_clstate.c @@ -89,6 +89,8 @@ extern u_int32_t newnfs_false, newnfs_true; extern int nfscl_debuglevel; extern int nfscl_enablecallb; extern int nfs_numnfscbd; +extern struct timeval nfsboottime; +extern uint32_t nfs_exchangeboot; NFSREQSPINLOCK; NFSCLSTATEMUTEX; int nfscl_inited = 0; @@ -883,9 +885,11 @@ nfscl_getcl(struct mount *mp, struct ucred *cred, NFSPROC_T *p, if (cred != NULL) { getcredhostuuid(cred, uuid, sizeof uuid); idlen = strlen(uuid); - if (idlen > 0) + if (idlen > 0) { + nfscl_uuidcheck(uuid); + idlen = strlen(uuid); idlen += sizeof (u_int64_t); - else + } else idlen += sizeof (u_int64_t) + 16; /* 16 random bytes */ newclp = malloc( sizeof (struct nfsclclient) + idlen - 1, M_NFSCLCLIENT, @@ -996,6 +1000,15 @@ nfscl_getcl(struct mount *mp, struct ucred *cred, NFSPROC_T *p, * such that the server throws away the clientid before * receiving the SetClientIDConfirm. */ + /* + * Must be done here while locked and before calling + * nfsrpc_setclient(). + */ + if (nfs_exchangeboot == 0) { + nfs_exchangeboot = nfsboottime.tv_sec; + if (nfs_exchangeboot == 0) + nfs_exchangeboot = arc4random(); + } if (clp->nfsc_renew > 0) clidinusedelay = NFSCL_LEASE(clp->nfsc_renew) * 2; else diff --git a/sys/fs/nfsclient/nfs_clvfsops.c b/sys/fs/nfsclient/nfs_clvfsops.c index 212c88f28930..74e5e2dc9b1b 100644 --- a/sys/fs/nfsclient/nfs_clvfsops.c +++ b/sys/fs/nfsclient/nfs_clvfsops.c @@ -567,7 +567,7 @@ nfs_mountdiskless(char *path, struct vnode **vpp, struct mount *mp) { struct sockaddr *nam; - int dirlen, error; + int dirlen, error, minvers; char *dirpath; /* @@ -580,9 +580,12 @@ nfs_mountdiskless(char *path, else dirlen = 0; nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK); + minvers = 0; + if ((args->flags & NFSMNT_NFSV4) != 0) + minvers = -1; if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen, NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NAMETIMEO, - NFS_DEFAULT_NEGNAMETIMEO, 0, 0, NULL, 0)) != 0) { + NFS_DEFAULT_NEGNAMETIMEO, minvers, 0, NULL, 0)) != 0) { printf("nfs_mountroot: mount %s on /: %d\n", path, error); return (error); } diff --git a/sys/nfs/nfs_diskless.c b/sys/nfs/nfs_diskless.c index 0f0cf80feeec..d5278612d8d9 100644 --- a/sys/nfs/nfs_diskless.c +++ b/sys/nfs/nfs_diskless.c @@ -119,6 +119,10 @@ nfs_parse_options(const char *envopts, struct nfs_args *nd) else if (strcmp(o, "nfsv3") == 0) { nd->flags &= ~NFSMNT_NFSV4; nd->flags |= NFSMNT_NFSV3; + } else if (strcmp(o, "nfsv4") == 0) { + nd->flags &= ~NFSMNT_NFSV3; + nd->flags |= NFSMNT_NFSV4; + nd->sotype = SOCK_STREAM; } else if (strcmp(o, "tcp") == 0) nd->sotype = SOCK_STREAM; else if (strcmp(o, "udp") == 0) @@ -271,24 +275,33 @@ match_done: return; } nd3->root_saddr.sin_port = htons(NFS_PORT); - fhlen = decode_nfshandle("boot.nfsroot.nfshandle", - &nd3->root_fh[0], NFSX_V3FHMAX); - if (fhlen == 0) { - printf("nfs_diskless: no NFS handle\n"); - return; + if ((cp = kern_getenv("boot.nfsroot.options")) != NULL) { + nfs_parse_options(cp, &nd3->root_args); + freeenv(cp); } - if (fhlen != nd3->root_fhsize) { - printf("nfs_diskless: bad NFS handle len=%d\n", fhlen); - return; + if ((nd3->root_args.flags & NFSMNT_NFSV4) == 0) { + fhlen = decode_nfshandle("boot.nfsroot.nfshandle", + &nd3->root_fh[0], NFSX_V3FHMAX); + if (fhlen == 0) { + printf("nfs_diskless: no NFS handle\n"); + return; + } + if (fhlen != nd3->root_fhsize) { + printf("nfs_diskless: bad NFS handle len=%d\n", + fhlen); + return; + } + } else { + /* + * For NFSv4, the file handle is derived from the + * boot.nfsroot.path during mounting by NFSv4. + */ + nd3->root_fhsize = 0; } if ((cp = kern_getenv("boot.nfsroot.path")) != NULL) { strncpy(nd3->root_hostnam, cp, MNAMELEN - 1); freeenv(cp); } - if ((cp = kern_getenv("boot.nfsroot.options")) != NULL) { - nfs_parse_options(cp, &nd3->root_args); - freeenv(cp); - } nfs_diskless_valid = 3; } else {