aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/fs/nfs/nfs_var.h1
-rw-r--r--sys/fs/nfsclient/nfs_clport.c31
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c3
-rw-r--r--sys/fs/nfsclient/nfs_clstate.c17
-rw-r--r--sys/fs/nfsclient/nfs_clvfsops.c7
-rw-r--r--sys/nfs/nfs_diskless.c37
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
@@ -660,6 +660,37 @@ ncl_pager_setsize(struct vnode *vp, u_quad_t *nsizep)
}
/*
+ * 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
* 2 - they should be persistent across client reboots
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index 9c86e0696153..308c45462002 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 {