Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 10 Dec 2011 02:06:11 +0000 (UTC)
From:      Rick Macklem <rmacklem@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r228385 - in projects/nfsv4.1-client/sys/fs: nfs nfsclient
Message-ID:  <201112100206.pBA26Bhh059411@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rmacklem
Date: Sat Dec 10 02:06:11 2011
New Revision: 228385
URL: http://svn.freebsd.org/changeset/base/228385

Log:
  Add the NFS client changes for a basic NFSv4.1 client. This
  includes support for sessions for both fore and back channels,
  creation of a ClientID the NFSv4.1 way and code that avoids
  using NFSv4.0 operations defined as "mandatory to not implement"
  for NFSv4.1. It includes handling of NFSv4.1 callbacks via
  a callback session. It does not include the new NFSv4.1 optional
  features like pNFS, but does allow the client to work with an
  NFSv4.1 server and creates the base on which pNFS can be implemented.
  The new operations are not counted in the nfsstats structure,
  since it needs to remain the same size, so that the nfsstats
  command will still work. It adds a new mount option called
  "minvers" which can be used to specify an NFSv4.1 mount.
  For example: "mount -t nfs -o nfsv4,minvers=1 <server>:/ /<path>
  Changes to sys/rpc are required before this will build/work.

Modified:
  projects/nfsv4.1-client/sys/fs/nfs/nfs.h
  projects/nfsv4.1-client/sys/fs/nfs/nfs_commonkrpc.c
  projects/nfsv4.1-client/sys/fs/nfs/nfs_commonsubs.c
  projects/nfsv4.1-client/sys/fs/nfs/nfs_var.h
  projects/nfsv4.1-client/sys/fs/nfs/nfsclstate.h
  projects/nfsv4.1-client/sys/fs/nfs/nfsport.h
  projects/nfsv4.1-client/sys/fs/nfs/nfsproto.h
  projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clcomsubs.c
  projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clkdtrace.c
  projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clkrpc.c
  projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clrpcops.c
  projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clstate.c
  projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clvfsops.c
  projects/nfsv4.1-client/sys/fs/nfsclient/nfsmount.h

Modified: projects/nfsv4.1-client/sys/fs/nfs/nfs.h
==============================================================================
--- projects/nfsv4.1-client/sys/fs/nfs/nfs.h	Sat Dec 10 01:44:24 2011	(r228384)
+++ projects/nfsv4.1-client/sys/fs/nfs/nfs.h	Sat Dec 10 02:06:11 2011	(r228385)
@@ -50,6 +50,7 @@
 #define	NFS_MAXREXMIT	100		/* Stop counting after this many */
 #define	NFSV4_CALLBACKTIMEO (2 * NFS_HZ) /* Timeout in ticks */
 #define	NFSV4_CALLBACKRETRY 5		/* Number of retries before failure */
+#define	NFSV4_CBSLOTS	8		/* Number of slots for session */
 #define	NFSV4_CBRETRYCNT 4		/* # of CBRecall retries upon err */
 #define	NFSV4_UPCALLTIMEO (15 * NFS_HZ)	/* Timeout in ticks for upcalls */
 					/* to gssd or nfsuserd */
@@ -529,6 +530,7 @@ struct nfsrv_descript {
 	nfsquad_t		nd_clientid;	/* Implied clientid */
 	int			nd_gssnamelen;	/* principal name length */
 	char			*nd_gssname;	/* principal name */
+	uint32_t		*nd_slotseq;	/* ptr to slot seq# in req */
 };
 
 #define	nd_princlen	nd_gssnamelen
@@ -559,6 +561,8 @@ struct nfsrv_descript {
 #define	ND_EXGSSINTEGRITY	0x00200000
 #define	ND_EXGSSPRIVACY		0x00400000
 #define	ND_INCRSEQID		0x00800000
+#define	ND_NFSV41		0x01000000
+#define	ND_HASSEQUENCE		0x02000000
 
 /*
  * ND_GSS should be the "or" of all GSS type authentications.
@@ -571,6 +575,7 @@ struct nfsv4_opflag {
 	int	savereply;
 	int	modifyfs;
 	int	lktype;
+	int	needsseq;
 };
 
 /*
@@ -644,6 +649,15 @@ struct nfsv4lock {
 #define	NFSACCCHK_VPNOTLOCKED		0
 #define	NFSACCCHK_VPISLOCKED		1
 
+/*
+ * Slot for the NFSv4.1 Sequence Op.
+ */
+struct nfsslot {
+	int		nfssl_inprog;
+	uint32_t	nfssl_seq;
+	struct mbuf	*nfssl_reply;
+};
+
 #endif	/* _KERNEL */
 
 #endif	/* _NFS_NFS_H */

Modified: projects/nfsv4.1-client/sys/fs/nfs/nfs_commonkrpc.c
==============================================================================
--- projects/nfsv4.1-client/sys/fs/nfs/nfs_commonkrpc.c	Sat Dec 10 01:44:24 2011	(r228384)
+++ projects/nfsv4.1-client/sys/fs/nfs/nfs_commonkrpc.c	Sat Dec 10 02:06:11 2011	(r228385)
@@ -77,23 +77,26 @@ dtrace_nfsclient_nfs23_done_probe_func_t
 /*
  * Registered probes by RPC type.
  */
-uint32_t	nfscl_nfs2_start_probes[NFS_NPROCS + 1];
-uint32_t	nfscl_nfs2_done_probes[NFS_NPROCS + 1];
+uint32_t	nfscl_nfs2_start_probes[NFSV41_NPROCS + 1];
+uint32_t	nfscl_nfs2_done_probes[NFSV41_NPROCS + 1];
 
-uint32_t	nfscl_nfs3_start_probes[NFS_NPROCS + 1];
-uint32_t	nfscl_nfs3_done_probes[NFS_NPROCS + 1];
+uint32_t	nfscl_nfs3_start_probes[NFSV41_NPROCS + 1];
+uint32_t	nfscl_nfs3_done_probes[NFSV41_NPROCS + 1];
 
-uint32_t	nfscl_nfs4_start_probes[NFS_NPROCS + 1];
-uint32_t	nfscl_nfs4_done_probes[NFS_NPROCS + 1];
+uint32_t	nfscl_nfs4_start_probes[NFSV41_NPROCS + 1];
+uint32_t	nfscl_nfs4_done_probes[NFSV41_NPROCS + 1];
 #endif
 
 NFSSTATESPINLOCK;
 NFSREQSPINLOCK;
+NFSDLOCKMUTEX;
 extern struct nfsstats newnfsstats;
 extern struct nfsreqhead nfsd_reqq;
 extern int nfscl_ticks;
 extern void (*ncl_call_invalcaches)(struct vnode *);
+extern int nfs_numnfscbd;
 
+SVCPOOL		*nfscbd_pool;
 static int	nfsrv_gsscallbackson = 0;
 static int	nfs_bufpackets = 4;
 static int	nfs_reconnects;
@@ -168,6 +171,7 @@ newnfs_connect(struct nfsmount *nmp, str
 	struct socket *so;
 	int one = 1, retries, error = 0;
 	struct thread *td = curthread;
+	SVCXPRT *xprt;
 
 	/*
 	 * We need to establish the socket using the credentials of
@@ -268,6 +272,24 @@ newnfs_connect(struct nfsmount *nmp, str
 			retries = nmp->nm_retry;
 		else
 			retries = INT_MAX;
+		if (NFSHASNFSV4N(nmp)) {
+			/*
+			 * Make sure the nfscbd_pool doesn't get destroyed
+			 * while doing this.
+			 */
+			NFSD_LOCK();
+			if (nfs_numnfscbd > 0) {
+				nfs_numnfscbd++;
+				NFSD_UNLOCK();
+				xprt = svc_vc_create_backchannel(nfscbd_pool);
+				CLNT_CONTROL(client, CLSET_BACKCHANNEL, xprt);
+				NFSD_LOCK();
+				nfs_numnfscbd--;
+				if (nfs_numnfscbd == 0)
+					wakeup(&nfs_numnfscbd);
+			}
+			NFSD_UNLOCK();
+		}
 	} else {
 		/*
 		 * Three cases:
@@ -440,9 +462,9 @@ newnfs_request(struct nfsrv_descript *nd
     struct thread *td, struct ucred *cred, u_int32_t prog, u_int32_t vers,
     u_char *retsum, int toplevel, u_int64_t *xidp)
 {
-	u_int32_t *tl;
+	u_int32_t retseq, retval, *tl;
 	time_t waituntil;
-	int i, j, set_uid = 0, set_sigset = 0;
+	int i = 0, j = 0, opcnt, set_uid = 0, set_sigset = 0, slot, freeslot;
 	int trycnt, error = 0, usegssname = 0, secflavour = AUTH_SYS;
 	u_int16_t procnum;
 	u_int trylater_delay = 1;
@@ -627,7 +649,9 @@ newnfs_request(struct nfsrv_descript *nd
 #endif
 	}
 	trycnt = 0;
+	freeslot = -1;		/* Set to slot that needs to be free'd */
 tryagain:
+	slot = -1;		/* Slot that needs a sequence# increment. */
 	if (nmp == NULL) {
 		timo.tv_usec = 0;
 		if (clp == NULL)
@@ -714,6 +738,81 @@ tryagain:
 		 */
 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 		nd->nd_repstat = fxdr_unsigned(u_int32_t, *tl);
+if (nd->nd_repstat >= 10000) printf("proc=%d reps=%d\n",nd->nd_procnum,nd->nd_repstat);
+
+		/*
+		 * Get rid of the tag, return count and SEQUENCE result for
+		 * NFSv4.
+		 */
+		if ((nd->nd_flag & ND_NFSV4) != 0) {
+			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+			i = fxdr_unsigned(int, *tl);
+			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
+			if (error)
+				goto nfsmout;
+			NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
+			opcnt = fxdr_unsigned(int, *tl++);
+			i = fxdr_unsigned(int, *tl++);
+			j = fxdr_unsigned(int, *tl);
+if (j >= 10000) printf("fop=%d fst=%d\n",i,j);
+			/*
+			 * If the first op is Sequence, free up the slot.
+			 */
+if (nmp != NULL && i == NFSV4OP_SEQUENCE && j != 0) printf("failed seq=%d\n", j);
+			if (nmp != NULL && i == NFSV4OP_SEQUENCE && j == 0) {
+				NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID +
+				    5 * NFSX_UNSIGNED);
+				NFSLOCKMNT(nmp);
+				tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
+				retseq = fxdr_unsigned(uint32_t, *tl++);
+				slot = fxdr_unsigned(int, *tl++);
+				freeslot = slot;
+				if (retseq != nmp->nm_slotseq[slot])
+					printf("retseq diff 0x%x\n", retseq);
+				retval = fxdr_unsigned(uint32_t, *++tl);
+#ifdef notyet
+				if ((retval + 1) < nmp->nm_foreslots)
+					nmp->nm_foreslots = (retval + 1);
+				else if ((retval + 1) > nmp->nm_foreslots)
+					nmp->nm_foreslots = (retval < 64) ?
+					    (retval + 1) : 64;
+#else
+				/*
+				 * There seems to be some confusion with
+				 * respect to whether this value is the
+				 * largest slot number to be used, numbered
+				 * 0<->N-1 or the size of the slot table.
+				 * In other words, is it N or N-1?
+				 * For now, play it safe and assume the
+				 * worst cases of the above, such that
+				 * nm_foreslots might be one less than the
+				 * server specified. This is safe, whereas
+				 * setting nm_foreslots one greater than
+				 * the server intended could cause grief.
+				 */
+				if (retval < nmp->nm_foreslots)
+{
+printf("foreslots shrinking %d\n", retval);
+					nmp->nm_foreslots = retval;
+}
+				else if (retval > nmp->nm_foreslots)
+{
+printf("foreslots growing %d\n", retval);
+					nmp->nm_foreslots = (retval < 64) ?
+					    retval : 64;
+}
+#endif	/* notyet */
+				NFSUNLOCKMNT(nmp);
+
+				/* Grab the op and status for the next one. */
+				if (opcnt > 1) {
+					NFSM_DISSECT(tl, uint32_t *,
+					    2 * NFSX_UNSIGNED);
+					i = fxdr_unsigned(int, *tl++);
+					j = fxdr_unsigned(int, *tl);
+				}
+			}
+		}
 		if (nd->nd_repstat != 0) {
 			if (((nd->nd_repstat == NFSERR_DELAY ||
 			      nd->nd_repstat == NFSERR_GRACE) &&
@@ -738,6 +837,13 @@ tryagain:
 				while (NFSD_MONOSEC < waituntil)
 					(void) nfs_catnap(PZERO, 0, "nfstry");
 				trylater_delay *= 2;
+				if (slot != -1) {
+					NFSLOCKMNT(nmp);
+					nmp->nm_slotseq[slot]++;
+					*nd->nd_slotseq = txdr_unsigned(
+					    nmp->nm_slotseq[slot]);
+					NFSUNLOCKMNT(nmp);
+				}
 				m_freem(nd->nd_mrep);
 				nd->nd_mrep = NULL;
 				goto tryagain;
@@ -754,34 +860,19 @@ tryagain:
 					(*ncl_call_invalcaches)(vp);
 			}
 		}
-
-		/*
-		 * Get rid of the tag, return count, and PUTFH result for V4.
-		 */
-		if (nd->nd_flag & ND_NFSV4) {
-			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
-			i = fxdr_unsigned(int, *tl);
-			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
-			if (error)
-				goto nfsmout;
-			NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
-			i = fxdr_unsigned(int, *++tl);
-
-			/*
-			 * If the first op's status is non-zero, mark that
-			 * there is no more data to process.
-			 */
-			if (*++tl)
-				nd->nd_flag |= ND_NOMOREDATA;
-
+		if ((nd->nd_flag & ND_NFSV4) != 0) {
+			/* Free the slot, as required. */
+			if (freeslot != -1)
+				nfscl_freeslot(nmp, freeslot);
 			/*
-			 * If the first op is Putfh, throw its results away
-			 * and toss the op# and status for the first op.
+			 * If this op is Putfh, throw its results away.
 			 */
-			if (nmp != NULL && i == NFSV4OP_PUTFH && *tl == 0) {
+if (j >= 10000) printf("nop=%d nst=%d\n",i,j);
+			if (nmp != NULL && i == NFSV4OP_PUTFH && j == 0) {
 				NFSM_DISSECT(tl,u_int32_t *,2 * NFSX_UNSIGNED);
 				i = fxdr_unsigned(int, *tl++);
 				j = fxdr_unsigned(int, *tl);
+if (j >= 10000) printf("n2op=%d n2st=%d\n",i,j);
 				/*
 				 * All Compounds that do an Op that must
 				 * be in sequence consist of NFSV4OP_PUTFH
@@ -804,13 +895,13 @@ tryagain:
 				      j != NFSERR_RESOURCE &&
 				      j != NFSERR_NOFILEHANDLE)))		 
 					nd->nd_flag |= ND_INCRSEQID;
-				/*
-				 * If the first op's status is non-zero, mark
-				 * that there is no more data to process.
-				 */
-				if (j)
-					nd->nd_flag |= ND_NOMOREDATA;
 			}
+			/*
+			 * If this op's status is non-zero, mark
+			 * that there is no more data to process.
+			 */
+			if (j)
+				nd->nd_flag |= ND_NOMOREDATA;
 
 			/*
 			 * If R_DONTRECOVER is set, replace the stale error

Modified: projects/nfsv4.1-client/sys/fs/nfs/nfs_commonsubs.c
==============================================================================
--- projects/nfsv4.1-client/sys/fs/nfs/nfs_commonsubs.c	Sat Dec 10 01:44:24 2011	(r228384)
+++ projects/nfsv4.1-client/sys/fs/nfs/nfs_commonsubs.c	Sat Dec 10 02:06:11 2011	(r228385)
@@ -83,47 +83,66 @@ NFSSOCKMUTEX;
  * non-idempotent Ops.
  * Define it here, since it is used by both the client and server.
  */
-struct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS] = {
-	{ 0, 0, 0, 0, LK_EXCLUSIVE },		/* undef */
-	{ 0, 0, 0, 0, LK_EXCLUSIVE },		/* undef */
-	{ 0, 0, 0, 0, LK_EXCLUSIVE },		/* undef */
-	{ 0, 1, 0, 0, LK_SHARED },		/* Access */
-	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* Close */
-	{ 0, 2, 0, 1, LK_EXCLUSIVE },		/* Commit */
-	{ 1, 2, 1, 1, LK_EXCLUSIVE },		/* Create */
-	{ 0, 0, 0, 0, LK_EXCLUSIVE },		/* Delegpurge */
-	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* Delegreturn */
-	{ 0, 1, 0, 0, LK_SHARED },		/* Getattr */
-	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* GetFH */
-	{ 2, 1, 1, 1, LK_EXCLUSIVE },		/* Link */
-	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* Lock */
-	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* LockT */
-	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* LockU */
-	{ 1, 1, 0, 0, LK_EXCLUSIVE },		/* Lookup */
-	{ 1, 1, 0, 0, LK_EXCLUSIVE },		/* Lookupp */
-	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* NVerify */
-	{ 1, 1, 0, 1, LK_EXCLUSIVE },		/* Open */
-	{ 1, 1, 0, 0, LK_EXCLUSIVE },		/* OpenAttr */
-	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* OpenConfirm */
-	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* OpenDowngrade */
-	{ 1, 0, 0, 0, LK_EXCLUSIVE },		/* PutFH */
-	{ 1, 0, 0, 0, LK_EXCLUSIVE },		/* PutPubFH */
-	{ 1, 0, 0, 0, LK_EXCLUSIVE },		/* PutRootFH */
-	{ 0, 1, 0, 0, LK_SHARED },		/* Read */
-	{ 0, 1, 0, 0, LK_SHARED },		/* Readdir */
-	{ 0, 1, 0, 0, LK_SHARED },		/* ReadLink */
-	{ 0, 2, 1, 1, LK_EXCLUSIVE },		/* Remove */
-	{ 2, 1, 1, 1, LK_EXCLUSIVE },		/* Rename */
-	{ 0, 0, 0, 0, LK_EXCLUSIVE },		/* Renew */
-	{ 0, 0, 0, 0, LK_EXCLUSIVE },		/* RestoreFH */
-	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* SaveFH */
-	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* SecInfo */
-	{ 0, 2, 1, 1, LK_EXCLUSIVE },		/* Setattr */
-	{ 0, 0, 0, 0, LK_EXCLUSIVE },		/* SetClientID */
-	{ 0, 0, 0, 0, LK_EXCLUSIVE },		/* SetClientIDConfirm */
-	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* Verify */
-	{ 0, 2, 1, 1, LK_EXCLUSIVE },		/* Write */
-	{ 0, 0, 0, 0, LK_EXCLUSIVE },		/* ReleaseLockOwner */
+struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* undef */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* undef */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* undef */
+	{ 0, 1, 0, 0, LK_SHARED, 1 },			/* Access */
+	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* Close */
+	{ 0, 2, 0, 1, LK_EXCLUSIVE, 1 },		/* Commit */
+	{ 1, 2, 1, 1, LK_EXCLUSIVE, 1 },		/* Create */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Delegpurge */
+	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* Delegreturn */
+	{ 0, 1, 0, 0, LK_SHARED, 1 },			/* Getattr */
+	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* GetFH */
+	{ 2, 1, 1, 1, LK_EXCLUSIVE, 1 },		/* Link */
+	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* Lock */
+	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* LockT */
+	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* LockU */
+	{ 1, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* Lookup */
+	{ 1, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* Lookupp */
+	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* NVerify */
+	{ 1, 1, 0, 1, LK_EXCLUSIVE, 1 },		/* Open */
+	{ 1, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* OpenAttr */
+	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* OpenConfirm */
+	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* OpenDowngrade */
+	{ 1, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* PutFH */
+	{ 1, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* PutPubFH */
+	{ 1, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* PutRootFH */
+	{ 0, 1, 0, 0, LK_SHARED, 1 },			/* Read */
+	{ 0, 1, 0, 0, LK_SHARED, 1 },			/* Readdir */
+	{ 0, 1, 0, 0, LK_SHARED, 1 },			/* ReadLink */
+	{ 0, 2, 1, 1, LK_EXCLUSIVE, 1 },		/* Remove */
+	{ 2, 1, 1, 1, LK_EXCLUSIVE, 1 },		/* Rename */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Renew */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* RestoreFH */
+	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* SaveFH */
+	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* SecInfo */
+	{ 0, 2, 1, 1, LK_EXCLUSIVE, 1 },		/* Setattr */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* SetClientID */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* SetClientIDConfirm */
+	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1 },		/* Verify */
+	{ 0, 2, 1, 1, LK_EXCLUSIVE, 1 },		/* Write */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* ReleaseLockOwner */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Backchannel Ctrl */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Bind Conn to Sess */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0 },		/* Exchange ID */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0 },		/* Create Session */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0 },		/* Destroy Session */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Free StateID */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Get Dir Deleg */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Get Device Info */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Get Device List */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Layout Commit */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Layout Get */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Layout Return */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Secinfo No name */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Sequence */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Set SSV */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Test StateID */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Want Delegation */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0 },		/* Destroy ClientID */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1 },		/* Reclaim Complete */
 };
 #endif	/* !APPLEKEXT */
 
@@ -145,9 +164,9 @@ static struct nfsuserlruhead nfsuserlruh
  * marked 0 in this array, the code will still work, just not quite as
  * efficiently.)
  */
-static int nfs_bigreply[NFS_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
+int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0 };
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
 /* local functions */
 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
@@ -1855,7 +1874,7 @@ nfsv4_getref(struct nfsv4lock *lp, int *
 		if (isleptp)
 			*isleptp = 1;
 		(void) nfsmsleep(&lp->nfslock_lock, mutex,
-		    PZERO - 1, "nfsv4lck", NULL);
+		    PZERO - 1, "nfsv4gr", NULL);
 	}
 	if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
 		return;
@@ -3478,3 +3497,47 @@ newnfs_sndunlock(int *flagp)
 	NFSUNLOCKSOCK();
 }
 
+/*
+ * Handle an NFSv4.1 Sequence request for the session.
+ */
+int
+nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
+    struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
+{
+	int error;
+
+	error = 0;
+	*reply = NULL;
+	if (slotid > maxslot)
+		return (NFSERR_BADSLOT);
+	if (seqid == slots[slotid].nfssl_seq) {
+		/* A retry. */
+		if (slots[slotid].nfssl_inprog != 0)
+			error = NFSERR_DELAY;
+		else if (slots[slotid].nfssl_reply != NULL) {
+			*reply = slots[slotid].nfssl_reply;
+			slots[slotid].nfssl_reply = NULL;
+			slots[slotid].nfssl_inprog = 1;
+		} else
+			error = NFSERR_SEQMISORDERED;
+	} else if ((slots[slotid].nfssl_seq + 1) == seqid) {
+		m_freem(slots[slotid].nfssl_reply);
+		slots[slotid].nfssl_reply = NULL;
+		slots[slotid].nfssl_inprog = 1;
+		slots[slotid].nfssl_seq++;
+	} else
+		error = NFSERR_SEQMISORDERED;
+	return (error);
+}
+
+/*
+ * Cache this reply for the slot.
+ */
+void
+nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, struct mbuf *rep)
+{
+
+	slots[slotid].nfssl_reply = rep;
+	slots[slotid].nfssl_inprog = 0;
+}
+

Modified: projects/nfsv4.1-client/sys/fs/nfs/nfs_var.h
==============================================================================
--- projects/nfsv4.1-client/sys/fs/nfs/nfs_var.h	Sat Dec 10 01:44:24 2011	(r228384)
+++ projects/nfsv4.1-client/sys/fs/nfs/nfs_var.h	Sat Dec 10 02:06:11 2011	(r228385)
@@ -257,6 +257,9 @@ int nfsrv_mtostr(struct nfsrv_descript *
 int nfsrv_checkutf8(u_int8_t *, int);
 int newnfs_sndlock(int *);
 void newnfs_sndunlock(int *);
+int nfsv4_seqsession(uint32_t, uint32_t, uint32_t, struct nfsslot *,
+    struct mbuf **, uint16_t);
+void nfsv4_seqsess_cacherep(uint32_t, struct nfsslot *, struct mbuf *);
 
 /* nfs_clcomsubs.c */
 void nfsm_uiombuf(struct nfsrv_descript *, struct uio *, int);
@@ -362,7 +365,7 @@ int nfsrpc_setclient(struct nfsmount *, 
 int nfsrpc_getattr(vnode_t, struct ucred *, NFSPROC_T *,
     struct nfsvattr *, void *);
 int nfsrpc_getattrnovp(struct nfsmount *, u_int8_t *, int, int,
-    struct ucred *, NFSPROC_T *, struct nfsvattr *, u_int64_t *);
+    struct ucred *, NFSPROC_T *, struct nfsvattr *, u_int64_t *, uint32_t *);
 int nfsrpc_setattr(vnode_t, struct vattr *, NFSACL_T *, struct ucred *,
     NFSPROC_T *, struct nfsvattr *, int *, void *);
 int nfsrpc_lookup(vnode_t, char *, int, struct ucred *, NFSPROC_T *,
@@ -426,6 +429,14 @@ int nfsrpc_delegreturn(struct nfscldeleg
     struct nfsmount *, NFSPROC_T *, int);
 int nfsrpc_getacl(vnode_t, struct ucred *, NFSPROC_T *, NFSACL_T *, void *);
 int nfsrpc_setacl(vnode_t, struct ucred *, NFSPROC_T *, NFSACL_T *, void *);
+int nfsrpc_exchangeid(struct nfsmount *, struct nfsclclient *,
+    struct ucred *, NFSPROC_T *);
+int nfsrpc_createsession(struct nfsmount *, struct nfsclclient *,
+    struct ucred *, NFSPROC_T *);
+int nfsrpc_destroysession(struct nfsmount *, struct nfsclclient *,
+    struct ucred *, NFSPROC_T *);
+int nfsrpc_destroyclient(struct nfsmount *, struct nfsclclient *,
+    struct ucred *, NFSPROC_T *);
 
 /* nfs_clstate.c */
 int nfscl_open(vnode_t, u_int8_t *, int, u_int32_t, int,
@@ -435,7 +446,7 @@ int nfscl_getstateid(vnode_t, u_int8_t *
     NFSPROC_T *, nfsv4stateid_t *, void **);
 void nfscl_ownerrelease(struct nfsclowner *, int, int, int);
 void nfscl_openrelease(struct nfsclopen *, int, int);
-int nfscl_getcl(vnode_t, struct ucred *, NFSPROC_T *,
+int nfscl_getcl(struct mount *, struct ucred *, NFSPROC_T *, int,
     struct nfsclclient **);
 struct nfsclclient *nfscl_findcl(struct nfsmount *);
 void nfscl_clientrelease(struct nfsclclient *);
@@ -487,6 +498,8 @@ void nfscl_deleggetmodtime(vnode_t, stru
 int nfscl_tryclose(struct nfsclopen *, struct ucred *,
     struct nfsmount *, NFSPROC_T *);
 void nfscl_cleanup(NFSPROC_T *);
+void nfscl_setsequence(struct nfsrv_descript *, struct nfsmount *, int);
+void nfscl_freeslot(struct nfsmount *, int);
 
 /* nfs_clport.c */
 int nfscl_nget(mount_t, vnode_t, struct nfsfh *,

Modified: projects/nfsv4.1-client/sys/fs/nfs/nfsclstate.h
==============================================================================
--- projects/nfsv4.1-client/sys/fs/nfs/nfsclstate.h	Sat Dec 10 01:44:24 2011	(r228384)
+++ projects/nfsv4.1-client/sys/fs/nfs/nfsclstate.h	Sat Dec 10 02:06:11 2011	(r228385)
@@ -50,6 +50,8 @@ struct nfsclclient {
 	struct nfscldeleghead	nfsc_deleg;
 	struct nfscldeleghash	nfsc_deleghash[NFSCLDELEGHASHSIZE];
 	struct nfsv4lock nfsc_lock;
+	struct	nfsslot nfsc_cbslots[NFSV4_CBSLOTS]; /* NFSv4.1 cb slot table */
+	uint8_t	nfsc_sessionid[NFSX_V4SESSIONID]; /* NFSv4.1 session id */
 	struct proc	*nfsc_renewthread;
 	struct nfsmount	*nfsc_nmp;
 	nfsquad_t	nfsc_clientid;
@@ -58,6 +60,7 @@ struct nfsclclient {
 	u_int32_t	nfsc_renew;
 	u_int32_t	nfsc_cbident;
 	u_int16_t	nfsc_flags;
+	u_int16_t	nfsc_backslots;	/* Number of back channel slots. */
 	u_int16_t	nfsc_idlen;
 	u_int8_t	nfsc_id[1];	/* Malloc'd to correct length */
 };

Modified: projects/nfsv4.1-client/sys/fs/nfs/nfsport.h
==============================================================================
--- projects/nfsv4.1-client/sys/fs/nfs/nfsport.h	Sat Dec 10 01:44:24 2011	(r228384)
+++ projects/nfsv4.1-client/sys/fs/nfs/nfsport.h	Sat Dec 10 02:06:11 2011	(r228385)
@@ -229,6 +229,34 @@
  */
 #define	NFSV4OP_NOPS		40
 
+/*
+ * Additional Ops for NFSv4.1.
+ */
+#define	NFSV4OP_BACKCHANNELCTL	40
+#define	NFSV4OP_BINDCONNTOSESS	41
+#define	NFSV4OP_EXCHANGEID	42
+#define	NFSV4OP_CREATESESSION	43
+#define	NFSV4OP_DESTROYSESSION	44
+#define	NFSV4OP_FREESTATEID	45
+#define	NFSV4OP_GETDIRDELEG	46
+#define	NFSV4OP_GETDEVINFO	47
+#define	NFSV4OP_GETDEVLIST	48
+#define	NFSV4OP_LAYOUTCOMMIT	49
+#define	NFSV4OP_LAYOUTGET	50
+#define	NFSV4OP_LAYOUTRETURN	51
+#define	NFSV4OP_SECINFONONAME	52
+#define	NFSV4OP_SEQUENCE	53
+#define	NFSV4OP_SETSSV		54
+#define	NFSV4OP_TESTSTATEID	55
+#define	NFSV4OP_WANTDELEG	56
+#define	NFSV4OP_DESTROYCLIENTID	57
+#define	NFSV4OP_RECLAIMCOMPL	58
+
+/*
+ * Must be one more than last op#.
+ */
+#define	NFSV41_NOPS		59
+
 /* Quirky case if the illegal op code */
 #define	NFSV4OP_OPILLEGAL	10044
 
@@ -262,6 +290,20 @@
 #define	NFSV4OP_CBNOPS		5
 
 /*
+ * Additional Callback Ops for NFSv4.1 only. Not yet in nfsstats.
+ */
+#define	NFSV4OP_CBLAYOUTRECALL	5
+#define	NFSV4OP_CBNOTIFY	6
+#define	NFSV4OP_CBPUSHDELEG	7
+#define	NFSV4OP_CBRECALLANY	8
+#define	NFSV4OP_CBRECALLOBJAVAIL 9
+#define	NFSV4OP_CBRECALLSLOT	10
+#define	NFSV4OP_CBSEQUENCE	11
+#define	NFSV4OP_CBWANTCANCELLED	12
+#define	NFSV4OP_CBNOTIFYLOCK	13
+#define	NFSV4OP_CBNOTIFYDEVID	14
+
+/*
  * The lower numbers -> 21 are used by NFSv2 and v3. These define higher
  * numbers used by NFSv4.
  * NFS_V3NPROCS is one greater than the last V3 op and NFS_NPROCS is
@@ -294,6 +336,19 @@
  * Must be defined as one higher than the last Proc# above.
  */
 #define	NFSV4_NPROCS		41
+
+/* Additional procedures for NFSv4.1. */
+#define	NFSPROC_EXCHANGEID	41
+#define	NFSPROC_CREATESESSION	42
+#define	NFSPROC_DESTROYSESSION	43
+#define	NFSPROC_DESTROYCLIENT	44
+#define	NFSPROC_FREESTATEID	45
+
+/*
+ * Must be defined as one higher than the last NFSv4.1 Proc# above.
+ */
+#define	NFSV41_NPROCS		46
+
 #endif	/* NFS_V3NPROCS */
 
 /*
@@ -766,6 +821,7 @@ void newnfs_realign(struct mbuf **);
 
 #define	NFSHASNFSV3(n)		((n)->nm_flag & NFSMNT_NFSV3)
 #define	NFSHASNFSV4(n)		((n)->nm_flag & NFSMNT_NFSV4)
+#define	NFSHASNFSV4N(n)		((n)->nm_minorvers > 0)
 #define	NFSHASNFSV3OR4(n)	((n)->nm_flag & (NFSMNT_NFSV3 | NFSMNT_NFSV4))
 #define	NFSHASGOTFSINFO(n)	((n)->nm_state & NFSSTA_GOTFSINFO)
 #define	NFSHASHASSETFSID(n)	((n)->nm_state & NFSSTA_HASSETFSID)

Modified: projects/nfsv4.1-client/sys/fs/nfs/nfsproto.h
==============================================================================
--- projects/nfsv4.1-client/sys/fs/nfs/nfsproto.h	Sat Dec 10 01:44:24 2011	(r228384)
+++ projects/nfsv4.1-client/sys/fs/nfs/nfsproto.h	Sat Dec 10 02:06:11 2011	(r228385)
@@ -62,7 +62,9 @@
 #define	NFS_MINPACKET	20
 #define	NFS_FABLKSIZE	512	/* Size in bytes of a block wrt fa_blocks */
 #define	NFSV4_MINORVERSION	0	/* V4 Minor version */
+#define	NFSV41_MINORVERSION	1	/* V4 Minor version */
 #define	NFSV4_CBVERS		1	/* V4 CB Version */
+#define	NFSV41_CBVERS		4	/* V4.1 CB Version */
 #define	NFSV4_SMALLSTR	50		/* Strings small enough for stack */
 
 /* Stat numbers for rpc returns (version 2, 3 and 4) */
@@ -145,6 +147,12 @@
 #define	NFSERR_ADMINREVOKED	10047
 #define	NFSERR_CBPATHDOWN	10048
 
+/* NFSv4.1 specific errors. */
+#define	NFSERR_BADSLOT		10053
+#define	NFSERR_SEQMISORDERED	10063
+#define	NFSERR_SEQUENCEPOS	10064
+#define	NFSERR_OPNOTINSESS	10071
+
 #define	NFSERR_STALEWRITEVERF	30001	/* Fake return for nfs_commit() */
 #define	NFSERR_DONTREPLY	30003	/* Don't process request */
 #define	NFSERR_RETVOID		30004	/* Return void, not error */
@@ -189,6 +197,7 @@
 #define	NFSX_V4SPECDATA		(2 * NFSX_UNSIGNED)
 #define	NFSX_V4TIME		(NFSX_HYPER + NFSX_UNSIGNED)
 #define	NFSX_V4SETTIME		(NFSX_UNSIGNED + NFSX_V4TIME)
+#define	NFSX_V4SESSIONID	16
 
 /* sizes common to multiple NFS versions */
 #define	NFSX_FHMAX		(NFSX_V4FHMAX)
@@ -258,6 +267,19 @@
  * Must be defined as one higher than the last Proc# above.
  */
 #define	NFSV4_NPROCS		41
+
+/* Additional procedures for NFSv4.1. */
+#define	NFSPROC_EXCHANGEID	41
+#define	NFSPROC_CREATESESSION	42
+#define	NFSPROC_DESTROYSESSION	43
+#define	NFSPROC_DESTROYCLIENT	44
+#define	NFSPROC_FREESTATEID	45
+
+/*
+ * Must be defined as one higher than the last NFSv4.1 Proc# above.
+ */
+#define	NFSV41_NPROCS		46
+
 #endif	/* NFS_V3NPROCS */
 
 /*
@@ -269,10 +291,10 @@
 
 /*
  * NFSPROC_NOOP is a fake op# that can't be the same as any V2/3/4 Procedure
- * or Operation#. Since the NFS V4 Op #s go higher, use NFSV4OP_NOPS, which
+ * or Operation#. Since the NFS V4 Op #s go higher, use NFSV41_NOPS, which
  * is one greater than the highest Op#.
  */
-#define	NFSPROC_NOOP		NFSV4OP_NOPS
+#define	NFSPROC_NOOP		NFSV41_NOPS
 
 /* Actual Version 2 procedure numbers */
 #define	NFSV2PROC_NULL		0
@@ -468,6 +490,42 @@
 #define	NFSV3FSINFO_HOMOGENEOUS		0x08
 #define	NFSV3FSINFO_CANSETTIME		0x10
 
+/* Flags for Exchange ID */
+#define	NFSV4EXCH_SUPPMOVEDREFER	0x00000001
+#define	NFSV4EXCH_SUPPMOVEDMIGR	0x00000002
+#define	NFSV4EXCH_BINDPRINCSTATEID	0x00000100
+#define	NFSV4EXCH_USENONPNFS		0x00010000
+#define	NFSV4EXCH_USEPNFSMDS		0x00020000
+#define	NFSV4EXCH_USEPNFSDS		0x00040000
+#define	NFSV4EXCH_MASKPNFS		0x00070000
+#define	NFSV4EXCH_UPDCONFIRMEDRECA	0x40000000
+#define	NFSV4EXCH_CONFIRMEDR		0x80000000
+
+/* State Protects */
+#define	NFSV4EXCH_SP4NONE		0
+#define	NFSV4EXCH_SP4MACHCRED		1
+#define	NFSV4EXCH_SP4SSV		2
+
+/* Flags for Create Session */
+#define	NFSV4CRSESS_PERSIST		0x00000001
+#define	NFSV4CRSESS_CONNBACKCHAN	0x00000002
+#define	NFSV4CRSESS_CONNRDMA		0x00000004
+
+/* Flags for Sequence */
+#define	NFSV4SEQ_CBPATHDOWN		0x00000001
+#define	NFSV4SEQ_CBGSSCONTEXPIRING	0x00000002
+#define	NFSV4SEQ_CBGSSCONTEXPIRED	0x00000004
+#define	NFSV4SEQ_EXPIREDALLSTATEREVOKED	0x00000008
+#define	NFSV4SEQ_EXPIREDSOMESTATEREVOKED 0x00000010
+#define	NFSV4SEQ_ADMINSTATEREVOKED	0x00000020
+#define	NFSV4SEQ_RECALLABLESTATEREVOKED	0x00000040
+#define	NFSV4SEQ_LEASEMOVED		0x00000080
+#define	NFSV4SEQ_RESTARTRECLAIMNEEDED	0x00000100
+#define	NFSV4SEQ_CBPATHDOWNSESSION	0x00000200
+#define	NFSV4SEQ_BACKCHANNELFAULT	0x00000400
+#define	NFSV4SEQ_DEVIDCHANGED		0x00000800
+#define	NFSV4SEQ_DEVIDDELETED		0x00001000
+
 /* Conversion macros */
 #define	vtonfsv2_mode(t,m) 						\
 		txdr_unsigned(((t) == VFIFO) ? MAKEIMODE(VCHR, (m)) : 	\

Modified: projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clcomsubs.c
==============================================================================
--- projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clcomsubs.c	Sat Dec 10 01:44:24 2011	(r228384)
+++ projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clcomsubs.c	Sat Dec 10 02:06:11 2011	(r228385)
@@ -43,10 +43,11 @@ __FBSDID("$FreeBSD$");
 #include <fs/nfs/nfsport.h>
 
 extern struct nfsstats newnfsstats;
-extern struct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS];
+extern struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS];
 extern int ncl_mbuf_mlen;
 extern enum vtype newnv2tov_type[8];
 extern enum vtype nv34tov_type[8];
+extern int	nfs_bigreply[NFSV41_NPROCS];
 NFSCLSTATEMUTEX;
 #endif	/* !APPLEKEXT */
 
@@ -56,7 +57,7 @@ static struct {
 	int	opcnt;
 	const u_char *tag;
 	int	taglen;
-} nfsv4_opmap[NFS_NPROCS] = {
+} nfsv4_opmap[NFSV41_NPROCS] = {
 	{ 0, 1, "Null", 4 },
 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
 	{ NFSV4OP_SETATTR, 2, "Setattr", 7, },
@@ -98,15 +99,20 @@ static struct {
 	{ NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
 	{ NFSV4OP_GETATTR, 1, "Getacl", 6, },
 	{ NFSV4OP_SETATTR, 1, "Setacl", 6, },
+	{ NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, },
+	{ NFSV4OP_CREATESESSION, 1, "CreateSession", 13, },
+	{ NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, },
+	{ NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, },
+	{ NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, },
 };
 
 
 /*
  * NFS RPCS that have large request message size.
  */
-static int nfs_bigrequest[NFS_NPROCS] = {
+static int nfs_bigrequest[NFSV41_NPROCS] = {
 	0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 };
 
 /*
@@ -125,9 +131,12 @@ nfscl_reqstart(struct nfsrv_descript *nd
 	/*
 	 * First, fill in some of the fields of nd.
 	 */
-	if (NFSHASNFSV4(nmp))
+	nd->nd_slotseq = NULL;
+	if (NFSHASNFSV4(nmp)) {
 		nd->nd_flag = ND_NFSV4;
-	else if (NFSHASNFSV3(nmp))
+		if (NFSHASNFSV4N(nmp))
+			nd->nd_flag |= ND_NFSV41;
+	} else if (NFSHASNFSV3(nmp))
 		nd->nd_flag = ND_NFSV3;
 	else
 		nd->nd_flag = ND_NFSV2;
@@ -151,17 +160,36 @@ nfscl_reqstart(struct nfsrv_descript *nd
 	if (nd->nd_flag & ND_NFSV4) {
 		opcnt = nfsv4_opmap[procnum].opcnt +
 		    nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
+		if ((nd->nd_flag & ND_NFSV41) != 0) {
+			opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
+			if (procnum == NFSPROC_RENEW)
+				/*
+				 * For the special case of Renew, just do a
+				 * Sequence Op.
+				 */
+				opcnt = 1;
+		}
 		/*
 		 * What should the tag really be?
 		 */
 		(void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
 			nfsv4_opmap[procnum].taglen);
-		NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
-		*tl++ = txdr_unsigned(NFSV4_MINORVERSION);
+		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			*tl++ = txdr_unsigned(NFSV41_MINORVERSION);
+		else
+			*tl++ = txdr_unsigned(NFSV4_MINORVERSION);
 		if (opcntpp != NULL)
 			*opcntpp = tl;
-		*tl++ = txdr_unsigned(opcnt);
+		*tl = txdr_unsigned(opcnt);
+		if ((nd->nd_flag & ND_NFSV41) != 0 &&
+		    nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
+			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+			*tl = txdr_unsigned(NFSV4OP_SEQUENCE);
+			nfscl_setsequence(nd, nmp, nfs_bigreply[procnum]);
+		}
 		if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
+			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 			*tl = txdr_unsigned(NFSV4OP_PUTFH);
 			(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
 			if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh==2){
@@ -171,13 +199,17 @@ nfscl_reqstart(struct nfsrv_descript *nd
 				(void) nfsrv_putattrbit(nd, &attrbits);
 				nd->nd_flag |= ND_V4WCCATTR;
 			}
+		}
+		if (procnum != NFSPROC_RENEW ||
+		    (nd->nd_flag & ND_NFSV41) == 0) {
 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+			*tl = txdr_unsigned(nfsv4_opmap[procnum].op);
 		}
-		*tl = txdr_unsigned(nfsv4_opmap[procnum].op);
 	} else {
 		(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
 	}
-	NFSINCRGLOBAL(newnfsstats.rpccnt[procnum]);
+	if (procnum < NFSV4_NPROCS)
+		NFSINCRGLOBAL(newnfsstats.rpccnt[procnum]);
 }
 
 #ifndef APPLE

Modified: projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clkdtrace.c
==============================================================================
--- projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clkdtrace.c	Sat Dec 10 01:44:24 2011	(r228384)
+++ projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clkdtrace.c	Sat Dec 10 02:06:11 2011	(r228385)
@@ -92,7 +92,7 @@ struct dtnfsclient_rpc {
  * This table is indexed by NFSv3 procedure number, but also used for NFSv2
  * procedure names and NFSv4 operations.
  */
-static struct dtnfsclient_rpc	dtnfsclient_rpcs[NFS_NPROCS + 1] = {
+static struct dtnfsclient_rpc	dtnfsclient_rpcs[NFSV41_NPROCS + 1] = {
 	{ "null", "null", "null" },
 	{ "getattr", "getattr", "getattr" },
 	{ "setattr", "setattr", "setattr" },
@@ -196,17 +196,17 @@ extern uint32_t	nfscl_attrcache_load_don
  * stored in one of these two NFS client-allocated arrays; 0 indicates that
  * the event is not being traced so probes should not be called.
  *
- * For simplicity, we allocate both v2, v3 and v4 arrays as NFS_NPROCS + 1, and
- * the v2, v3 arrays are simply sparse.
+ * For simplicity, we allocate both v2, v3 and v4 arrays as NFSV41_NPROCS + 1,
+ * and the v2, v3 arrays are simply sparse.
  */
-extern uint32_t			nfscl_nfs2_start_probes[NFS_NPROCS + 1];
-extern uint32_t			nfscl_nfs2_done_probes[NFS_NPROCS + 1];
+extern uint32_t			nfscl_nfs2_start_probes[NFSV41_NPROCS + 1];
+extern uint32_t			nfscl_nfs2_done_probes[NFSV41_NPROCS + 1];
 
-extern uint32_t			nfscl_nfs3_start_probes[NFS_NPROCS + 1];
-extern uint32_t			nfscl_nfs3_done_probes[NFS_NPROCS + 1];
+extern uint32_t			nfscl_nfs3_start_probes[NFSV41_NPROCS + 1];
+extern uint32_t			nfscl_nfs3_done_probes[NFSV41_NPROCS + 1];
 
-extern uint32_t			nfscl_nfs4_start_probes[NFS_NPROCS + 1];
-extern uint32_t			nfscl_nfs4_done_probes[NFS_NPROCS + 1];
+extern uint32_t			nfscl_nfs4_start_probes[NFSV41_NPROCS + 1];
+extern uint32_t			nfscl_nfs4_done_probes[NFSV41_NPROCS + 1];
 
 /*
  * Look up a DTrace probe ID to see if it's associated with a "done" event --
@@ -217,7 +217,7 @@ dtnfs234_isdoneprobe(dtrace_id_t id)
 {
 	int i;
 
-	for (i = 0; i < NFS_NPROCS + 1; i++) {
+	for (i = 0; i < NFSV41_NPROCS + 1; i++) {
 		if (dtnfsclient_rpcs[i].nr_v4_id_done == id ||
 		    dtnfsclient_rpcs[i].nr_v3_id_done == id ||
 		    dtnfsclient_rpcs[i].nr_v2_id_done == id)
@@ -401,7 +401,7 @@ dtnfsclient_provide(void *arg, dtrace_pr
 	 * Register NFSv2 RPC procedures; note sparseness check for each slot
 	 * in the NFSv3, NFSv4 procnum-indexed array.
 	 */
-	for (i = 0; i < NFS_NPROCS + 1; i++) {
+	for (i = 0; i < NFSV41_NPROCS + 1; i++) {
 		if (dtnfsclient_rpcs[i].nr_v2_name != NULL &&
 		    dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs2_str,
 		    dtnfsclient_rpcs[i].nr_v2_name, dtnfsclient_start_str) ==
@@ -430,7 +430,7 @@ dtnfsclient_provide(void *arg, dtrace_pr
 	 * Register NFSv3 RPC procedures; note sparseness check for each slot
 	 * in the NFSv4 procnum-indexed array.
 	 */
-	for (i = 0; i < NFS_NPROCS + 1; i++) {
+	for (i = 0; i < NFSV41_NPROCS + 1; i++) {
 		if (dtnfsclient_rpcs[i].nr_v3_name != NULL &&
 		    dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs3_str,
 		    dtnfsclient_rpcs[i].nr_v3_name, dtnfsclient_start_str) ==
@@ -458,7 +458,7 @@ dtnfsclient_provide(void *arg, dtrace_pr
 	/*
 	 * Register NFSv4 RPC procedures.
 	 */
-	for (i = 0; i < NFS_NPROCS + 1; i++) {
+	for (i = 0; i < NFSV41_NPROCS + 1; i++) {
 		if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs4_str,
 		    dtnfsclient_rpcs[i].nr_v4_name, dtnfsclient_start_str) ==
 		    0) {

Modified: projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clkrpc.c
==============================================================================
--- projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clkrpc.c	Sat Dec 10 01:44:24 2011	(r228384)
+++ projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clkrpc.c	Sat Dec 10 02:06:11 2011	(r228385)
@@ -46,7 +46,7 @@ __FBSDID("$FreeBSD$");
 
 NFSDLOCKMUTEX;
 
-SVCPOOL		*nfscbd_pool;
+extern SVCPOOL	*nfscbd_pool;
 
 static int nfs_cbproc(struct nfsrv_descript *, u_int32_t);
 
@@ -91,6 +91,7 @@ nfscb_program(struct svc_req *rqst, SVCX
 	nd.nd_mreq = NULL;
 	nd.nd_cred = NULL;
 
+printf("cbproc=%d\n",nd.nd_procnum);
 	if (nd.nd_procnum != NFSPROC_NULL) {
 		if (!svc_getcred(rqst, &nd.nd_cred, &credflavor)) {
 			svcerr_weakauth(rqst);
@@ -136,6 +137,8 @@ nfscb_program(struct svc_req *rqst, SVCX
 			m_freem(nd.nd_mreq);
 	} else if (!svc_sendreply_mbuf(rqst, nd.nd_mreq)) {
 		svcerr_systemerr(rqst);
+} else {
+printf("cbrep sent\n");
 	}
 	svc_freereq(rqst);
 }
@@ -272,13 +275,15 @@ nfsrvd_cbinit(int terminating)
 	NFSD_LOCK_ASSERT();
 
 	if (terminating) {
+		/* Wait for any xprt registrations to complete. */
+		while (nfs_numnfscbd > 0)
+			msleep(&nfs_numnfscbd, NFSDLOCKMUTEXPTR, PZERO, 
+			    "nfscbdt", 0);
 		NFSD_UNLOCK();
 		svcpool_destroy(nfscbd_pool);
 		nfscbd_pool = NULL;
-		NFSD_LOCK();
-	}
-
-	NFSD_UNLOCK();
+	} else
+		NFSD_UNLOCK();
 
 	nfscbd_pool = svcpool_create("nfscbd", NULL);
 	nfscbd_pool->sp_rcache = NULL;

Modified: projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clrpcops.c
==============================================================================
--- projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clrpcops.c	Sat Dec 10 01:44:24 2011	(r228384)
+++ projects/nfsv4.1-client/sys/fs/nfsclient/nfs_clrpcops.c	Sat Dec 10 02:06:11 2011	(r228385)
@@ -720,10 +720,13 @@ nfsrpc_openconfirm(vnode_t vp, u_int8_t 
 {
 	u_int32_t *tl;
 	struct nfsrv_descript nfsd, *nd = &nfsd;
+	struct nfsmount *nmp;
 	int error;
 
-	nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, VFSTONFS(vnode_mount(vp)),

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201112100206.pBA26Bhh059411>