svn commit: r253375 - projects/nfsv4.1-server/sys/fs/nfsserver

Rick Macklem rmacklem at FreeBSD.org
Tue Jul 16 00:05:19 UTC 2013


Author: rmacklem
Date: Tue Jul 16 00:05:17 2013
New Revision: 253375
URL: http://svnweb.freebsd.org/changeset/base/253375

Log:
  Merge in changes for the NFSv4.1 server to the first 4 files.
  More to come soon.

Modified:
  projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdcache.c
  projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdkrpc.c
  projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdport.c
  projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdserv.c

Modified: projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdcache.c
==============================================================================
--- projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdcache.c	Mon Jul 15 23:27:48 2013	(r253374)
+++ projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdcache.c	Tue Jul 16 00:05:17 2013	(r253375)
@@ -811,6 +811,9 @@ APPLESTATIC void
 nfsrvd_refcache(struct nfsrvcache *rp)
 {
 
+	if (rp == NULL)
+		/* For NFSv4.1, there is no cache entry. */
+		return;
 	NFSLOCKCACHE();
 	if (rp->rc_refcnt < 0)
 		panic("nfs cache refcnt");

Modified: projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdkrpc.c
==============================================================================
--- projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdkrpc.c	Mon Jul 15 23:27:48 2013	(r253374)
+++ projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdkrpc.c	Tue Jul 16 00:05:17 2013	(r253375)
@@ -304,7 +304,10 @@ nfs_proc(struct nfsrv_descript *nd, u_in
     u_int64_t sockref, struct nfsrvcache **rpp)
 {
 	struct thread *td = curthread;
-	int cacherep = RC_DOIT, isdgram;
+	int cacherep = RC_DOIT, isdgram, taglen = -1;
+	struct mbuf *m;
+	u_char tag[NFSV4_SMALLSTR + 1], *tagstr = NULL;
+	u_int32_t minorvers = 0;
 
 	*rpp = NULL;
 	if (nd->nd_nam2 == NULL) {
@@ -337,7 +340,14 @@ nfs_proc(struct nfsrv_descript *nd, u_in
 		nd->nd_retxid = xid;
 		nd->nd_tcpconntime = NFSD_MONOSEC;
 		nd->nd_sockref = sockref;
-		cacherep = nfsrvd_getcache(nd, so);
+		if ((nd->nd_flag & ND_NFSV4) != 0)
+			nfsd_getminorvers(nd, tag, &tagstr, &taglen,
+			    &minorvers);
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			/* NFSv4.1 caches replies in the session slots. */
+			cacherep = RC_DOIT;
+		else
+			cacherep = nfsrvd_getcache(nd, so);
 	}
 
 	/*
@@ -347,13 +357,31 @@ nfs_proc(struct nfsrv_descript *nd, u_in
 	 * RC_DROPIT - just throw the request away
 	 */
 	if (cacherep == RC_DOIT) {
-		nfsrvd_dorpc(nd, isdgram, td);
-		if (nd->nd_repstat == NFSERR_DONTREPLY)
-			cacherep = RC_DROPIT;
-		else
+		nfsrvd_dorpc(nd, isdgram, tagstr, taglen, minorvers, td);
+		if ((nd->nd_flag & ND_NFSV41) != 0) {
+			if (nd->nd_repstat != NFSERR_REPLYFROMCACHE &&
+			    (nd->nd_flag & ND_SAVEREPLY) != 0) {
+				/* Cache a copy of the reply. */
+				m = m_copym(nd->nd_mreq, 0, M_COPYALL,
+				    M_WAITOK);
+			} else
+				m = NULL;
+			if ((nd->nd_flag & ND_HASSEQUENCE) != 0)
+				nfsrv_cache_session(nd->nd_sessionid,
+				    nd->nd_slotid, nd->nd_repstat, &m);
+			if (nd->nd_repstat == NFSERR_REPLYFROMCACHE)
+				nd->nd_repstat = 0;
 			cacherep = RC_REPLY;
-		*rpp = nfsrvd_updatecache(nd, so);
+		} else {
+			if (nd->nd_repstat == NFSERR_DONTREPLY)
+				cacherep = RC_DROPIT;
+			else
+				cacherep = RC_REPLY;
+			*rpp = nfsrvd_updatecache(nd, so);
+		}
 	}
+	if (tagstr != NULL && taglen > NFSV4_SMALLSTR)
+		free(tagstr, M_TEMP);
 
 	NFSEXITCODE2(0, nd);
 	return (cacherep);

Modified: projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdport.c
==============================================================================
--- projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdport.c	Mon Jul 15 23:27:48 2013	(r253374)
+++ projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdport.c	Tue Jul 16 00:05:17 2013	(r253375)
@@ -58,6 +58,7 @@ extern struct nfsrv_stablefirst nfsrv_st
 extern void (*nfsd_call_servertimer)(void);
 extern SVCPOOL	*nfsrvd_pool;
 extern struct nfsv4lock nfsd_suspend_lock;
+extern struct nfssessionhash nfssessionhash[NFSSESSIONHASHSIZE];
 struct vfsoptlist nfsv4root_opt, nfsv4root_newopt;
 NFSDLOCKMUTEX;
 struct mtx nfs_cache_mutex;
@@ -65,6 +66,7 @@ struct mtx nfs_v4root_mutex;
 struct nfsrvfh nfs_rootfh, nfs_pubfh;
 int nfs_pubfhset = 0, nfs_rootfhset = 0;
 struct proc *nfsd_master_proc = NULL;
+int nfsd_debuglevel = 0;
 static pid_t nfsd_master_pid = (pid_t)-1;
 static char nfsd_master_comm[MAXCOMLEN + 1];
 static struct timeval nfsd_master_start;
@@ -90,6 +92,8 @@ SYSCTL_INT(_vfs_nfsd, OID_AUTO, issue_de
     &nfsrv_issuedelegs, 0, "Enable nfsd to issue delegations");
 SYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_locallocks, CTLFLAG_RW,
     &nfsrv_dolocallocks, 0, "Enable nfsd to acquire local locks on files");
+SYSCTL_INT(_vfs_nfsd, OID_AUTO, debuglevel, CTLFLAG_RW, &nfsd_debuglevel,
+    0, "Debug level for new nfs server");
 
 #define	MAX_REORDERED_RPC	16
 #define	NUM_HEURISTIC		1031
@@ -3245,6 +3249,18 @@ nfsrv_hashfh(fhandle_t *fhp)
 }
 
 /*
+ * Calculate a hash value for the sessionid.
+ */
+uint32_t
+nfsrv_hashsessionid(uint8_t *sessionid)
+{
+	uint32_t hashval;
+
+	hashval = hash32_buf(sessionid, NFSX_V4SESSIONID, 0);
+	return (hashval);
+}
+
+/*
  * Signal the userland master nfsd to backup the stable restart file.
  */
 void
@@ -3278,7 +3294,7 @@ extern int (*nfsd_call_nfsd)(struct thre
 static int
 nfsd_modevent(module_t mod, int type, void *data)
 {
-	int error = 0;
+	int error = 0, i;
 	static int loaded = 0;
 
 	switch (type) {
@@ -3290,6 +3306,9 @@ nfsd_modevent(module_t mod, int type, vo
 		mtx_init(&nfs_v4root_mutex, "nfs_v4root_mutex", NULL, MTX_DEF);
 		mtx_init(&nfsv4root_mnt.mnt_mtx, "struct mount mtx", NULL,
 		    MTX_DEF);
+		for (i = 0; i < NFSSESSIONHASHSIZE; i++)
+			mtx_init(&nfssessionhash[i].mtx, "nfs_session_mutex",
+			    NULL, MTX_DEF);
 		lockinit(&nfsv4root_mnt.mnt_explock, PVFS, "explock", 0, 0);
 		nfsrvd_initcache();
 		nfsd_init();
@@ -3333,6 +3352,8 @@ nfsd_modevent(module_t mod, int type, vo
 		mtx_destroy(&nfs_cache_mutex);
 		mtx_destroy(&nfs_v4root_mutex);
 		mtx_destroy(&nfsv4root_mnt.mnt_mtx);
+		for (i = 0; i < NFSSESSIONHASHSIZE; i++)
+			mtx_destroy(&nfssessionhash[i].mtx);
 		lockdestroy(&nfsv4root_mnt.mnt_explock);
 		loaded = 0;
 		break;

Modified: projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdserv.c
==============================================================================
--- projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdserv.c	Mon Jul 15 23:27:48 2013	(r253374)
+++ projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdserv.c	Tue Jul 16 00:05:17 2013	(r253375)
@@ -2523,7 +2523,7 @@ nfsrvd_open(struct nfsrv_descript *nd, _
     struct nfsexstuff *exp)
 {
 	u_int32_t *tl;
-	int i;
+	int i, retext;
 	struct nfsstate *stp = NULL;
 	int error = 0, create, claim, exclusive_flag = 0;
 	u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
@@ -2560,6 +2560,16 @@ nfsrvd_open(struct nfsrv_descript *nd, _
 	stp->ls_uid = nd->nd_cred->cr_uid;
 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
 	i = fxdr_unsigned(int, *tl++);
+	retext = -1;
+	if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
+	    NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
+		retext = NFSV4OPEN_RESOURCE;
+		if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
+		    NFSV4OPEN_WANTPUSHDELEG)) == NFSV4OPEN_WANTNODELEG)
+			retext = NFSV4OPEN_NOTWANTED;
+		i &= ~(NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
+		    NFSV4OPEN_WANTPUSHDELEG);
+	}
 	switch (i) {
 	case NFSV4OPEN_ACCESSREAD:
 		stp->ls_flags |= NFSLCK_READACCESS;
@@ -2634,6 +2644,28 @@ nfsrvd_open(struct nfsrv_descript *nd, _
 			cverf[0] = *tl++;
 			cverf[1] = *tl;
 			break;
+		case NFSCREATE_EXCLUSIVE41:
+			NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
+			cverf[0] = *tl++;
+			cverf[1] = *tl;
+			error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
+			if (error != 0)
+				goto nfsmout;
+			if (NFSISSET_ATTRBIT(&attrbits,
+			    NFSATTRBIT_TIMEACCESSSET))
+				nd->nd_repstat = NFSERR_INVAL;
+			/*
+			 * If the na_gid being set is the same as that of
+			 * the directory it is going in, clear it, since
+			 * that is what will be set by default. This allows
+			 * a user that isn't in that group to do the create.
+			 */
+			if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
+			    nva.na_gid == dirfor.na_gid)
+				NFSVNO_UNSET(&nva, gid);
+			if (nd->nd_repstat == 0)
+				nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
+			break;
 		default:
 			nd->nd_repstat = NFSERR_BADXDR;
 			goto nfsmout;
@@ -2715,27 +2747,38 @@ nfsrvd_open(struct nfsrv_descript *nd, _
 			exclusive_flag = 1;
 			if (!named.ni_vp)
 				nva.na_mode = 0;
+			break;
+		    case NFSCREATE_EXCLUSIVE41:
+			exclusive_flag = 1;
+			break;
 		    };
 		}
 		nfsvno_open(nd, &named, clientid, &stateid, stp,
 		    &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
 		    nd->nd_cred, p, exp, &vp);
-	} else if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
-		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
-		i = fxdr_unsigned(int, *tl);
-		switch (i) {
-		case NFSV4OPEN_DELEGATEREAD:
-			stp->ls_flags |= NFSLCK_DELEGREAD;
-			break;
-		case NFSV4OPEN_DELEGATEWRITE:
-			stp->ls_flags |= NFSLCK_DELEGWRITE;
-		case NFSV4OPEN_DELEGATENONE:
-			break;
-		default:
-			nd->nd_repstat = NFSERR_BADXDR;
-			goto nfsmout;
-		};
-		stp->ls_flags |= NFSLCK_RECLAIM;
+	} else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
+	    NFSV4OPEN_CLAIMFH) {
+		if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
+			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+			i = fxdr_unsigned(int, *tl);
+			switch (i) {
+			case NFSV4OPEN_DELEGATEREAD:
+				stp->ls_flags |= NFSLCK_DELEGREAD;
+				break;
+			case NFSV4OPEN_DELEGATEWRITE:
+				stp->ls_flags |= NFSLCK_DELEGWRITE;
+			case NFSV4OPEN_DELEGATENONE:
+				break;
+			default:
+				nd->nd_repstat = NFSERR_BADXDR;
+				goto nfsmout;
+			};
+			stp->ls_flags |= NFSLCK_RECLAIM;
+		} else {
+			/* CLAIM_NULL_FH */
+			if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
+				nd->nd_repstat = NFSERR_INVAL;
+		}
 		vp = dp;
 		NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
 		if ((vp->v_iflag & VI_DOOMED) == 0)
@@ -2824,7 +2867,18 @@ nfsrvd_open(struct nfsrv_descript *nd, _
 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
 		else if (rflags & NFSV4OPEN_WRITEDELEGATE)
 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
-		else
+		else if (retext != -1) {
+			*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
+			if (retext == NFSV4OPEN_RESOURCE ||
+			    retext == NFSV4OPEN_CONTENTION) {
+				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
+				*tl++ = txdr_unsigned(retext);
+				*tl = newnfs_false;
+			} else {
+				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+				*tl = txdr_unsigned(retext);
+			}
+		} else
 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
 		if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
 			NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
@@ -2947,7 +3001,7 @@ nfsrvd_delegpurge(struct nfsrv_descript 
 		nd->nd_flag |= ND_IMPLIEDCLID;
 		nd->nd_clientid.qval = clientid.qval;
 	}
-	nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL,
+	nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
 	    NFSV4OP_DELEGPURGE, nd->nd_cred, p);
 nfsmout:
 	NFSEXITCODE2(error, nd);
@@ -2978,7 +3032,7 @@ nfsrvd_delegreturn(struct nfsrv_descript
 		nd->nd_flag |= ND_IMPLIEDCLID;
 		nd->nd_clientid.qval = clientid.qval;
 	}
-	nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp,
+	nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
 	    NFSV4OP_DELEGRETURN, nd->nd_cred, p);
 nfsmout:
 	vput(vp);
@@ -3016,6 +3070,10 @@ nfsrvd_openconfirm(struct nfsrv_descript
 	nfsv4stateid_t stateid;
 	nfsquad_t clientid;
 
+	if ((nd->nd_flag & ND_NFSV41) != 0) {
+		nd->nd_repstat = NFSERR_NOTSUPP;
+		goto nfsmout;
+	}
 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
 	stp->ls_ownerlen = 0;
 	stp->ls_op = nd->nd_rp;
@@ -3136,6 +3194,10 @@ nfsrvd_renew(struct nfsrv_descript *nd, 
 	int error = 0;
 	nfsquad_t clientid;
 
+	if ((nd->nd_flag & ND_NFSV41) != 0) {
+		nd->nd_repstat = NFSERR_NOTSUPP;
+		goto nfsmout;
+	}
 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
 		nd->nd_repstat = NFSERR_WRONGSEC;
 		goto nfsmout;
@@ -3151,7 +3213,7 @@ nfsrvd_renew(struct nfsrv_descript *nd, 
 		nd->nd_clientid.qval = clientid.qval;
 	}
 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
-	    NULL, (nfsquad_t)((u_quad_t)0), nd, p);
+	    NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
 nfsmout:
 	NFSEXITCODE2(error, nd);
 	return (error);
@@ -3275,6 +3337,10 @@ nfsrvd_setclientid(struct nfsrv_descript
 	u_char *verf, *ucp, *ucp2, addrbuf[24];
 	nfsquad_t clientid, confirm;
 
+	if ((nd->nd_flag & ND_NFSV41) != 0) {
+		nd->nd_repstat = NFSERR_NOTSUPP;
+		goto nfsmout;
+	}
 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
 		nd->nd_repstat = NFSERR_WRONGSEC;
 		goto out;
@@ -3387,6 +3453,10 @@ nfsrvd_setclientidcfrm(struct nfsrv_desc
 	int error = 0;
 	nfsquad_t clientid, confirm;
 
+	if ((nd->nd_flag & ND_NFSV41) != 0) {
+		nd->nd_repstat = NFSERR_NOTSUPP;
+		goto nfsmout;
+	}
 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
 		nd->nd_repstat = NFSERR_WRONGSEC;
 		goto nfsmout;
@@ -3402,7 +3472,7 @@ nfsrvd_setclientidcfrm(struct nfsrv_desc
 	 * returns the appropriate NFSERR status.
 	 */
 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
-	    NULL, confirm, nd, p);
+	    NULL, NULL, confirm, 0, nd, p);
 nfsmout:
 	NFSEXITCODE2(error, nd);
 	return (error);
@@ -3477,6 +3547,10 @@ nfsrvd_releaselckown(struct nfsrv_descri
 	int error = 0, len;
 	nfsquad_t clientid;
 
+	if ((nd->nd_flag & ND_NFSV41) != 0) {
+		nd->nd_repstat = NFSERR_NOTSUPP;
+		goto nfsmout;
+	}
 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
 		nd->nd_repstat = NFSERR_WRONGSEC;
 		goto nfsmout;
@@ -3516,3 +3590,383 @@ nfsmout:
 	NFSEXITCODE2(error, nd);
 	return (error);
 }
+
+/*
+ * nfsv4 exchange_id service
+ */
+APPLESTATIC int
+nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
+    __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
+{
+	uint32_t *tl;
+	int error = 0, i, idlen;
+	struct nfsclient *clp = NULL;
+	nfsquad_t clientid, confirm;
+	uint8_t *verf;
+	uint32_t sp4type, v41flags;
+	uint64_t owner_minor;
+	struct timespec verstime;
+
+	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
+		nd->nd_repstat = NFSERR_WRONGSEC;
+		goto nfsmout;
+	}
+	NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
+	verf = (uint8_t *)tl;
+	tl += (NFSX_VERF / NFSX_UNSIGNED);
+	i = fxdr_unsigned(int, *tl);
+	if (i > NFSV4_OPAQUELIMIT || i <= 0) {
+		nd->nd_repstat = NFSERR_BADXDR;
+		goto nfsmout;
+	}
+	idlen = i;
+	if (nd->nd_flag & ND_GSS)
+		i += nd->nd_princlen;
+	clp = (struct nfsclient *)malloc(sizeof(struct nfsclient) + i,
+	    M_NFSDCLIENT, M_WAITOK | M_ZERO);
+	NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
+	NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
+	NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
+	clp->lc_req.nr_cred = NULL;
+	NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
+	clp->lc_idlen = idlen;
+	error = nfsrv_mtostr(nd, clp->lc_id, idlen);
+	if (error != 0)
+		goto nfsmout;
+	if ((nd->nd_flag & ND_GSS) != 0) {
+		clp->lc_flags = LCL_GSS;
+		if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
+			clp->lc_flags |= LCL_GSSINTEGRITY;
+		else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
+			clp->lc_flags |= LCL_GSSPRIVACY;
+	} else
+		clp->lc_flags = 0;
+	if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
+		clp->lc_flags |= LCL_NAME;
+		clp->lc_namelen = nd->nd_princlen;
+		clp->lc_name = &clp->lc_id[idlen];
+		NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
+	} else {
+		clp->lc_uid = nd->nd_cred->cr_uid;
+		clp->lc_gid = nd->nd_cred->cr_gid;
+	}
+	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
+	v41flags = fxdr_unsigned(uint32_t, *tl++);
+	if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
+	    NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
+	    NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
+		nd->nd_repstat = NFSERR_INVAL;
+		goto nfsmout;
+	}
+	if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
+		confirm.lval[1] = 1;
+	else
+		confirm.lval[1] = 0;
+	v41flags = NFSV4EXCH_USENONPNFS;
+	sp4type = fxdr_unsigned(uint32_t, *tl);
+	if (sp4type != NFSV4EXCH_SP4NONE) {
+		nd->nd_repstat = NFSERR_NOTSUPP;
+		goto nfsmout;
+	}
+
+	/*
+	 * nfsrv_setclient() does the actual work of adding it to the
+	 * client list. If there is no error, the structure has been
+	 * linked into the client list and clp should no longer be used
+	 * here. When an error is returned, it has not been linked in,
+	 * so it should be free'd.
+	 */
+	nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
+	if (clp != NULL) {
+		NFSSOCKADDRFREE(clp->lc_req.nr_nam);
+		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
+		free(clp, M_NFSDCLIENT);
+	}
+	if (nd->nd_repstat == 0) {
+		if (confirm.lval[1] != 0)
+			v41flags |= NFSV4EXCH_CONFIRMEDR;
+		NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
+		*tl++ = clientid.lval[0];			/* ClientID */
+		*tl++ = clientid.lval[1];
+		*tl++ = txdr_unsigned(confirm.lval[0]);		/* SequenceID */
+		*tl++ = txdr_unsigned(v41flags);		/* Exch flags */
+		*tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE);	/* No SSV */
+		owner_minor = 0;				/* Owner */
+		txdr_hyper(owner_minor, tl);			/* Minor */
+		(void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
+		    strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */
+		NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
+		*tl++ = txdr_unsigned(NFSX_UNSIGNED);
+		NFSBCOPY(&time_uptime, tl++, NFSX_UNSIGNED);
+		*tl = txdr_unsigned(1);
+		(void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
+		(void)nfsm_strtom(nd, version, strlen(version));
+		NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
+		verstime.tv_sec = 1293840000;		/* Jan 1, 2011 */
+		verstime.tv_nsec = 0;
+		txdr_nfsv4time(&verstime, tl);
+	}
+	NFSEXITCODE2(0, nd);
+	return (0);
+nfsmout:
+	if (clp != NULL) {
+		NFSSOCKADDRFREE(clp->lc_req.nr_nam);
+		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
+		free(clp, M_NFSDCLIENT);
+	}
+	NFSEXITCODE2(error, nd);
+	return (error);
+}
+
+/*
+ * nfsv4 create session service
+ */
+APPLESTATIC int
+nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
+    __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
+{
+	uint32_t *tl;
+	int error = 0;
+	nfsquad_t clientid, confirm;
+	struct nfsdsession *sep = NULL;
+	uint32_t rdmacnt;
+
+	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
+		nd->nd_repstat = NFSERR_WRONGSEC;
+		goto nfsmout;
+	}
+	sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
+	    M_NFSDSESSION, M_WAITOK | M_ZERO);
+	NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
+	clientid.lval[0] = *tl++;
+	clientid.lval[1] = *tl++;
+	confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
+	sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
+	/* Persistent sessions and RDMA are not supported. */
+	sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
+
+	/* Fore channel attributes. */
+	NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
+	tl++;					/* Header pad always 0. */
+	sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
+	sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
+	sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
+	sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
+	sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
+	if (sep->sess_maxslots > NFSV4_SLOTS)
+		sep->sess_maxslots = NFSV4_SLOTS;
+	rdmacnt = fxdr_unsigned(uint32_t, *tl);
+	if (rdmacnt > 1) {
+		nd->nd_repstat = NFSERR_BADXDR;
+		goto nfsmout;
+	} else if (rdmacnt == 1)
+		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+
+	/* Back channel attributes. */
+	NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
+	tl++;					/* Header pad always 0. */
+	sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
+	sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
+	sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
+	sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
+	sep->sess_cbmaxslots = fxdr_unsigned(uint32_t, *tl++);
+	rdmacnt = fxdr_unsigned(uint32_t, *tl);
+	if (rdmacnt > 1) {
+		nd->nd_repstat = NFSERR_BADXDR;
+		goto nfsmout;
+	} else if (rdmacnt == 1)
+		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+
+	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+	sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
+
+	/*
+	 * nfsrv_getclient() searches the client list for a match and
+	 * returns the appropriate NFSERR status.
+	 */
+	nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
+	    NULL, sep, confirm, sep->sess_cbprogram, nd, p);
+	if (nd->nd_repstat == 0) {
+		NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
+		NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
+		NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
+		*tl++ = txdr_unsigned(confirm.lval[0]);	/* sequenceid */
+		*tl++ = txdr_unsigned(sep->sess_crflags);
+
+		/* Fore channel attributes. */
+		*tl++ = 0;
+		*tl++ = txdr_unsigned(sep->sess_maxreq);
+		*tl++ = txdr_unsigned(sep->sess_maxresp);
+		*tl++ = txdr_unsigned(sep->sess_maxrespcached);
+		*tl++ = txdr_unsigned(sep->sess_maxops);
+		*tl++ = txdr_unsigned(sep->sess_maxslots);
+		*tl++ = txdr_unsigned(1);
+		*tl++ = txdr_unsigned(0);			/* No RDMA. */
+
+		/* Back channel attributes. */
+		*tl++ = 0;
+		*tl++ = txdr_unsigned(sep->sess_cbmaxreq);
+		*tl++ = txdr_unsigned(sep->sess_cbmaxresp);
+		*tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
+		*tl++ = txdr_unsigned(sep->sess_cbmaxops);
+		*tl++ = txdr_unsigned(sep->sess_cbmaxslots);
+		*tl++ = txdr_unsigned(1);
+		*tl = txdr_unsigned(0);			/* No RDMA. */
+	}
+nfsmout:
+	if (nd->nd_repstat != 0)
+		free(sep, M_NFSDSESSION);
+	NFSEXITCODE2(error, nd);
+	return (error);
+}
+
+/*
+ * nfsv4 sequence service
+ */
+APPLESTATIC int
+nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
+    __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
+{
+	uint32_t *tl;
+	uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
+	int cache_this, error = 0;
+
+	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
+		nd->nd_repstat = NFSERR_WRONGSEC;
+		goto nfsmout;
+	}
+	NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
+	NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
+	NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
+	sequenceid = fxdr_unsigned(uint32_t, *tl++);
+	nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
+	highest_slotid = fxdr_unsigned(uint32_t, *tl++);
+	if (*tl == newnfs_true)
+		cache_this = 1;
+	else
+		cache_this = 0;
+	nd->nd_flag |= ND_HASSEQUENCE;
+	nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
+	    &target_highest_slotid, cache_this, &sflags, p);
+	if (nd->nd_repstat == 0) {
+		NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
+		NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
+		NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
+		*tl++ = txdr_unsigned(sequenceid);
+		*tl++ = txdr_unsigned(nd->nd_slotid);
+		*tl++ = txdr_unsigned(highest_slotid);
+		*tl++ = txdr_unsigned(target_highest_slotid);
+		*tl = txdr_unsigned(sflags);
+	}
+nfsmout:
+	NFSEXITCODE2(error, nd);
+	return (error);
+}
+
+/*
+ * nfsv4 reclaim complete service
+ */
+APPLESTATIC int
+nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
+    __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
+{
+	uint32_t *tl;
+	int error = 0;
+
+	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
+		nd->nd_repstat = NFSERR_WRONGSEC;
+		goto nfsmout;
+	}
+	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+	if (*tl == newnfs_true)
+		nd->nd_repstat = NFSERR_NOTSUPP;
+	else
+		nd->nd_repstat = nfsrv_checkreclaimcomplete(nd);
+nfsmout:
+	NFSEXITCODE2(error, nd);
+	return (error);
+}
+
+/*
+ * nfsv4 destroy clientid service
+ */
+APPLESTATIC int
+nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
+    __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
+{
+	uint32_t *tl;
+	nfsquad_t clientid;
+	int error = 0;
+
+	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
+		nd->nd_repstat = NFSERR_WRONGSEC;
+		goto nfsmout;
+	}
+	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
+	clientid.lval[0] = *tl++;
+	clientid.lval[1] = *tl;
+	nd->nd_repstat = nfsrv_destroyclient(clientid, p);
+nfsmout:
+	NFSEXITCODE2(error, nd);
+	return (error);
+}
+
+/*
+ * nfsv4 destroy session service
+ */
+APPLESTATIC int
+nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
+    __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
+{
+	uint8_t *cp, sessid[NFSX_V4SESSIONID];
+	int error = 0;
+
+	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
+		nd->nd_repstat = NFSERR_WRONGSEC;
+		goto nfsmout;
+	}
+	NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
+	NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
+	nd->nd_repstat = nfsrv_destroysession(nd, sessid);
+nfsmout:
+	NFSEXITCODE2(error, nd);
+	return (error);
+}
+
+/*
+ * nfsv4 free stateid service
+ */
+APPLESTATIC int
+nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
+    __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
+{
+	uint32_t *tl;
+	nfsv4stateid_t stateid;
+	int error = 0;
+
+	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
+		nd->nd_repstat = NFSERR_WRONGSEC;
+		goto nfsmout;
+	}
+	NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
+	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
+	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
+	nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
+nfsmout:
+	NFSEXITCODE2(error, nd);
+	return (error);
+}
+
+/*
+ * nfsv4 service not supported
+ */
+APPLESTATIC int
+nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
+    __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
+{
+
+	nd->nd_repstat = NFSERR_NOTSUPP;
+	NFSEXITCODE2(0, nd);
+	return (0);
+}
+


More information about the svn-src-projects mailing list