Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 1 Jul 2014 20:47:16 +0000 (UTC)
From:      Rick Macklem <rmacklem@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r268115 - in head/sys: conf fs/nfs fs/nfsclient fs/nfsserver modules/krpc rpc
Message-ID:  <201407012047.s61KlGYY090389@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rmacklem
Date: Tue Jul  1 20:47:16 2014
New Revision: 268115
URL: http://svnweb.freebsd.org/changeset/base/268115

Log:
  Merge the NFSv4.1 server code in projects/nfsv4.1-server over
  into head. The code is not believed to have any effect
  on the semantics of non-NFSv4.1 server behaviour.
  It is a rather large merge, but I am hoping that there will
  not be any regressions for the NFS server.
  
  MFC after:	1 month

Added:
  head/sys/rpc/clnt_bck.c   (contents, props changed)
Modified:
  head/sys/conf/files
  head/sys/fs/nfs/nfs.h
  head/sys/fs/nfs/nfs_commonkrpc.c
  head/sys/fs/nfs/nfs_commonport.c
  head/sys/fs/nfs/nfs_commonsubs.c
  head/sys/fs/nfs/nfs_var.h
  head/sys/fs/nfs/nfsclstate.h
  head/sys/fs/nfs/nfsdport.h
  head/sys/fs/nfs/nfsport.h
  head/sys/fs/nfs/nfsproto.h
  head/sys/fs/nfs/nfsrvstate.h
  head/sys/fs/nfsclient/nfs_clstate.c
  head/sys/fs/nfsserver/nfs_nfsdcache.c
  head/sys/fs/nfsserver/nfs_nfsdkrpc.c
  head/sys/fs/nfsserver/nfs_nfsdport.c
  head/sys/fs/nfsserver/nfs_nfsdserv.c
  head/sys/fs/nfsserver/nfs_nfsdsocket.c
  head/sys/fs/nfsserver/nfs_nfsdstate.c
  head/sys/fs/nfsserver/nfs_nfsdsubs.c
  head/sys/modules/krpc/Makefile
  head/sys/rpc/krpc.h
  head/sys/rpc/svc.h
  head/sys/rpc/svc_vc.c

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Tue Jul  1 20:00:35 2014	(r268114)
+++ head/sys/conf/files	Tue Jul  1 20:47:16 2014	(r268115)
@@ -3810,6 +3810,7 @@ pci/viapm.c			optional viapm pci
 rpc/auth_none.c			optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
 rpc/auth_unix.c			optional krpc | nfslockd | nfsclient | nfscl | nfsd
 rpc/authunix_prot.c		optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
+rpc/clnt_bck.c			optional krpc | nfslockd | nfsserver | nfscl | nfsd
 rpc/clnt_dg.c			optional krpc | nfslockd | nfsclient | nfscl | nfsd
 rpc/clnt_rc.c			optional krpc | nfslockd | nfsclient | nfscl | nfsd
 rpc/clnt_vc.c			optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd

Modified: head/sys/fs/nfs/nfs.h
==============================================================================
--- head/sys/fs/nfs/nfs.h	Tue Jul  1 20:00:35 2014	(r268114)
+++ head/sys/fs/nfs/nfs.h	Tue Jul  1 20:47:16 2014	(r268115)
@@ -50,7 +50,8 @@
 #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_SLOTS	64		/* Number of slots, fore channel */
+#define	NFSV4_CBSLOTS	8		/* Number of slots, back channel */
 #define	NFSV4_CBRETRYCNT 4		/* # of CBRecall retries upon err */
 #define	NFSV4_UPCALLTIMEO (15 * NFS_HZ)	/* Timeout in ticks for upcalls */
 					/* to gssd or nfsuserd */
@@ -91,6 +92,9 @@
 #ifndef NFSLOCKHASHSIZE
 #define	NFSLOCKHASHSIZE		20	/* Size of server nfslock hash table */
 #endif
+#ifndef NFSSESSIONHASHSIZE
+#define	NFSSESSIONHASHSIZE	20	/* Size of server session hash table */
+#endif
 #define	NFSSTATEHASHSIZE	10	/* Size of server stateid hash table */
 #ifndef NFSUSERHASHSIZE
 #define	NFSUSERHASHSIZE		30	/* Size of user id hash table */
@@ -276,6 +280,8 @@ struct nfsreferral {
 #define	LCL_GSSINTEGRITY	0x00002000
 #define	LCL_GSSPRIVACY		0x00004000
 #define	LCL_ADMINREVOKED	0x00008000
+#define	LCL_RECLAIMCOMPLETE	0x00010000
+#define	LCL_NFSV41		0x00020000
 
 #define	LCL_GSS		LCL_KERBV	/* Or of all mechs */
 
@@ -318,6 +324,11 @@ struct nfsreferral {
 #define	NFSLCK_SETATTR		0x02000000
 #define	NFSLCK_DELEGPURGE	0x04000000
 #define	NFSLCK_DELEGRETURN	0x08000000
+#define	NFSLCK_WANTWDELEG	0x10000000
+#define	NFSLCK_WANTRDELEG	0x20000000
+#define	NFSLCK_WANTNODELEG	0x40000000
+#define	NFSLCK_WANTBITS							\
+    (NFSLCK_WANTWDELEG | NFSLCK_WANTRDELEG | NFSLCK_WANTNODELEG)
 
 /* And bits for nid_flag */
 #define	NFSID_INITIALIZE	0x0001
@@ -341,68 +352,120 @@ struct nfsreferral {
  * THE MACROS MUST BE MANUALLY MODIFIED IF NFSATTRBIT_MAXWORDS CHANGES!!
  * It is (NFSATTRBIT_MAX + 31) / 32.
  */
-#define	NFSATTRBIT_MAXWORDS	2
+#define	NFSATTRBIT_MAXWORDS	3
 
 typedef struct {
 	u_int32_t bits[NFSATTRBIT_MAXWORDS];
 } nfsattrbit_t;
 
-#define	NFSZERO_ATTRBIT(b) do { (b)->bits[0] = 0; (b)->bits[1] = 0; } while (0)
-#define	NFSSET_ATTRBIT(t, f) do { (t)->bits[0] = (f)->bits[0]; 		\
-				  (t)->bits[1] = (f)->bits[1]; } while (0)
+#define	NFSZERO_ATTRBIT(b) do {						\
+	(b)->bits[0] = 0;						\
+	(b)->bits[1] = 0;						\
+	(b)->bits[2] = 0;						\
+} while (0)
+
+#define	NFSSET_ATTRBIT(t, f) do {					\
+	(t)->bits[0] = (f)->bits[0];			 		\
+	(t)->bits[1] = (f)->bits[1];					\
+	(t)->bits[2] = (f)->bits[2];					\
+} while (0)
+
 #define	NFSSETSUPP_ATTRBIT(b) do { 					\
 	(b)->bits[0] = NFSATTRBIT_SUPP0; 				\
-	(b)->bits[1] = (NFSATTRBIT_SUPP1 | NFSATTRBIT_SUPPSETONLY); } while (0)
+	(b)->bits[1] = (NFSATTRBIT_SUPP1 | NFSATTRBIT_SUPPSETONLY);	\
+	(b)->bits[2] = NFSATTRBIT_SUPP2;				\
+} while (0)
+
 #define	NFSISSET_ATTRBIT(b, p)	((b)->bits[(p) / 32] & (1 << ((p) % 32)))
 #define	NFSSETBIT_ATTRBIT(b, p)	((b)->bits[(p) / 32] |= (1 << ((p) % 32)))
 #define	NFSCLRBIT_ATTRBIT(b, p)	((b)->bits[(p) / 32] &= ~(1 << ((p) % 32)))
+
 #define	NFSCLRALL_ATTRBIT(b, a)	do { 					\
-		(b)->bits[0] &= ~((a)->bits[0]); 			\
-		(b)->bits[1] &= ~((a)->bits[1]); 			\
-		} while (0)
+	(b)->bits[0] &= ~((a)->bits[0]);	 			\
+	(b)->bits[1] &= ~((a)->bits[1]);	 			\
+	(b)->bits[2] &= ~((a)->bits[2]);				\
+} while (0)
+
 #define	NFSCLRNOT_ATTRBIT(b, a)	do { 					\
-		(b)->bits[0] &= ((a)->bits[0]); 			\
-		(b)->bits[1] &= ((a)->bits[1]); 			\
-		} while (0)
+	(b)->bits[0] &= ((a)->bits[0]);		 			\
+	(b)->bits[1] &= ((a)->bits[1]);		 			\
+	(b)->bits[2] &= ((a)->bits[2]);		 			\
+} while (0)
+
 #define	NFSCLRNOTFILLABLE_ATTRBIT(b) do { 				\
-		(b)->bits[0] &= NFSATTRBIT_SUPP0; 			\
-		(b)->bits[1] &= NFSATTRBIT_SUPP1; } while (0)
+	(b)->bits[0] &= NFSATTRBIT_SUPP0;	 			\
+	(b)->bits[1] &= NFSATTRBIT_SUPP1;				\
+	(b)->bits[2] &= NFSATTRBIT_SUPP2;				\
+} while (0)
+
 #define	NFSCLRNOTSETABLE_ATTRBIT(b) do { 				\
-		(b)->bits[0] &= NFSATTRBIT_SETABLE0; 			\
-		(b)->bits[1] &= NFSATTRBIT_SETABLE1; } while (0)
-#define	NFSNONZERO_ATTRBIT(b)	((b)->bits[0] || (b)->bits[1])
-#define	NFSEQUAL_ATTRBIT(b, p)						\
-	((b)->bits[0] == (p)->bits[0] && (b)->bits[1] == (p)->bits[1])
+	(b)->bits[0] &= NFSATTRBIT_SETABLE0;	 			\
+	(b)->bits[1] &= NFSATTRBIT_SETABLE1;				\
+	(b)->bits[2] &= NFSATTRBIT_SETABLE2;				\
+} while (0)
+
+#define	NFSNONZERO_ATTRBIT(b)	((b)->bits[0] || (b)->bits[1] || (b)->bits[2])
+#define	NFSEQUAL_ATTRBIT(b, p)	((b)->bits[0] == (p)->bits[0] &&	\
+	(b)->bits[1] == (p)->bits[1] && (b)->bits[2] == (p)->bits[2])
+
 #define	NFSGETATTR_ATTRBIT(b) do { 					\
-		(b)->bits[0] = NFSATTRBIT_GETATTR0; 			\
-		(b)->bits[1] = NFSATTRBIT_GETATTR1; } while (0)
+	(b)->bits[0] = NFSATTRBIT_GETATTR0;	 			\
+	(b)->bits[1] = NFSATTRBIT_GETATTR1;				\
+	(b)->bits[2] = NFSATTRBIT_GETATTR2;				\
+} while (0)
+
 #define	NFSWCCATTR_ATTRBIT(b) do { 					\
-		(b)->bits[0] = NFSATTRBIT_WCCATTR0; 			\
-		(b)->bits[1] = NFSATTRBIT_WCCATTR1; } while (0)
+	(b)->bits[0] = NFSATTRBIT_WCCATTR0;	 			\
+	(b)->bits[1] = NFSATTRBIT_WCCATTR1;				\
+	(b)->bits[2] = NFSATTRBIT_WCCATTR2;				\
+} while (0)
+
 #define	NFSWRITEGETATTR_ATTRBIT(b) do { 				\
-		(b)->bits[0] = NFSATTRBIT_WRITEGETATTR0;		\
-		(b)->bits[1] = NFSATTRBIT_WRITEGETATTR1; } while (0)
+	(b)->bits[0] = NFSATTRBIT_WRITEGETATTR0;			\
+	(b)->bits[1] = NFSATTRBIT_WRITEGETATTR1;			\
+	(b)->bits[2] = NFSATTRBIT_WRITEGETATTR2;			\
+} while (0)
+
 #define	NFSCBGETATTR_ATTRBIT(b, c) do { 				\
-	(c)->bits[0] = ((b)->bits[0] & NFSATTRBIT_CBGETATTR0); 		\
-	(c)->bits[1] = ((b)->bits[1] & NFSATTRBIT_CBGETATTR1); } while (0)
+	(c)->bits[0] = ((b)->bits[0] & NFSATTRBIT_CBGETATTR0);		\
+	(c)->bits[1] = ((b)->bits[1] & NFSATTRBIT_CBGETATTR1);		\
+	(c)->bits[2] = ((b)->bits[2] & NFSATTRBIT_CBGETATTR2);		\
+} while (0)
+
 #define	NFSPATHCONF_GETATTRBIT(b) do { 					\
-		(b)->bits[0] = NFSGETATTRBIT_PATHCONF0; 		\
-		(b)->bits[1] = NFSGETATTRBIT_PATHCONF1; } while (0)
+	(b)->bits[0] = NFSGETATTRBIT_PATHCONF0;		 		\
+	(b)->bits[1] = NFSGETATTRBIT_PATHCONF1;				\
+	(b)->bits[2] = NFSGETATTRBIT_PATHCONF2;				\
+} while (0)
+
 #define	NFSSTATFS_GETATTRBIT(b)	do { 					\
-		(b)->bits[0] = NFSGETATTRBIT_STATFS0; 			\
-		(b)->bits[1] = NFSGETATTRBIT_STATFS1; } while (0)
+	(b)->bits[0] = NFSGETATTRBIT_STATFS0;	 			\
+	(b)->bits[1] = NFSGETATTRBIT_STATFS1;				\
+	(b)->bits[2] = NFSGETATTRBIT_STATFS2;				\
+} while (0)
+
 #define	NFSISSETSTATFS_ATTRBIT(b) 					\
 		(((b)->bits[0] & NFSATTRBIT_STATFS0) || 		\
-		 ((b)->bits[1] & NFSATTRBIT_STATFS1))
+		 ((b)->bits[1] & NFSATTRBIT_STATFS1) ||			\
+		 ((b)->bits[2] & NFSATTRBIT_STATFS2))
+
 #define	NFSCLRSTATFS_ATTRBIT(b)	do { 					\
-		(b)->bits[0] &= ~NFSATTRBIT_STATFS0; 			\
-		(b)->bits[1] &= ~NFSATTRBIT_STATFS1; } while (0)
+	(b)->bits[0] &= ~NFSATTRBIT_STATFS0;	 			\
+	(b)->bits[1] &= ~NFSATTRBIT_STATFS1;				\
+	(b)->bits[2] &= ~NFSATTRBIT_STATFS2;				\
+} while (0)
+
 #define	NFSREADDIRPLUS_ATTRBIT(b) do { 					\
-		(b)->bits[0] = NFSATTRBIT_READDIRPLUS0; 		\
-		(b)->bits[1] = NFSATTRBIT_READDIRPLUS1; } while (0)
+	(b)->bits[0] = NFSATTRBIT_READDIRPLUS0;		 		\
+	(b)->bits[1] = NFSATTRBIT_READDIRPLUS1;				\
+	(b)->bits[2] = NFSATTRBIT_READDIRPLUS2;				\
+} while (0)
+
 #define	NFSREFERRAL_ATTRBIT(b) do { 					\
-		(b)->bits[0] = NFSATTRBIT_REFERRAL0;	 		\
-		(b)->bits[1] = NFSATTRBIT_REFERRAL1; } while (0)
+	(b)->bits[0] = NFSATTRBIT_REFERRAL0;		 		\
+	(b)->bits[1] = NFSATTRBIT_REFERRAL1;				\
+	(b)->bits[2] = NFSATTRBIT_REFERRAL2;				\
+} while (0)
 
 /*
  * Store uid, gid creds that were used when the stateid was acquired.
@@ -529,6 +592,9 @@ struct nfsrv_descript {
 	int			nd_gssnamelen;	/* principal name length */
 	char			*nd_gssname;	/* principal name */
 	uint32_t		*nd_slotseq;	/* ptr to slot seq# in req */
+	uint8_t			nd_sessionid[NFSX_V4SESSIONID];	/* Session id */
+	uint32_t		nd_slotid;	/* Slotid for this RPC */
+	SVCXPRT			*nd_xprt;	/* Server RPC handle */
 };
 
 #define	nd_princlen	nd_gssnamelen
@@ -562,6 +628,8 @@ struct nfsrv_descript {
 #define	ND_NFSCL		0x01000000
 #define	ND_NFSV41		0x02000000
 #define	ND_HASSEQUENCE		0x04000000
+#define	ND_CACHETHIS		0x08000000
+#define	ND_LASTOP		0x10000000
 
 /*
  * ND_GSS should be the "or" of all GSS type authentications.

Modified: head/sys/fs/nfs/nfs_commonkrpc.c
==============================================================================
--- head/sys/fs/nfs/nfs_commonkrpc.c	Tue Jul  1 20:00:35 2014	(r268114)
+++ head/sys/fs/nfs/nfs_commonkrpc.c	Tue Jul  1 20:47:16 2014	(r268115)
@@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/vnode.h>
 
 #include <rpc/rpc.h>
+#include <rpc/krpc.h>
 
 #include <kgssapi/krb5/kcrypto.h>
 
@@ -738,8 +739,12 @@ tryagain:
 	}
 
 	nd->nd_mrep = NULL;
-	stat = CLNT_CALL_MBUF(nrp->nr_client, &ext, procnum, nd->nd_mreq,
-	    &nd->nd_mrep, timo);
+	if (clp != NULL && sep != NULL)
+		stat = clnt_bck_call(nrp->nr_client, &ext, procnum,
+		    nd->nd_mreq, &nd->nd_mrep, timo, sep->nfsess_xprt);
+	else
+		stat = CLNT_CALL_MBUF(nrp->nr_client, &ext, procnum,
+		    nd->nd_mreq, &nd->nd_mrep, timo);
 
 	if (rep != NULL) {
 		/*
@@ -794,7 +799,8 @@ tryagain:
 	nd->nd_md = nd->nd_mrep;
 	nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
 	nd->nd_repstat = 0;
-	if (nd->nd_procnum != NFSPROC_NULL) {
+	if (nd->nd_procnum != NFSPROC_NULL &&
+	    nd->nd_procnum != NFSV4PROC_CBNULL) {
 		/* If sep == NULL, set it to the default in nmp. */
 		if (sep == NULL && nmp != NULL)
 			sep = NFSMNT_MDSSESSION(nmp);
@@ -826,11 +832,20 @@ tryagain:
 			/*
 			 * If the first op is Sequence, free up the slot.
 			 */
-			if (nmp != NULL && i == NFSV4OP_SEQUENCE && j != 0)
+			if ((nmp != NULL && i == NFSV4OP_SEQUENCE && j != 0) ||
+			    (clp != NULL && i == NFSV4OP_CBSEQUENCE && j != 0))
 				NFSCL_DEBUG(1, "failed seq=%d\n", j);
-			if (nmp != NULL && i == NFSV4OP_SEQUENCE && j == 0) {
-				NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID +
-				    5 * NFSX_UNSIGNED);
+			if ((nmp != NULL && i == NFSV4OP_SEQUENCE && j == 0) ||
+			    (clp != NULL && i == NFSV4OP_CBSEQUENCE && j == 0)
+			    ) {
+				if (i == NFSV4OP_SEQUENCE)
+					NFSM_DISSECT(tl, uint32_t *,
+					    NFSX_V4SESSIONID +
+					    5 * NFSX_UNSIGNED);
+				else
+					NFSM_DISSECT(tl, uint32_t *,
+					    NFSX_V4SESSIONID +
+					    4 * NFSX_UNSIGNED);
 				mtx_lock(&sep->nfsess_mtx);
 				tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
 				retseq = fxdr_unsigned(uint32_t, *tl++);

Modified: head/sys/fs/nfs/nfs_commonport.c
==============================================================================
--- head/sys/fs/nfs/nfs_commonport.c	Tue Jul  1 20:00:35 2014	(r268114)
+++ head/sys/fs/nfs/nfs_commonport.c	Tue Jul  1 20:47:16 2014	(r268115)
@@ -112,6 +112,7 @@ MALLOC_DEFINE(M_NEWNFSDEVINFO, "NFSCL de
 MALLOC_DEFINE(M_NEWNFSSOCKREQ, "NFSCL sockreq", "NFS Sock Req");
 MALLOC_DEFINE(M_NEWNFSCLDS, "NFSCL session", "NFSv4.1 Session");
 MALLOC_DEFINE(M_NEWNFSLAYRECALL, "NFSCL layrecall", "NFSv4.1 Layout Recall");
+MALLOC_DEFINE(M_NEWNFSDSESSION, "NFSD session", "NFSD Session for a client");
 
 /*
  * Definition of mutex locks.

Modified: head/sys/fs/nfs/nfs_commonsubs.c
==============================================================================
--- head/sys/fs/nfs/nfs_commonsubs.c	Tue Jul  1 20:00:35 2014	(r268114)
+++ head/sys/fs/nfs/nfs_commonsubs.c	Tue Jul  1 20:47:16 2014	(r268115)
@@ -1733,6 +1733,23 @@ nfsv4_loadattr(struct nfsrv_descript *nd
 			}
 			attrsum += NFSX_HYPER;
 			break;
+		case NFSATTRBIT_SUPPATTREXCLCREAT:
+			retnotsup = 0;
+			error = nfsrv_getattrbits(nd, &retattrbits,
+			    &cnt, &retnotsup);
+			if (error)
+			    goto nfsmout;
+			if (compare && !(*retcmpp)) {
+			   NFSSETSUPP_ATTRBIT(&checkattrbits);
+			   NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits);
+			   NFSCLRBIT_ATTRBIT(&checkattrbits,
+				NFSATTRBIT_TIMEACCESSSET);
+			   if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
+			       || retnotsup)
+				*retcmpp = NFSERR_NOTSAME;
+			}
+			attrsum += cnt;
+			break;
 		default:
 			printf("EEK! nfsv4_loadattr unknown attr=%d\n",
 				bitpos);
@@ -2469,6 +2486,12 @@ nfsv4_fillattr(struct nfsrv_descript *nd
 			txdr_hyper(uquad, tl);
 			retnum += NFSX_HYPER;
 			break;
+		case NFSATTRBIT_SUPPATTREXCLCREAT:
+			NFSSETSUPP_ATTRBIT(&attrbits);
+			NFSCLRNOTSETABLE_ATTRBIT(&attrbits);
+			NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
+			retnum += nfsrv_putattrbit(nd, &attrbits);
+			break;
 		default:
 			printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
 		};
@@ -3663,6 +3686,9 @@ nfsmout:
 
 /*
  * Handle an NFSv4.1 Sequence request for the session.
+ * If reply != NULL, use it to return the cached reply, as required.
+ * The client gets a cached reply via this call for callbacks, however the
+ * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
  */
 int
 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
@@ -3671,7 +3697,8 @@ nfsv4_seqsession(uint32_t seqid, uint32_
 	int error;
 
 	error = 0;
-	*reply = NULL;
+	if (reply != NULL)
+		*reply = NULL;
 	if (slotid > maxslot)
 		return (NFSERR_BADSLOT);
 	if (seqid == slots[slotid].nfssl_seq) {
@@ -3679,13 +3706,18 @@ nfsv4_seqsession(uint32_t seqid, uint32_
 		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;
+			if (reply != NULL) {
+				*reply = slots[slotid].nfssl_reply;
+				slots[slotid].nfssl_reply = NULL;
+			}
 			slots[slotid].nfssl_inprog = 1;
+			error = NFSERR_REPLYFROMCACHE;
 		} else
-			error = NFSERR_SEQMISORDERED;
+			/* No reply cached, so just do it. */
+			slots[slotid].nfssl_inprog = 1;
 	} else if ((slots[slotid].nfssl_seq + 1) == seqid) {
-		m_freem(slots[slotid].nfssl_reply);
+		if (slots[slotid].nfssl_reply != NULL)
+			m_freem(slots[slotid].nfssl_reply);
 		slots[slotid].nfssl_reply = NULL;
 		slots[slotid].nfssl_inprog = 1;
 		slots[slotid].nfssl_seq++;
@@ -3696,12 +3728,22 @@ nfsv4_seqsession(uint32_t seqid, uint32_
 
 /*
  * Cache this reply for the slot.
+ * Use the "rep" argument to return the cached reply if repstat is set to
+ * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
  */
 void
-nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, struct mbuf *rep)
+nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
+   struct mbuf **rep)
 {
 
-	slots[slotid].nfssl_reply = rep;
+	if (repstat == NFSERR_REPLYFROMCACHE) {
+		*rep = slots[slotid].nfssl_reply;
+		slots[slotid].nfssl_reply = NULL;
+	} else {
+		if (slots[slotid].nfssl_reply != NULL)
+			m_freem(slots[slotid].nfssl_reply);
+		slots[slotid].nfssl_reply = *rep;
+	}
 	slots[slotid].nfssl_inprog = 0;
 }
 
@@ -3713,9 +3755,36 @@ nfsv4_setsequence(struct nfsmount *nmp, 
     struct nfsclsession *sep, int dont_replycache)
 {
 	uint32_t *tl, slotseq = 0;
+	int error, maxslot, slotpos;
+	uint8_t sessionid[NFSX_V4SESSIONID];
+
+	error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
+	    sessionid);
+	if (error != 0)
+		return;
+	KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot"));
+
+	/* Build the Sequence arguments. */
+	NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
+	bcopy(sessionid, tl, NFSX_V4SESSIONID);
+	tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
+	nd->nd_slotseq = tl;
+	*tl++ = txdr_unsigned(slotseq);
+	*tl++ = txdr_unsigned(slotpos);
+	*tl++ = txdr_unsigned(maxslot);
+	if (dont_replycache == 0)
+		*tl = newnfs_true;
+	else
+		*tl = newnfs_false;
+	nd->nd_flag |= ND_HASSEQUENCE;
+}
+
+int
+nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
+    int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
+{
 	int i, maxslot, slotpos;
 	uint64_t bitval;
-	uint8_t sessionid[NFSX_V4SESSIONID];
 
 	/* Find an unused slot. */
 	slotpos = -1;
@@ -3728,7 +3797,7 @@ nfsv4_setsequence(struct nfsmount *nmp, 
 				slotpos = i;
 				sep->nfsess_slots |= bitval;
 				sep->nfsess_slotseq[i]++;
-				slotseq = sep->nfsess_slotseq[i];
+				*slotseqp = sep->nfsess_slotseq[i];
 				break;
 			}
 			bitval <<= 1;
@@ -3739,10 +3808,11 @@ nfsv4_setsequence(struct nfsmount *nmp, 
 			 * This RPC attempt will fail when it calls
 			 * newnfs_request().
 			 */
-			if ((nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
+			if (nmp != NULL &&
+			    (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
 			    != 0) {
 				mtx_unlock(&sep->nfsess_mtx);
-				return;
+				return (ESTALE);
 			}
 			/* Wake up once/sec, to check for a forced dismount. */
 			(void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
@@ -3758,21 +3828,9 @@ nfsv4_setsequence(struct nfsmount *nmp, 
 	}
 	bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
 	mtx_unlock(&sep->nfsess_mtx);
-	KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot"));
-
-	/* Build the Sequence arguments. */
-	NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
-	bcopy(sessionid, tl, NFSX_V4SESSIONID);
-	tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
-	nd->nd_slotseq = tl;
-	*tl++ = txdr_unsigned(slotseq);
-	*tl++ = txdr_unsigned(slotpos);
-	*tl++ = txdr_unsigned(maxslot);
-	if (dont_replycache == 0)
-		*tl = newnfs_true;
-	else
-		*tl = newnfs_false;
-	nd->nd_flag |= ND_HASSEQUENCE;
+	*slotposp = slotpos;
+	*maxslotp = maxslot;
+	return (0);
 }
 
 /*

Modified: head/sys/fs/nfs/nfs_var.h
==============================================================================
--- head/sys/fs/nfs/nfs_var.h	Tue Jul  1 20:00:35 2014	(r268114)
+++ head/sys/fs/nfs/nfs_var.h	Tue Jul  1 20:47:16 2014	(r268115)
@@ -61,6 +61,7 @@ union nethostaddr;
 struct nfsstate;
 struct nfslock;
 struct nfsclient;
+struct nfsdsession;
 struct nfslockconflict;
 struct nfsd_idargs;
 struct nfsd_clid;
@@ -90,8 +91,11 @@ NFS_READDIR_ARGS;
 /* nfs_nfsdstate.c */
 int nfsrv_setclient(struct nfsrv_descript *, struct nfsclient **,
     nfsquad_t *, nfsquad_t *, NFSPROC_T *);
-int nfsrv_getclient(nfsquad_t, int, struct nfsclient **, nfsquad_t,
-    struct nfsrv_descript *, NFSPROC_T *);
+int nfsrv_getclient(nfsquad_t, int, struct nfsclient **, struct nfsdsession *,
+    nfsquad_t, uint32_t, struct nfsrv_descript *, NFSPROC_T *);
+int nfsrv_destroyclient(nfsquad_t, NFSPROC_T *);
+int nfsrv_destroysession(struct nfsrv_descript *, uint8_t *);
+int nfsrv_freestateid(struct nfsrv_descript *, nfsv4stateid_t *, NFSPROC_T *);
 int nfsrv_adminrevoke(struct nfsd_clid *, NFSPROC_T *);
 void nfsrv_dumpclients(struct nfsd_dumpclients *, int);
 void nfsrv_dumplocks(vnode_t, struct nfsd_dumplocks *, int, NFSPROC_T *);
@@ -105,8 +109,8 @@ int nfsrv_opencheck(nfsquad_t, nfsv4stat
     vnode_t, struct nfsrv_descript *, NFSPROC_T *, int);
 int nfsrv_openupdate(vnode_t, struct nfsstate *, nfsquad_t,
     nfsv4stateid_t *, struct nfsrv_descript *, NFSPROC_T *);
-int nfsrv_delegupdate(nfsquad_t, nfsv4stateid_t *, vnode_t, int,
-    struct ucred *, NFSPROC_T *);
+int nfsrv_delegupdate(struct nfsrv_descript *, nfsquad_t, nfsv4stateid_t *,
+    vnode_t, int, struct ucred *, NFSPROC_T *);
 int nfsrv_releaselckown(struct nfsstate *, nfsquad_t, NFSPROC_T *);
 void nfsrv_zapclient(struct nfsclient *, NFSPROC_T *);
 int nfssvc_idname(struct nfsd_idargs *);
@@ -127,6 +131,10 @@ int nfsrv_checkgetattr(struct nfsrv_desc
 int nfsrv_nfsuserdport(u_short, NFSPROC_T *);
 void nfsrv_nfsuserddelport(void);
 void nfsrv_throwawayallstate(NFSPROC_T *);
+int nfsrv_checksequence(struct nfsrv_descript *, uint32_t, uint32_t *,
+    uint32_t *, int, uint32_t *, NFSPROC_T *);
+int nfsrv_checkreclaimcomplete(struct nfsrv_descript *);
+void nfsrv_cache_session(uint8_t *, uint32_t, int, struct mbuf **);
 
 /* nfs_nfsdserv.c */
 int nfsrvd_access(struct nfsrv_descript *, int,
@@ -211,10 +219,27 @@ int nfsrvd_releaselckown(struct nfsrv_de
     vnode_t, NFSPROC_T *, struct nfsexstuff *);
 int nfsrvd_pathconf(struct nfsrv_descript *, int,
     vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_exchangeid(struct nfsrv_descript *, int,
+    vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_createsession(struct nfsrv_descript *, int,
+    vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_sequence(struct nfsrv_descript *, int,
+    vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_reclaimcomplete(struct nfsrv_descript *, int,
+    vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_destroyclientid(struct nfsrv_descript *, int,
+    vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_destroysession(struct nfsrv_descript *, int,
+    vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_freestateid(struct nfsrv_descript *, int,
+    vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_notsupp(struct nfsrv_descript *, int,
+    vnode_t, NFSPROC_T *, struct nfsexstuff *);
 
 /* nfs_nfsdsocket.c */
 void nfsrvd_rephead(struct nfsrv_descript *);
-void nfsrvd_dorpc(struct nfsrv_descript *, int, NFSPROC_T *);
+void nfsrvd_dorpc(struct nfsrv_descript *, int, u_char *, int, u_int32_t,
+    NFSPROC_T *);
 
 /* nfs_nfsdcache.c */
 void nfsrvd_initcache(void);
@@ -264,9 +289,11 @@ int nfsv4_getipaddr(struct nfsrv_descrip
     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 *);
+void nfsv4_seqsess_cacherep(uint32_t, struct nfsslot *, int, struct mbuf **);
 void nfsv4_setsequence(struct nfsmount *, struct nfsrv_descript *,
     struct nfsclsession *, int);
+int nfsv4_sequencelookup(struct nfsmount *, struct nfsclsession *, int *,
+    int *, uint32_t *, uint8_t *);
 void nfsv4_freeslot(struct nfsclsession *, int);
 
 /* nfs_clcomsubs.c */
@@ -322,6 +349,8 @@ int nfsrv_parsename(struct nfsrv_descrip
     NFSPATHLEN_T *);
 void nfsd_init(void);
 int nfsd_checkrootexp(struct nfsrv_descript *);
+void nfsd_getminorvers(struct nfsrv_descript *, u_char *, u_char **, int *,
+    u_int32_t *);
 
 /* nfs_clvfsops.c */
 void nfscl_retopts(struct nfsmount *, char *, size_t);
@@ -628,6 +657,7 @@ int nfsvno_advlock(vnode_t, int, u_int64
 int nfsrv_v4rootexport(void *, struct ucred *, NFSPROC_T *);
 int nfsvno_testexp(struct nfsrv_descript *, struct nfsexstuff *);
 uint32_t nfsrv_hashfh(fhandle_t *);
+uint32_t nfsrv_hashsessionid(uint8_t *);
 void nfsrv_backupstable(void);
 
 /* nfs_commonkrpc.c */

Modified: head/sys/fs/nfs/nfsclstate.h
==============================================================================
--- head/sys/fs/nfs/nfsclstate.h	Tue Jul  1 20:00:35 2014	(r268114)
+++ head/sys/fs/nfs/nfsclstate.h	Tue Jul  1 20:47:16 2014	(r268115)
@@ -57,6 +57,7 @@ struct nfsclsession {
 	struct mtx	nfsess_mtx;
 	struct nfsslot	nfsess_cbslots[NFSV4_CBSLOTS];
 	nfsquad_t	nfsess_clientid;
+	SVCXPRT		*nfsess_xprt;		/* For backchannel callback */
 	uint32_t	nfsess_slotseq[64];	/* Max for 64bit nm_slots */
 	uint64_t	nfsess_slots;
 	uint32_t	nfsess_sequenceid;

Modified: head/sys/fs/nfs/nfsdport.h
==============================================================================
--- head/sys/fs/nfs/nfsdport.h	Tue Jul  1 20:00:35 2014	(r268114)
+++ head/sys/fs/nfs/nfsdport.h	Tue Jul  1 20:47:16 2014	(r268115)
@@ -115,3 +115,9 @@ struct nfsexstuff {
 #define	NFSRV_MINFH	(sizeof (fhandle_t))
 #define	NFSRV_MAXFH	(sizeof (fhandle_t))
 
+/* Use this macro for debug printfs. */
+#define	NFSD_DEBUG(level, ...)	do {					\
+		if (nfsd_debuglevel >= (level))				\
+			printf(__VA_ARGS__);				\
+	} while (0)
+

Modified: head/sys/fs/nfs/nfsport.h
==============================================================================
--- head/sys/fs/nfs/nfsport.h	Tue Jul  1 20:00:35 2014	(r268114)
+++ head/sys/fs/nfs/nfsport.h	Tue Jul  1 20:47:16 2014	(r268115)
@@ -638,6 +638,9 @@ void nfsrvd_rcv(struct socket *, void *,
 #define	NFSUNLOCKSOCKREQ(r)	mtx_unlock(&((r)->nr_mtx))
 #define	NFSLOCKDS(d)		mtx_lock(&((d)->nfsclds_mtx))
 #define	NFSUNLOCKDS(d)		mtx_unlock(&((d)->nfsclds_mtx))
+#define	NFSSESSIONMUTEXPTR(s)	(&((s)->mtx))
+#define	NFSLOCKSESSION(s)	mtx_lock(&((s)->mtx))
+#define	NFSUNLOCKSESSION(s)	mtx_unlock(&((s)->mtx))
 
 /*
  * Use these macros to initialize/free a mutex.
@@ -733,6 +736,7 @@ MALLOC_DECLARE(M_NEWNFSDEVINFO);
 MALLOC_DECLARE(M_NEWNFSSOCKREQ);
 MALLOC_DECLARE(M_NEWNFSCLDS);
 MALLOC_DECLARE(M_NEWNFSLAYRECALL);
+MALLOC_DECLARE(M_NEWNFSDSESSION);
 #define	M_NFSRVCACHE	M_NEWNFSRVCACHE
 #define	M_NFSDCLIENT	M_NEWNFSDCLIENT
 #define	M_NFSDSTATE	M_NEWNFSDSTATE
@@ -758,6 +762,7 @@ MALLOC_DECLARE(M_NEWNFSLAYRECALL);
 #define	M_NFSSOCKREQ	M_NEWNFSSOCKREQ
 #define	M_NFSCLDS	M_NEWNFSCLDS
 #define	M_NFSLAYRECALL	M_NEWNFSLAYRECALL
+#define	M_NFSDSESSION	M_NEWNFSDSESSION
 
 #define	NFSINT_SIGMASK(set) 						\
 	(SIGISMEMBER(set, SIGINT) || SIGISMEMBER(set, SIGTERM) ||	\

Modified: head/sys/fs/nfs/nfsproto.h
==============================================================================
--- head/sys/fs/nfs/nfsproto.h	Tue Jul  1 20:00:35 2014	(r268114)
+++ head/sys/fs/nfs/nfsproto.h	Tue Jul  1 20:47:16 2014	(r268115)
@@ -389,9 +389,13 @@
 #define	NFSV4OPEN_CLAIMPREVIOUS		1
 #define	NFSV4OPEN_CLAIMDELEGATECUR	2
 #define	NFSV4OPEN_CLAIMDELEGATEPREV	3
+#define	NFSV4OPEN_CLAIMFH		4
+#define	NFSV4OPEN_CLAIMDELEGATECURFH	5
+#define	NFSV4OPEN_CLAIMDELEGATEPREVFH	6
 #define	NFSV4OPEN_DELEGATENONE		0
 #define	NFSV4OPEN_DELEGATEREAD		1
 #define	NFSV4OPEN_DELEGATEWRITE		2
+#define	NFSV4OPEN_DELEGATENONEEXT	3
 #define	NFSV4OPEN_LIMITSIZE		1
 #define	NFSV4OPEN_LIMITBLOCKS		2
 
@@ -479,6 +483,14 @@
 #define	NFSV4OPEN_ACCESSREAD		0x00000001
 #define	NFSV4OPEN_ACCESSWRITE		0x00000002
 #define	NFSV4OPEN_ACCESSBOTH		0x00000003
+#define	NFSV4OPEN_WANTDELEGMASK		0x0000ff00
+#define	NFSV4OPEN_WANTREADDELEG		0x00000100
+#define	NFSV4OPEN_WANTWRITEDELEG	0x00000200
+#define	NFSV4OPEN_WANTANYDELEG		0x00000300
+#define	NFSV4OPEN_WANTNODELEG		0x00000400
+#define	NFSV4OPEN_WANTCANCEL		0x00000500
+#define	NFSV4OPEN_WANTSIGNALDELEG	0x00010000
+#define	NFSV4OPEN_WANTPUSHDELEG		0x00020000
 
 #define	NFSV4OPEN_DENYNONE		0x00000000
 #define	NFSV4OPEN_DENYREAD		0x00000001
@@ -486,16 +498,35 @@
 #define	NFSV4OPEN_DENYBOTH		0x00000003
 
 /*
+ * Delegate_none_ext reply values.
+ */
+#define	NFSV4OPEN_NOTWANTED		0
+#define	NFSV4OPEN_CONTENTION		1
+#define	NFSV4OPEN_RESOURCE		2
+#define	NFSV4OPEN_NOTSUPPFTYPE		3
+#define	NFSV4OPEN_NOTSUPPWRITEFTYPE	4
+#define	NFSV4OPEN_NOTSUPPUPGRADE	5
+#define	NFSV4OPEN_NOTSUPPDOWNGRADE	6
+#define	NFSV4OPEN_CANCELLED		7
+#define	NFSV4OPEN_ISDIR			8
+
+/*
  * Open result flags
- * (The first two are in the spec. The rest are used internally.)
+ * (The first four are in the spec. The rest are used internally.)
  */
 #define	NFSV4OPEN_RESULTCONFIRM		0x00000002
 #define	NFSV4OPEN_LOCKTYPEPOSIX		0x00000004
+#define	NFSV4OPEN_PRESERVEUNLINKED	0x00000008
+#define	NFSV4OPEN_MAYNOTIFYLOCK		0x00000020
 #define	NFSV4OPEN_RFLAGS 						\
-		(NFSV4OPEN_RESULTCONFIRM | NFSV4OPEN_LOCKTYPEPOSIX)
+    (NFSV4OPEN_RESULTCONFIRM | NFSV4OPEN_LOCKTYPEPOSIX |		\
+    NFSV4OPEN_PRESERVEUNLINKED | NFSV4OPEN_MAYNOTIFYLOCK)
 #define	NFSV4OPEN_RECALL		0x00010000
 #define	NFSV4OPEN_READDELEGATE		0x00020000
 #define	NFSV4OPEN_WRITEDELEGATE		0x00040000
+#define	NFSV4OPEN_WDRESOURCE		0x00080000
+#define	NFSV4OPEN_WDCONTENTION		0x00100000
+#define	NFSV4OPEN_WDNOTWANTED		0x00200000
 
 /*
  * NFS V4 File Handle types
@@ -805,6 +836,27 @@ struct nfsv3_sattr {
 #define	NFSATTRBIT_TIMEMODIFY		53
 #define	NFSATTRBIT_TIMEMODIFYSET	54
 #define	NFSATTRBIT_MOUNTEDONFILEID	55
+#define	NFSATTRBIT_DIRNOTIFDELAY	56
+#define	NFSATTRBIT_DIRENTNOTIFDELAY	57
+#define	NFSATTRBIT_DACL			58
+#define	NFSATTRBIT_SACL			59
+#define	NFSATTRBIT_CHANGEPOLICY		60
+#define	NFSATTRBIT_FSSTATUS		61
+#define	NFSATTRBIT_FSLAYOUTTYPE		62
+#define	NFSATTRBIT_LAYOUTHINT		63
+#define	NFSATTRBIT_LAYOUTTYPE		64
+#define	NFSATTRBIT_LAYOUTBLKSIZE	65
+#define	NFSATTRBIT_LAYOUTALIGNMENT	66
+#define	NFSATTRBIT_FSLOCATIONSINFO	67
+#define	NFSATTRBIT_MDSTHRESHOLD		68
+#define	NFSATTRBIT_RETENTIONGET		69
+#define	NFSATTRBIT_RETENTIONSET		70
+#define	NFSATTRBIT_RETENTEVTGET		71
+#define	NFSATTRBIT_RETENTEVTSET		72
+#define	NFSATTRBIT_RETENTIONHOLD	73
+#define	NFSATTRBIT_MODESETMASKED	74
+#define	NFSATTRBIT_SUPPATTREXCLCREAT	75
+#define	NFSATTRBIT_FSCHARSETCAP		76
 
 #define	NFSATTRBM_SUPPORTEDATTRS	0x00000001
 #define	NFSATTRBM_TYPE			0x00000002
@@ -862,8 +914,29 @@ struct nfsv3_sattr {
 #define	NFSATTRBM_TIMEMODIFY		0x00200000
 #define	NFSATTRBM_TIMEMODIFYSET		0x00400000
 #define	NFSATTRBM_MOUNTEDONFILEID	0x00800000
+#define	NFSATTRBM_DIRNOTIFDELAY		0x01000000
+#define	NFSATTRBM_DIRENTNOTIFDELAY	0x02000000
+#define	NFSATTRBM_DACL			0x04000000
+#define	NFSATTRBM_SACL			0x08000000
+#define	NFSATTRBM_CHANGEPOLICY		0x10000000
+#define	NFSATTRBM_FSSTATUS		0x20000000
+#define	NFSATTRBM_FSLAYOUTTYPE		0x40000000
+#define	NFSATTRBM_LAYOUTHINT		0x80000000
+#define	NFSATTRBM_LAYOUTTYPE		0x00000001
+#define	NFSATTRBM_LAYOUTBLKSIZE		0x00000002
+#define	NFSATTRBM_LAYOUTALIGNMENT	0x00000004
+#define	NFSATTRBM_FSLOCATIONSINFO	0x00000008
+#define	NFSATTRBM_MDSTHRESHOLD		0x00000010
+#define	NFSATTRBM_RETENTIONGET		0x00000020
+#define	NFSATTRBM_RETENTIONSET		0x00000040
+#define	NFSATTRBM_RETENTEVTGET		0x00000080
+#define	NFSATTRBM_RETENTEVTSET		0x00000100
+#define	NFSATTRBM_RETENTIONHOLD		0x00000200
+#define	NFSATTRBM_MODESETMASKED		0x00000400
+#define	NFSATTRBM_SUPPATTREXCLCREAT	0x00000800
+#define	NFSATTRBM_FSCHARSETCAP		0x00001000
 
-#define	NFSATTRBIT_MAX			56
+#define	NFSATTRBIT_MAX			77
 
 /*
  * Sets of attributes that are supported, by words in the bitmap.
@@ -871,6 +944,7 @@ struct nfsv3_sattr {
 /*
  * NFSATTRBIT_SUPPORTED - SUPP0 - bits 0<->31
  *			  SUPP1 - bits 32<->63
+ *			  SUPP2 - bits 64<->95
  */
 #define	NFSATTRBIT_SUPP0						\
  	(NFSATTRBM_SUPPORTEDATTRS |					\
@@ -937,6 +1011,8 @@ struct nfsv3_sattr {
 #define	NFSATTRBIT_SUPP1	NFSATTRBIT_S1
 #endif
 
+#define	NFSATTRBIT_SUPP2	NFSATTRBM_SUPPATTREXCLCREAT
+
 /*
  * NFSATTRBIT_SUPPSETONLY is the OR of NFSATTRBIT_TIMEACCESSSET and
  * NFSATTRBIT_TIMEMODIFYSET.
@@ -947,6 +1023,7 @@ struct nfsv3_sattr {
 /*
  * NFSATTRBIT_SETABLE - SETABLE0 - bits 0<->31
  *			SETABLE1 - bits 32<->63
+ *			SETABLE2 - bits 64<->95
  */
 #define	NFSATTRBIT_SETABLE0						\
 	(NFSATTRBM_SIZE |						\
@@ -957,6 +1034,7 @@ struct nfsv3_sattr {
  	NFSATTRBM_OWNERGROUP |						\
  	NFSATTRBM_TIMEACCESSSET |					\
  	NFSATTRBM_TIMEMODIFYSET)
+#define	NFSATTRBIT_SETABLE2		0
 
 /*
  * Set of attributes that the getattr vnode op needs.
@@ -987,6 +1065,11 @@ struct nfsv3_sattr {
  	NFSATTRBM_TIMEMODIFY)
 
 /*
+ * NFSATTRBIT_GETATTR2 - bits 64<->95
+ */
+#define	NFSATTRBIT_GETATTR2		0
+
+/*
  * Subset of the above that the Write RPC gets.
  * OR of the following bits.
  * NFSATTRBIT_WRITEGETATTR0 - bits 0<->31
@@ -1013,6 +1096,11 @@ struct nfsv3_sattr {
  	NFSATTRBM_TIMEMODIFY)
 
 /*
+ * NFSATTRBIT_WRITEGETATTR2 - bits 64<->95
+ */
+#define	NFSATTRBIT_WRITEGETATTR2	0
+
+/*
  * Set of attributes that the wccattr operation op needs.
  * OR of the following bits.
  * NFSATTRBIT_WCCATTR0 - bits 0<->31
@@ -1026,6 +1114,11 @@ struct nfsv3_sattr {
  	(NFSATTRBM_TIMEMODIFY)
 
 /*
+ * NFSATTRBIT_WCCATTR2 - bits 64<->95
+ */
+#define	NFSATTRBIT_WCCATTR2		0
+
+/*
  * NFSATTRBIT_CBGETATTR0 - bits 0<->31
  */
 #define	NFSATTRBIT_CBGETATTR0	(NFSATTRBM_CHANGE | NFSATTRBM_SIZE)
@@ -1036,6 +1129,11 @@ struct nfsv3_sattr {
 #define	NFSATTRBIT_CBGETATTR1		0x0
 
 /*
+ * NFSATTRBIT_CBGETATTR2 - bits 64<->95
+ */
+#define	NFSATTRBIT_CBGETATTR2		0x0
+
+/*
  * Sets of attributes that require a VFS_STATFS() call to get the
  * values of.
  * NFSATTRBIT_STATFS0 - bits 0<->31
@@ -1067,6 +1165,11 @@ struct nfsv3_sattr {
 	NFSATTRBM_TIMEDELTA)
 
 /*
+ * NFSATTRBIT_STATFS2 - bits 64<->95
+ */
+#define	NFSATTRBIT_STATFS2		0
+
+/*
  * These are the bits that are needed by the nfs_statfs() call.
  * (The regular getattr bits are or'd in so the vnode gets the correct
  *  type, etc.)
@@ -1094,6 +1197,11 @@ struct nfsv3_sattr {
 				NFSATTRBM_TIMEDELTA)
 
 /*
+ * NFSGETATTRBIT_STATFS2 - bits 64<->95
+ */
+#define	NFSGETATTRBIT_STATFS2		0
+
+/*
  * Set of attributes for the equivalent of an nfsv3 pathconf rpc.
  * NFSGETATTRBIT_PATHCONF0 - bits 0<->31
  */
@@ -1111,6 +1219,11 @@ struct nfsv3_sattr {
 				NFSATTRBM_NOTRUNC)
 
 /*
+ * NFSGETATTRBIT_PATHCONF2 - bits 64<->95
+ */
+#define	NFSGETATTRBIT_PATHCONF2		0
+
+/*
  * Sets of attributes required by readdir and readdirplus.
  * NFSATTRBIT_READDIRPLUS0	(NFSATTRBIT_GETATTR0 | NFSATTRBIT_FILEHANDLE |
  *				 NFSATTRBIT_RDATTRERROR)
@@ -1118,6 +1231,7 @@ struct nfsv3_sattr {
 #define	NFSATTRBIT_READDIRPLUS0	(NFSATTRBIT_GETATTR0 | NFSATTRBM_FILEHANDLE | \
 				NFSATTRBM_RDATTRERROR)
 #define	NFSATTRBIT_READDIRPLUS1	NFSATTRBIT_GETATTR1
+#define	NFSATTRBIT_READDIRPLUS2		0
 
 /*
  * Set of attributes supported by Referral vnodes.
@@ -1125,6 +1239,7 @@ struct nfsv3_sattr {
 #define	NFSATTRBIT_REFERRAL0	(NFSATTRBM_TYPE | NFSATTRBM_FSID |	\
 	NFSATTRBM_RDATTRERROR | NFSATTRBM_FSLOCATIONS)
 #define	NFSATTRBIT_REFERRAL1	NFSATTRBM_MOUNTEDONFILEID
+#define	NFSATTRBIT_REFERRAL2		0
 
 /*
  * Structure for data handled by the statfs rpc. Since some fields are

Modified: head/sys/fs/nfs/nfsrvstate.h
==============================================================================
--- head/sys/fs/nfs/nfsrvstate.h	Tue Jul  1 20:00:35 2014	(r268114)
+++ head/sys/fs/nfs/nfsrvstate.h	Tue Jul  1 20:47:16 2014	(r268115)
@@ -42,6 +42,8 @@ LIST_HEAD(nfsclienthashhead, nfsclient);
 LIST_HEAD(nfsstatehead, nfsstate);
 LIST_HEAD(nfslockhead, nfslock);
 LIST_HEAD(nfslockhashhead, nfslockfile);
+LIST_HEAD(nfssessionhead, nfsdsession);
+LIST_HEAD(nfssessionhashhead, nfsdsession);
 
 /*
  * List head for nfsusrgrp.
@@ -64,6 +66,13 @@ TAILQ_HEAD(nfsuserlruhead, nfsusrgrp);
 	(&nfsgroupnamehash[((l)>=4?(*(p)+*((p)+1)+*((p)+2)+*((p)+3)):*(p)) \
 		% NFSGROUPHASHSIZE])
 
+struct nfssessionhash {
+	struct mtx			mtx;
+	struct nfssessionhashhead	list;
+};
+#define	NFSSESSIONHASH(f) 						\
+	(&nfssessionhash[nfsrv_hashsessionid(f) % NFSSESSIONHASHSIZE])
+
 /*
  * Client server structure for V4. It is doubly linked into two lists.
  * The first is a hash table based on the clientid and the second is a
@@ -76,6 +85,7 @@ struct nfsclient {
 	struct nfsstatehead lc_open;		/* Open owner list */
 	struct nfsstatehead lc_deleg;		/* Delegations */
 	struct nfsstatehead lc_olddeleg;	/* and old delegations */
+	struct nfssessionhead lc_session;	/* List of NFSv4.1 sessions */
 	time_t		lc_expiry;		/* Expiry time (sec) */
 	time_t		lc_delegtime;		/* Old deleg expiry (sec) */
 	nfsquad_t	lc_clientid;		/* 64 bit clientid */
@@ -101,6 +111,43 @@ struct nfsclient {
 #define	CLOPS_RENEWOP		0x0004
 
 /*
+ * Structure for an NFSv4.1 session.
+ * Locking rules for this structure.
+ * To add/delete one of these structures from the lists, you must lock
+ * both: NFSLOCKSESSION(session hashhead) and NFSLOCKSTATE() in that order.
+ * To traverse the lists looking for one of these, you must hold one
+ * of these two locks.
+ * The exception is if the thread holds the exclusive root sleep lock.
+ * In this case, all other nfsd threads are blocked, so locking the
+ * mutexes isn't required.
+ * When manipulating sess_refcnt, NFSLOCKSTATE() must be locked.
+ * When manipulating the fields withinsess_cbsess except nfsess_xprt,
+ * sess_cbsess.nfsess_mtx must be locked.
+ * When manipulating sess_slots and sess_cbsess.nfsess_xprt,
+ * NFSLOCKSESSION(session hashhead) must be locked.
+ */
+struct nfsdsession {
+	uint64_t		sess_refcnt;	/* Reference count. */
+	LIST_ENTRY(nfsdsession)	sess_hash;	/* Hash list of sessions. */
+	LIST_ENTRY(nfsdsession)	sess_list;	/* List of client sessions. */
+	struct nfsslot		sess_slots[NFSV4_SLOTS];
+	struct nfsclient	*sess_clp;	/* Associated clientid. */
+	uint32_t		sess_crflags;
+	uint32_t		sess_cbprogram;
+	uint32_t		sess_maxreq;
+	uint32_t		sess_maxresp;
+	uint32_t		sess_maxrespcached;
+	uint32_t		sess_maxops;
+	uint32_t		sess_maxslots;
+	uint32_t		sess_cbmaxreq;
+	uint32_t		sess_cbmaxresp;
+	uint32_t		sess_cbmaxrespcached;
+	uint32_t		sess_cbmaxops;
+	uint8_t			sess_sessionid[NFSX_V4SESSIONID];
+	struct nfsclsession	sess_cbsess;	/* Callback session. */
+};
+
+/*
  * Nfs state structure. I couldn't resist overloading this one, since
  * it makes cleanup, etc. simpler. These structures are used in four ways:
  * - open_owner structures chained off of nfsclient

Modified: head/sys/fs/nfsclient/nfs_clstate.c
==============================================================================
--- head/sys/fs/nfsclient/nfs_clstate.c	Tue Jul  1 20:00:35 2014	(r268114)
+++ head/sys/fs/nfsclient/nfs_clstate.c	Tue Jul  1 20:47:16 2014	(r268115)
@@ -3548,7 +3548,7 @@ out:
 		if (clp != NULL) {
 			nfsv4_seqsess_cacherep(slotid,
 			    NFSMNT_MDSSESSION(clp->nfsc_nmp)->nfsess_cbslots,
-			    rep);
+			    NFSERR_OK, &rep);
 			NFSUNLOCKCLSTATE();
 		} else {
 			NFSUNLOCKCLSTATE();

Modified: head/sys/fs/nfsserver/nfs_nfsdcache.c
==============================================================================
--- head/sys/fs/nfsserver/nfs_nfsdcache.c	Tue Jul  1 20:00:35 2014	(r268114)
+++ head/sys/fs/nfsserver/nfs_nfsdcache.c	Tue Jul  1 20:47:16 2014	(r268115)
@@ -977,6 +977,9 @@ nfsrvd_refcache(struct nfsrvcache *rp)

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



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