Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 1 Jan 2014 01:46:56 +0000 (UTC)
From:      Rick Macklem <rmacklem@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r260158 - in projects/nfsv4.1-server/sys: conf fs/nfs fs/nfsserver modules/krpc rpc
Message-ID:  <201401010146.s011ku84089718@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rmacklem
Date: Wed Jan  1 01:46:56 2014
New Revision: 260158
URL: http://svnweb.freebsd.org/changeset/base/260158

Log:
  Add backchannel support to the NFSv4.1 server.

Added:
  projects/nfsv4.1-server/sys/rpc/clnt_bck.c   (contents, props changed)
Modified:
  projects/nfsv4.1-server/sys/conf/files
  projects/nfsv4.1-server/sys/fs/nfs/nfs.h
  projects/nfsv4.1-server/sys/fs/nfs/nfs_commonkrpc.c
  projects/nfsv4.1-server/sys/fs/nfs/nfs_commonsubs.c
  projects/nfsv4.1-server/sys/fs/nfs/nfs_var.h
  projects/nfsv4.1-server/sys/fs/nfs/nfsclstate.h
  projects/nfsv4.1-server/sys/fs/nfs/nfsport.h
  projects/nfsv4.1-server/sys/fs/nfs/nfsrvstate.h
  projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdkrpc.c
  projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdserv.c
  projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdstate.c
  projects/nfsv4.1-server/sys/modules/krpc/Makefile
  projects/nfsv4.1-server/sys/rpc/krpc.h
  projects/nfsv4.1-server/sys/rpc/svc.h
  projects/nfsv4.1-server/sys/rpc/svc_vc.c

Modified: projects/nfsv4.1-server/sys/conf/files
==============================================================================
--- projects/nfsv4.1-server/sys/conf/files	Wed Jan  1 01:26:39 2014	(r260157)
+++ projects/nfsv4.1-server/sys/conf/files	Wed Jan  1 01:46:56 2014	(r260158)
@@ -3749,6 +3749,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: projects/nfsv4.1-server/sys/fs/nfs/nfs.h
==============================================================================
--- projects/nfsv4.1-server/sys/fs/nfs/nfs.h	Wed Jan  1 01:26:39 2014	(r260157)
+++ projects/nfsv4.1-server/sys/fs/nfs/nfs.h	Wed Jan  1 01:46:56 2014	(r260158)
@@ -281,6 +281,7 @@ struct nfsreferral {
 #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 */
 
@@ -588,6 +589,7 @@ struct nfsrv_descript {
 	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

Modified: projects/nfsv4.1-server/sys/fs/nfs/nfs_commonkrpc.c
==============================================================================
--- projects/nfsv4.1-server/sys/fs/nfs/nfs_commonkrpc.c	Wed Jan  1 01:26:39 2014	(r260157)
+++ projects/nfsv4.1-server/sys/fs/nfs/nfs_commonkrpc.c	Wed Jan  1 01:46:56 2014	(r260158)
@@ -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: projects/nfsv4.1-server/sys/fs/nfs/nfs_commonsubs.c
==============================================================================
--- projects/nfsv4.1-server/sys/fs/nfs/nfs_commonsubs.c	Wed Jan  1 01:26:39 2014	(r260157)
+++ projects/nfsv4.1-server/sys/fs/nfs/nfs_commonsubs.c	Wed Jan  1 01:46:56 2014	(r260158)
@@ -3744,9 +3744,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;
@@ -3759,7 +3786,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;
@@ -3770,10 +3797,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,
@@ -3789,21 +3817,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: projects/nfsv4.1-server/sys/fs/nfs/nfs_var.h
==============================================================================
--- projects/nfsv4.1-server/sys/fs/nfs/nfs_var.h	Wed Jan  1 01:26:39 2014	(r260157)
+++ projects/nfsv4.1-server/sys/fs/nfs/nfs_var.h	Wed Jan  1 01:46:56 2014	(r260158)
@@ -292,6 +292,8 @@ int nfsv4_seqsession(uint32_t, uint32_t,
 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 */

Modified: projects/nfsv4.1-server/sys/fs/nfs/nfsclstate.h
==============================================================================
--- projects/nfsv4.1-server/sys/fs/nfs/nfsclstate.h	Wed Jan  1 01:26:39 2014	(r260157)
+++ projects/nfsv4.1-server/sys/fs/nfs/nfsclstate.h	Wed Jan  1 01:46:56 2014	(r260158)
@@ -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: projects/nfsv4.1-server/sys/fs/nfs/nfsport.h
==============================================================================
--- projects/nfsv4.1-server/sys/fs/nfs/nfsport.h	Wed Jan  1 01:26:39 2014	(r260157)
+++ projects/nfsv4.1-server/sys/fs/nfs/nfsport.h	Wed Jan  1 01:46:56 2014	(r260158)
@@ -638,6 +638,7 @@ 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))
 

Modified: projects/nfsv4.1-server/sys/fs/nfs/nfsrvstate.h
==============================================================================
--- projects/nfsv4.1-server/sys/fs/nfs/nfsrvstate.h	Wed Jan  1 01:26:39 2014	(r260157)
+++ projects/nfsv4.1-server/sys/fs/nfs/nfsrvstate.h	Wed Jan  1 01:46:56 2014	(r260158)
@@ -112,8 +112,22 @@ struct nfsclient {
 
 /*
  * 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];
@@ -129,8 +143,8 @@ struct nfsdsession {
 	uint32_t		sess_cbmaxresp;
 	uint32_t		sess_cbmaxrespcached;
 	uint32_t		sess_cbmaxops;
-	uint32_t		sess_cbmaxslots;
 	uint8_t			sess_sessionid[NFSX_V4SESSIONID];
+	struct nfsclsession	sess_cbsess;	/* Callback session. */
 };
 
 /*

Modified: projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdkrpc.c
==============================================================================
--- projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdkrpc.c	Wed Jan  1 01:26:39 2014	(r260157)
+++ projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdkrpc.c	Wed Jan  1 01:46:56 2014	(r260158)
@@ -98,7 +98,7 @@ SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_m
     &nfs_maxvers, 0, "The highest version of NFS handled by the server");
 
 static int nfs_proc(struct nfsrv_descript *, u_int32_t, struct socket *,
-    u_int64_t, struct nfsrvcache **);
+    u_int64_t, SVCXPRT *, struct nfsrvcache **);
 
 extern u_long sb_max_adj;
 extern int newnfs_numnfsd;
@@ -252,7 +252,7 @@ nfssvc_program(struct svc_req *rqst, SVC
 		}
 
 		cacherep = nfs_proc(&nd, rqst->rq_xid, xprt->xp_socket,
-		    xprt->xp_sockref, &rp);
+		    xprt->xp_sockref, xprt, &rp);
 		NFSLOCKV4ROOTMUTEX();
 		nfsv4_relref(&nfsd_suspend_lock);
 		NFSUNLOCKV4ROOTMUTEX();
@@ -301,7 +301,7 @@ out:
  */
 static int
 nfs_proc(struct nfsrv_descript *nd, u_int32_t xid, struct socket *so,
-    u_int64_t sockref, struct nfsrvcache **rpp)
+    u_int64_t sockref, SVCXPRT *xprt, struct nfsrvcache **rpp)
 {
 	struct thread *td = curthread;
 	int cacherep = RC_DOIT, isdgram, taglen = -1;
@@ -357,6 +357,8 @@ nfs_proc(struct nfsrv_descript *nd, u_in
 	 * RC_DROPIT - just throw the request away
 	 */
 	if (cacherep == RC_DOIT) {
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			nd->nd_xprt = xprt;
 		nfsrvd_dorpc(nd, isdgram, tagstr, taglen, minorvers, td);
 		if ((nd->nd_flag & ND_NFSV41) != 0) {
 			if (nd->nd_repstat != NFSERR_REPLYFROMCACHE &&

Modified: projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdserv.c
==============================================================================
--- projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdserv.c	Wed Jan  1 01:26:39 2014	(r260157)
+++ projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdserv.c	Wed Jan  1 01:46:56 2014	(r260158)
@@ -666,10 +666,14 @@ nfsrvd_read(struct nfsrv_descript *nd, _
 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 		clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
 		clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
-		if (nd->nd_flag & ND_IMPLIEDCLID) {
-			if (nd->nd_clientid.qval != clientid.qval)
-				printf("EEK! multiple clids\n");
+		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
+			if ((nd->nd_flag & ND_NFSV41) != 0)
+				clientid.qval = nd->nd_clientid.qval;
+			else if (nd->nd_clientid.qval != clientid.qval)
+				printf("EEK1 multiple clids\n");
 		} else {
+			if ((nd->nd_flag & ND_NFSV41) != 0)
+				printf("EEK! no clientid from session\n");
 			nd->nd_flag |= ND_IMPLIEDCLID;
 			nd->nd_clientid.qval = clientid.qval;
 		}
@@ -818,10 +822,14 @@ nfsrvd_write(struct nfsrv_descript *nd, 
 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 		clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
 		clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
-		if (nd->nd_flag & ND_IMPLIEDCLID) {
-			if (nd->nd_clientid.qval != clientid.qval)
-				printf("EEK! multiple clids\n");
+		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
+			if ((nd->nd_flag & ND_NFSV41) != 0)
+				clientid.qval = nd->nd_clientid.qval;
+			else if (nd->nd_clientid.qval != clientid.qval)
+				printf("EEK2 multiple clids\n");
 		} else {
+			if ((nd->nd_flag & ND_NFSV41) != 0)
+				printf("EEK! no clientid from session\n");
 			nd->nd_flag |= ND_IMPLIEDCLID;
 			nd->nd_clientid.qval = clientid.qval;
 		}
@@ -2196,10 +2204,14 @@ nfsrvd_lock(struct nfsrv_descript *nd, _
 		stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
 		clientid.lval[0] = *tl++;
 		clientid.lval[1] = *tl++;
-		if (nd->nd_flag & ND_IMPLIEDCLID) {
-			if (nd->nd_clientid.qval != clientid.qval)
-				printf("EEK! multiple clids\n");
+		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
+			if ((nd->nd_flag & ND_NFSV41) != 0)
+				clientid.qval = nd->nd_clientid.qval;
+			else if (nd->nd_clientid.qval != clientid.qval)
+				printf("EEK3 multiple clids\n");
 		} else {
+			if ((nd->nd_flag & ND_NFSV41) != 0)
+				printf("EEK! no clientid from session\n");
 			nd->nd_flag |= ND_IMPLIEDCLID;
 			nd->nd_clientid.qval = clientid.qval;
 		}
@@ -2219,10 +2231,14 @@ nfsrvd_lock(struct nfsrv_descript *nd, _
 		stp->ls_seq = fxdr_unsigned(int, *tl);
 		clientid.lval[0] = stp->ls_stateid.other[0];
 		clientid.lval[1] = stp->ls_stateid.other[1];
-		if (nd->nd_flag & ND_IMPLIEDCLID) {
-			if (nd->nd_clientid.qval != clientid.qval)
-				printf("EEK! multiple clids\n");
+		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
+			if ((nd->nd_flag & ND_NFSV41) != 0)
+				clientid.qval = nd->nd_clientid.qval;
+			else if (nd->nd_clientid.qval != clientid.qval)
+				printf("EEK4 multiple clids\n");
 		} else {
+			if ((nd->nd_flag & ND_NFSV41) != 0)
+				printf("EEK! no clientid from session\n");
 			nd->nd_flag |= ND_IMPLIEDCLID;
 			nd->nd_clientid.qval = clientid.qval;
 		}
@@ -2368,10 +2384,14 @@ nfsrvd_lockt(struct nfsrv_descript *nd, 
 	tl += 2;
 	clientid.lval[0] = *tl++;
 	clientid.lval[1] = *tl;
-	if (nd->nd_flag & ND_IMPLIEDCLID) {
-		if (nd->nd_clientid.qval != clientid.qval)
-			printf("EEK! multiple clids\n");
+	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			clientid.qval = nd->nd_clientid.qval;
+		else if (nd->nd_clientid.qval != clientid.qval)
+			printf("EEK5 multiple clids\n");
 	} else {
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			printf("EEK! no clientid from session\n");
 		nd->nd_flag |= ND_IMPLIEDCLID;
 		nd->nd_clientid.qval = clientid.qval;
 	}
@@ -2479,10 +2499,14 @@ nfsrvd_locku(struct nfsrv_descript *nd, 
 	}
 	clientid.lval[0] = stp->ls_stateid.other[0];
 	clientid.lval[1] = stp->ls_stateid.other[1];
-	if (nd->nd_flag & ND_IMPLIEDCLID) {
-		if (nd->nd_clientid.qval != clientid.qval)
-			printf("EEK! multiple clids\n");
+	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			clientid.qval = nd->nd_clientid.qval;
+		else if (nd->nd_clientid.qval != clientid.qval)
+			printf("EEK6 multiple clids\n");
 	} else {
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			printf("EEK! no clientid from session\n");
 		nd->nd_flag |= ND_IMPLIEDCLID;
 		nd->nd_clientid.qval = clientid.qval;
 	}
@@ -2601,10 +2625,14 @@ nfsrvd_open(struct nfsrv_descript *nd, _
 	};
 	clientid.lval[0] = *tl++;
 	clientid.lval[1] = *tl;
-	if (nd->nd_flag & ND_IMPLIEDCLID) {
-		if (nd->nd_clientid.qval != clientid.qval)
-			printf("EEK! multiple clids\n");
+	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			clientid.qval = nd->nd_clientid.qval;
+		else if (nd->nd_clientid.qval != clientid.qval)
+			printf("EEK7 multiple clids\n");
 	} else {
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			printf("EEK! no clientid from session\n");
 		nd->nd_flag |= ND_IMPLIEDCLID;
 		nd->nd_clientid.qval = clientid.qval;
 	}
@@ -2954,10 +2982,14 @@ nfsrvd_close(struct nfsrv_descript *nd, 
 	stp->ls_flags = NFSLCK_CLOSE;
 	clientid.lval[0] = stp->ls_stateid.other[0];
 	clientid.lval[1] = stp->ls_stateid.other[1];
-	if (nd->nd_flag & ND_IMPLIEDCLID) {
-		if (nd->nd_clientid.qval != clientid.qval)
-			printf("EEK! multiple clids\n");
+	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			clientid.qval = nd->nd_clientid.qval;
+		else if (nd->nd_clientid.qval != clientid.qval)
+			printf("EEK8 multiple clids\n");
 	} else {
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			printf("EEK! no clientid from session\n");
 		nd->nd_flag |= ND_IMPLIEDCLID;
 		nd->nd_clientid.qval = clientid.qval;
 	}
@@ -2994,10 +3026,14 @@ nfsrvd_delegpurge(struct nfsrv_descript 
 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 	clientid.lval[0] = *tl++;
 	clientid.lval[1] = *tl;
-	if (nd->nd_flag & ND_IMPLIEDCLID) {
-		if (nd->nd_clientid.qval != clientid.qval)
-			printf("EEK! multiple clids\n");
+	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			clientid.qval = nd->nd_clientid.qval;
+		else if (nd->nd_clientid.qval != clientid.qval)
+			printf("EEK9 multiple clids\n");
 	} else {
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			printf("EEK! no clientid from session\n");
 		nd->nd_flag |= ND_IMPLIEDCLID;
 		nd->nd_clientid.qval = clientid.qval;
 	}
@@ -3025,10 +3061,14 @@ nfsrvd_delegreturn(struct nfsrv_descript
 	NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
 	clientid.lval[0] = stateid.other[0];
 	clientid.lval[1] = stateid.other[1];
-	if (nd->nd_flag & ND_IMPLIEDCLID) {
-		if (nd->nd_clientid.qval != clientid.qval)
-			printf("EEK! multiple clids\n");
+	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			clientid.qval = nd->nd_clientid.qval;
+		else if (nd->nd_clientid.qval != clientid.qval)
+			printf("EEK10 multiple clids\n");
 	} else {
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			printf("EEK! no clientid from session\n");
 		nd->nd_flag |= ND_IMPLIEDCLID;
 		nd->nd_clientid.qval = clientid.qval;
 	}
@@ -3086,10 +3126,14 @@ nfsrvd_openconfirm(struct nfsrv_descript
 	stp->ls_flags = NFSLCK_CONFIRM;
 	clientid.lval[0] = stp->ls_stateid.other[0];
 	clientid.lval[1] = stp->ls_stateid.other[1];
-	if (nd->nd_flag & ND_IMPLIEDCLID) {
-		if (nd->nd_clientid.qval != clientid.qval)
-			printf("EEK! multiple clids\n");
+	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			clientid.qval = nd->nd_clientid.qval;
+		else if (nd->nd_clientid.qval != clientid.qval)
+			printf("EEK11 multiple clids\n");
 	} else {
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			printf("EEK! no clientid from session\n");
 		nd->nd_flag |= ND_IMPLIEDCLID;
 		nd->nd_clientid.qval = clientid.qval;
 	}
@@ -3162,10 +3206,14 @@ nfsrvd_opendowngrade(struct nfsrv_descri
 
 	clientid.lval[0] = stp->ls_stateid.other[0];
 	clientid.lval[1] = stp->ls_stateid.other[1];
-	if (nd->nd_flag & ND_IMPLIEDCLID) {
-		if (nd->nd_clientid.qval != clientid.qval)
-			printf("EEK! multiple clids\n");
+	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			clientid.qval = nd->nd_clientid.qval;
+		else if (nd->nd_clientid.qval != clientid.qval)
+			printf("EEK12 multiple clids\n");
 	} else {
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			printf("EEK! no clientid from session\n");
 		nd->nd_flag |= ND_IMPLIEDCLID;
 		nd->nd_clientid.qval = clientid.qval;
 	}
@@ -3205,10 +3253,14 @@ nfsrvd_renew(struct nfsrv_descript *nd, 
 	NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 	clientid.lval[0] = *tl++;
 	clientid.lval[1] = *tl;
-	if (nd->nd_flag & ND_IMPLIEDCLID) {
-		if (nd->nd_clientid.qval != clientid.qval)
-			printf("EEK! multiple clids\n");
+	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			clientid.qval = nd->nd_clientid.qval;
+		else if (nd->nd_clientid.qval != clientid.qval)
+			printf("EEK13 multiple clids\n");
 	} else {
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			printf("EEK! no clientid from session\n");
 		nd->nd_flag |= ND_IMPLIEDCLID;
 		nd->nd_clientid.qval = clientid.qval;
 	}
@@ -3569,10 +3621,14 @@ nfsrvd_releaselckown(struct nfsrv_descri
 	stp->ls_uid = nd->nd_cred->cr_uid;
 	clientid.lval[0] = *tl++;
 	clientid.lval[1] = *tl;
-	if (nd->nd_flag & ND_IMPLIEDCLID) {
-		if (nd->nd_clientid.qval != clientid.qval)
-			printf("EEK! multiple clids\n");
+	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			clientid.qval = nd->nd_clientid.qval;
+		else if (nd->nd_clientid.qval != clientid.qval)
+			printf("EEK14 multiple clids\n");
 	} else {
+		if ((nd->nd_flag & ND_NFSV41) != 0)
+			printf("EEK! no clientid from session\n");
 		nd->nd_flag |= ND_IMPLIEDCLID;
 		nd->nd_clientid.qval = clientid.qval;
 	}
@@ -3634,13 +3690,13 @@ nfsrvd_exchangeid(struct nfsrv_descript 
 	if (error != 0)
 		goto nfsmout;
 	if ((nd->nd_flag & ND_GSS) != 0) {
-		clp->lc_flags = LCL_GSS;
+		clp->lc_flags = LCL_GSS | LCL_NFSV41;
 		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;
+		clp->lc_flags = LCL_NFSV41;
 	if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
 		clp->lc_flags |= LCL_NAME;
 		clp->lc_namelen = nd->nd_princlen;
@@ -3737,6 +3793,8 @@ nfsrvd_createsession(struct nfsrv_descri
 	}
 	sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
 	    M_NFSDSESSION, M_WAITOK | M_ZERO);
+	sep->sess_refcnt = 1;
+	mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
 	NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
 	clientid.lval[0] = *tl++;
 	clientid.lval[1] = *tl++;
@@ -3769,7 +3827,7 @@ nfsrvd_createsession(struct nfsrv_descri
 	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++);
+	sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
 	rdmacnt = fxdr_unsigned(uint32_t, *tl);
 	if (rdmacnt > 1) {
 		nd->nd_repstat = NFSERR_BADXDR;
@@ -3809,7 +3867,7 @@ nfsrvd_createsession(struct nfsrv_descri
 		*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(sep->sess_cbsess.nfsess_foreslots);
 		*tl++ = txdr_unsigned(1);
 		*tl = txdr_unsigned(0);			/* No RDMA. */
 	}

Modified: projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdstate.c
==============================================================================
--- projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdstate.c	Wed Jan  1 01:26:39 2014	(r260157)
+++ projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdstate.c	Wed Jan  1 01:46:56 2014	(r260158)
@@ -95,6 +95,8 @@ static int nfsrv_checkgrace(struct nfsrv
 static int nfsrv_docallback(struct nfsclient *clp, int procnum,
     nfsv4stateid_t *stateidp, int trunc, fhandle_t *fhp,
     struct nfsvattr *nap, nfsattrbit_t *attrbitp, NFSPROC_T *p);
+static int nfsrv_cbcallargs(struct nfsrv_descript *nd, struct nfsclient *clp,
+    uint32_t callback, int op, const char *optag, struct nfsdsession **sepp);
 static u_int32_t nfsrv_nextclientindex(void);
 static u_int32_t nfsrv_nextstateindex(struct nfsclient *clp);
 static void nfsrv_markstable(struct nfsclient *clp);
@@ -127,6 +129,9 @@ static void nfsrv_locklf(struct nfslockf
 static void nfsrv_unlocklf(struct nfslockfile *lfp);
 static struct nfsdsession *nfsrv_findsession(uint8_t *sessionid);
 static int nfsrv_freesession(struct nfsdsession *sep, uint8_t *sessionid);
+static int nfsv4_setcbsequence(struct nfsrv_descript *nd, struct nfsclient *clp,
+    int dont_replycache, struct nfsdsession **sepp);
+static int nfsv4_getcbsession(struct nfsclient *clp, struct nfsdsession **sepp);
 
 /*
  * Scan the client list for a match and either return the current one,
@@ -148,6 +153,7 @@ nfsrv_setclient(struct nfsrv_descript *n
 	/*
 	 * Check for state resource limit exceeded.
 	 */
+printf("in nfsrv_setcl\n");
 	if (nfsrv_openpluslock > NFSRV_V4STATELIMIT) {
 		error = NFSERR_RESOURCE;
 		goto out;
@@ -205,6 +211,7 @@ nfsrv_setclient(struct nfsrv_descript *n
 			NFSUNLOCKV4ROOTMUTEX();
 			confirmp->lval[1] = 0;
 			error = NFSERR_NOENT;
+printf("reconfirming\n");
 			goto out;
 		}
 		/*
@@ -252,6 +259,7 @@ nfsrv_setclient(struct nfsrv_descript *n
 		if (zapit)
 			nfsrv_zapclient(clp, p);
 		*new_clpp = NULL;
+printf("new cl\n");
 		goto out;
 	}
 
@@ -367,6 +375,7 @@ nfsrv_setclient(struct nfsrv_descript *n
 		NFSUNLOCKSTATE();
 		nfsrv_zapclient(clp, p);
 		*new_clpp = NULL;
+printf("new cl2\n");
 		goto out;
 	}
 
@@ -411,6 +420,7 @@ nfsrv_setclient(struct nfsrv_descript *n
 		newnfsstats.srvclients++;
 		nfsrv_openpluslock++;
 		nfsrv_clients++;
+printf("new cl3\n");
 	}
 	NFSLOCKV4ROOTMUTEX();
 	nfsv4_unlock(&nfsv4rootfs_lock, 1);
@@ -568,15 +578,39 @@ nfsrv_getclient(nfsquad_t clientid, int 
 		    clp->lc_flags &= ~(LCL_NEEDSCONFIRM | LCL_DONTCLEAN);
 		    if (clp->lc_program)
 			clp->lc_flags |= LCL_NEEDSCBNULL;
+printf("prog=%d\n", clp->lc_program);
 		    /* For NFSv4.1, link the session onto the client. */
 		    if (nsep != NULL) {
+printf("nsep not null\n");
+			/* Hold a reference on the xprt for a backchannel. */
+			if ((nsep->sess_crflags & NFSV4CRSESS_CONNBACKCHAN)
+			    != 0 && clp->lc_req.nr_client == NULL) {
+printf("set backch\n");
+			    clp->lc_req.nr_client = (struct __rpc_client *)
+				clnt_bck_create(nd->nd_xprt->xp_socket,
+				cbprogram, NFSV4_CBVERS);
+printf("cbcl=%p\n", clp->lc_req.nr_client);
+			    if (clp->lc_req.nr_client != NULL) {
+				SVC_ACQUIRE(nd->nd_xprt);
+				nd->nd_xprt->xp_p2 =
+				    clp->lc_req.nr_client->cl_private;
+				/* Disable idle timeout. */
+				nd->nd_xprt->xp_idletimeout = 0;
+				nsep->sess_cbsess.nfsess_xprt = nd->nd_xprt;
+			    } else
+				nsep->sess_crflags &= ~NFSV4CRSESS_CONNBACKCHAN;
+			}
 			NFSBCOPY(sessid, nsep->sess_sessionid,
 			    NFSX_V4SESSIONID);
+			NFSBCOPY(sessid, nsep->sess_cbsess.nfsess_sessionid,
+			    NFSX_V4SESSIONID);
 			shp = NFSSESSIONHASH(nsep->sess_sessionid);
 			NFSLOCKSESSION(shp);
 			LIST_INSERT_HEAD(&shp->list, nsep, sess_hash);
+			NFSLOCKSTATE();
 			LIST_INSERT_HEAD(&clp->lc_session, nsep, sess_list);
 			nsep->sess_clp = clp;
+			NFSUNLOCKSTATE();
 			NFSUNLOCKSESSION(shp);
 		    }
 		}
@@ -3835,9 +3869,7 @@ nfsrv_checkgrace(struct nfsrv_descript *
 {
 	int error = 0;
 
-	if ((nfsrv_stablefirst.nsf_flags & NFSNSF_GRACEOVER) != 0 ||
-	    (nd != NULL && clp != NULL && (nd->nd_flag & ND_NFSV41) != 0 &&
-	     (clp->lc_flags & LCL_RECLAIMCOMPLETE) != 0)) {
+	if ((nfsrv_stablefirst.nsf_flags & NFSNSF_GRACEOVER) != 0) {
 		if (flags & NFSLCK_RECLAIM) {
 			error = NFSERR_NOGRACE;
 			goto out;
@@ -3847,6 +3879,12 @@ nfsrv_checkgrace(struct nfsrv_descript *
 			error = NFSERR_GRACE;
 			goto out;
 		}
+		if (nd != NULL && clp != NULL &&
+		    (nd->nd_flag & ND_NFSV41) != 0 &&
+		    (clp->lc_flags & LCL_RECLAIMCOMPLETE) != 0) {
+			error = NFSERR_NOGRACE;
+			goto out;
+		}
 
 		/*
 		 * If grace is almost over and we are still getting Reclaims,
@@ -3877,6 +3915,7 @@ nfsrv_docallback(struct nfsclient *clp, 
 	struct ucred *cred;
 	int error = 0;
 	u_int32_t callback;
+	struct nfsdsession *sep = NULL;
 
 	cred = newnfs_getcred();
 	NFSLOCKSTATE();	/* mostly for lc_cbref++ */
@@ -3891,7 +3930,12 @@ nfsrv_docallback(struct nfsclient *clp, 
 	 * structure for newnfs_connect() to use.
 	 */
 	clp->lc_req.nr_prog = clp->lc_program;
-	clp->lc_req.nr_vers = NFSV4_CBVERS;
+#ifdef notnow
+	if ((clp->lc_flags & LCL_NFSV41) != 0)
+		clp->lc_req.nr_vers = NFSV41_CBVERS;
+	else
+#endif
+		clp->lc_req.nr_vers = NFSV4_CBVERS;
 
 	/*
 	 * First, fill in some of the fields of nd and cr.
@@ -3899,6 +3943,8 @@ nfsrv_docallback(struct nfsclient *clp, 
 	nd->nd_flag = ND_NFSV4;
 	if (clp->lc_flags & LCL_GSS)
 		nd->nd_flag |= ND_KERBV;
+	if ((clp->lc_flags & LCL_NFSV41) != 0)
+		nd->nd_flag |= ND_NFSV41;
 	nd->nd_repstat = 0;
 	cred->cr_uid = clp->lc_uid;
 	cred->cr_gid = clp->lc_gid;
@@ -3919,22 +3965,23 @@ nfsrv_docallback(struct nfsclient *clp, 
 	 */
 	if (procnum == NFSV4OP_CBGETATTR) {
 		nd->nd_procnum = NFSV4PROC_CBCOMPOUND;
-		(void) nfsm_strtom(nd, "CB Getattr", 10);
-		NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
-		*tl++ = txdr_unsigned(NFSV4_MINORVERSION);
-		*tl++ = txdr_unsigned(callback);
-		*tl++ = txdr_unsigned(1);
-		*tl = txdr_unsigned(NFSV4OP_CBGETATTR);
-		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, NFSX_MYFH, 0);
-		(void) nfsrv_putattrbit(nd, attrbitp);
+		error = nfsrv_cbcallargs(nd, clp, callback, NFSV4OP_CBGETATTR,
+		    "CB Getattr", &sep);
+		if (error != 0) {
+			mbuf_freem(nd->nd_mreq);
+			goto errout;
+		}
+		(void)nfsm_fhtom(nd, (u_int8_t *)fhp, NFSX_MYFH, 0);
+		(void)nfsrv_putattrbit(nd, attrbitp);
 	} else if (procnum == NFSV4OP_CBRECALL) {
 		nd->nd_procnum = NFSV4PROC_CBCOMPOUND;
-		(void) nfsm_strtom(nd, "CB Recall", 9);
-		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
-		*tl++ = txdr_unsigned(NFSV4_MINORVERSION);
-		*tl++ = txdr_unsigned(callback);
-		*tl++ = txdr_unsigned(1);
-		*tl++ = txdr_unsigned(NFSV4OP_CBRECALL);
+		error = nfsrv_cbcallargs(nd, clp, callback, NFSV4OP_CBRECALL,
+		    "CB Recall", &sep);
+		if (error != 0) {
+			mbuf_freem(nd->nd_mreq);
+			goto errout;
+		}
+		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
 		*tl++ = txdr_unsigned(stateidp->seqid);
 		NFSBCOPY((caddr_t)stateidp->other, (caddr_t)tl,
 		    NFSX_STATEIDOTHER);
@@ -3943,9 +3990,18 @@ nfsrv_docallback(struct nfsclient *clp, 
 			*tl = newnfs_true;
 		else
 			*tl = newnfs_false;
-		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, NFSX_MYFH, 0);
-	} else {
+		(void)nfsm_fhtom(nd, (u_int8_t *)fhp, NFSX_MYFH, 0);
+	} else if (procnum == NFSV4PROC_CBNULL) {
 		nd->nd_procnum = NFSV4PROC_CBNULL;
+		error = nfsv4_getcbsession(clp, &sep);
+		if (error != 0) {
+			mbuf_freem(nd->nd_mreq);
+			goto errout;
+		}
+	} else {
+		error = NFSERR_SERVERFAULT;
+		mbuf_freem(nd->nd_mreq);
+		goto errout;
 	}
 
 	/*
@@ -3953,7 +4009,9 @@ nfsrv_docallback(struct nfsclient *clp, 
 	 */
 	(void) newnfs_sndlock(&clp->lc_req.nr_lock);
 	if (clp->lc_req.nr_client == NULL) {
-		if (nd->nd_procnum == NFSV4PROC_CBNULL)
+		if ((clp->lc_flags & LCL_NFSV41) != 0)
+			error = ECONNREFUSED;
+		else if (nd->nd_procnum == NFSV4PROC_CBNULL)
 			error = newnfs_connect(NULL, &clp->lc_req, cred,
 			    NULL, 1);
 		else
@@ -3962,10 +4020,19 @@ nfsrv_docallback(struct nfsclient *clp, 
 	}
 	newnfs_sndunlock(&clp->lc_req.nr_lock);
 	if (!error) {
-		error = newnfs_request(nd, NULL, clp, &clp->lc_req, NULL,
-		    NULL, cred, clp->lc_program, NFSV4_CBVERS, NULL, 1, NULL,
-		    NULL);
+		if ((nd->nd_flag & ND_NFSV41) != 0) {
+			KASSERT(sep != NULL, ("sep NULL"));
+			error = newnfs_request(nd, NULL, clp, &clp->lc_req,
+			    NULL, NULL, cred, clp->lc_program,
+			    clp->lc_req.nr_vers, NULL, 1, NULL,
+			    &sep->sess_cbsess);
+			nfsrv_freesession(sep, NULL);
+		} else
+			error = newnfs_request(nd, NULL, clp, &clp->lc_req,
+			    NULL, NULL, cred, clp->lc_program,
+			    clp->lc_req.nr_vers, NULL, 1, NULL, NULL);
 	}
+errout:
 	NFSFREECRED(cred);
 
 	/*
@@ -3995,7 +4062,7 @@ nfsrv_docallback(struct nfsclient *clp, 
 		NFSUNLOCKSTATE();
 		if (nd->nd_repstat)
 			error = nd->nd_repstat;
-		else if (procnum == NFSV4OP_CBGETATTR)
+		else if (error == 0 && procnum == NFSV4OP_CBGETATTR)
 			error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
 			    NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL,
 			    p, NULL);
@@ -4014,6 +4081,38 @@ nfsrv_docallback(struct nfsclient *clp, 
 }
 
 /*
+ * Set up the compound RPC for the callback.
+ */
+static int
+nfsrv_cbcallargs(struct nfsrv_descript *nd, struct nfsclient *clp,
+    uint32_t callback, int op, const char *optag, struct nfsdsession **sepp)
+{
+	uint32_t *tl;
+	int error, len;
+
+	len = strlen(optag);
+	(void)nfsm_strtom(nd, optag, len);
+	NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
+	if ((nd->nd_flag & ND_NFSV41) != 0) {
+		*tl++ = txdr_unsigned(NFSV41_MINORVERSION);
+		*tl++ = txdr_unsigned(callback);
+		*tl++ = txdr_unsigned(2);
+		*tl = txdr_unsigned(NFSV4OP_CBSEQUENCE);
+		error = nfsv4_setcbsequence(nd, clp, 1, sepp);
+		if (error != 0)
+			return (error);
+		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+		*tl = txdr_unsigned(op);
+	} else {
+		*tl++ = txdr_unsigned(NFSV4_MINORVERSION);
+		*tl++ = txdr_unsigned(callback);
+		*tl++ = txdr_unsigned(1);
+		*tl = txdr_unsigned(op);
+	}
+	return (0);
+}
+
+/*
  * Return the next index# for a clientid. Mostly just increment and return
  * the next one, but... if the 32bit unsigned does actually wrap around,
  * it should be rebooted.
@@ -5476,7 +5575,9 @@ nfsrv_checksequence(struct nfsrv_descrip
 {
 	struct nfsdsession *sep;
 	struct nfssessionhash *shp;
+	CLIENT *cl;
 	int error;
+	SVCXPRT *savxprt;
 
 	shp = NFSSESSIONHASH(nd->nd_sessionid);
 	NFSLOCKSESSION(shp);
@@ -5495,6 +5596,26 @@ nfsrv_checksequence(struct nfsrv_descrip
 		nd->nd_flag |= ND_SAVEREPLY;
 	/* Renew the lease. */
 	sep->sess_clp->lc_expiry = nfsrv_leaseexpiry();
+	nd->nd_clientid.qval = sep->sess_clp->lc_clientid.qval;
+	nd->nd_flag |= ND_IMPLIEDCLID;
+
+	/*
+	 * If this session handles the backchannel, save the nd_xprt for this
+	 * RPC, since this is the one being used.
+	 */
+	if (sep->sess_cbsess.nfsess_xprt != NULL &&
+	    (sep->sess_crflags & NFSV4CRSESS_CONNBACKCHAN) != 0) {
+		savxprt = sep->sess_cbsess.nfsess_xprt;
+		SVC_ACQUIRE(nd->nd_xprt);
+		nd->nd_xprt->xp_p2 = savxprt->xp_p2;
+		nd->nd_xprt->xp_idletimeout = 0;	/* Disable timeout. */
+		sep->sess_cbsess.nfsess_xprt = nd->nd_xprt;
+		SVC_RELEASE(savxprt);
+	}
+
+	cl = sep->sess_clp->lc_req.nr_client;
+	if (cl == NULL)
+		*sflagsp |= NFSV4SEQ_CBPATHDOWN;
 	NFSUNLOCKSESSION(shp);
 	*sflagsp = 0;
 	if (error == NFSERR_EXPIRED) {
@@ -5616,8 +5737,16 @@ nfsrv_freesession(struct nfsdsession *se
 		NFSLOCKSESSION(shp);
 	}
 	if (sep != NULL) {
+		NFSLOCKSTATE();
+		sep->sess_refcnt--;
+		if (sep->sess_refcnt > 0) {
+			NFSUNLOCKSTATE();
+			NFSUNLOCKSESSION(shp);
+			return (0);
+		}
 		LIST_REMOVE(sep, sess_hash);
 		LIST_REMOVE(sep, sess_list);
+		NFSUNLOCKSTATE();
 	}
 	NFSUNLOCKSESSION(shp);
 	if (sep == NULL)
@@ -5625,6 +5754,8 @@ nfsrv_freesession(struct nfsdsession *se
 	for (i = 0; i < NFSV4_SLOTS; i++)
 		if (sep->sess_slots[i].nfssl_reply != NULL)
 			m_freem(sep->sess_slots[i].nfssl_reply);
+	if (sep->sess_cbsess.nfsess_xprt != NULL)
+		SVC_RELEASE(sep->sess_cbsess.nfsess_xprt);
 	free(sep, M_NFSDSESSION);
 	return (0);
 }
@@ -5678,3 +5809,64 @@ nfsrv_freestateid(struct nfsrv_descript 
 	return (error);
 }
 
+/*
+ * Generate the xdr for an NFSv4.1 CBSequence Operation.
+ */
+static int
+nfsv4_setcbsequence(struct nfsrv_descript *nd, struct nfsclient *clp,
+    int dont_replycache, struct nfsdsession **sepp)
+{
+	struct nfsdsession *sep;
+	uint32_t *tl, slotseq = 0;
+	int maxslot, slotpos;
+	uint8_t sessionid[NFSX_V4SESSIONID];
+	int error;
+
+	error = nfsv4_getcbsession(clp, sepp);
+	if (error != 0)
+		return (error);
+	sep = *sepp;
+	(void)nfsv4_sequencelookup(NULL, &sep->sess_cbsess, &slotpos, &maxslot,
+	    &slotseq, sessionid);
+	KASSERT(maxslot >= 0, ("nfsv4_setcbsequence neg maxslot"));
+
+	/* Build the Sequence arguments. */
+	NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 5 * 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;
+	*tl = 0;			/* No referring call list, for now. */
+	nd->nd_flag |= ND_HASSEQUENCE;
+	return (0);
+}
+
+/*
+ * Get a session for the callback.
+ */
+static int
+nfsv4_getcbsession(struct nfsclient *clp, struct nfsdsession **sepp)
+{
+	struct nfsdsession *sep;
+
+	NFSLOCKSTATE();
+	LIST_FOREACH(sep, &clp->lc_session, sess_list) {
+		if ((sep->sess_crflags & NFSV4CRSESS_CONNBACKCHAN) != 0)
+			break;
+	}
+	if (sep == NULL) {
+		NFSUNLOCKSTATE();
+		return (NFSERR_BADSESSION);
+	}
+	sep->sess_refcnt++;
+	*sepp = sep;
+	NFSUNLOCKSTATE();
+	return (0);

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



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