diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h index 28088c12d7e..145cbf98446 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 cf163adc02d..d23051058ce 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 974d08611a0..130cc499015 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 6dc97142b77..a511c31d520 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 212c88f2893..74e5e2dc9b1 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 0f0cf80feee..d5278612d8d 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 @@ nfs_setup_diskless(void) 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 {