Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 11 Jun 2017 20:27:39 +0000 (UTC)
From:      Rick Macklem <rmacklem@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r319833 - projects/pnfs-planb-server-stable11/sys/fs/nfsserver
Message-ID:  <201706112027.v5BKRdIG071904@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rmacklem
Date: Sun Jun 11 20:27:38 2017
New Revision: 319833
URL: https://svnweb.freebsd.org/changeset/base/319833

Log:
  Update some NFS server files with the pNFS code.

Modified:
  projects/pnfs-planb-server-stable11/sys/fs/nfsserver/nfs_nfsdserv.c
  projects/pnfs-planb-server-stable11/sys/fs/nfsserver/nfs_nfsdsocket.c
  projects/pnfs-planb-server-stable11/sys/fs/nfsserver/nfs_nfsdstate.c
  projects/pnfs-planb-server-stable11/sys/fs/nfsserver/nfs_nfsdsubs.c

Modified: projects/pnfs-planb-server-stable11/sys/fs/nfsserver/nfs_nfsdserv.c
==============================================================================
--- projects/pnfs-planb-server-stable11/sys/fs/nfsserver/nfs_nfsdserv.c	Sun Jun 11 20:18:18 2017	(r319832)
+++ projects/pnfs-planb-server-stable11/sys/fs/nfsserver/nfs_nfsdserv.c	Sun Jun 11 20:27:38 2017	(r319833)
@@ -54,6 +54,11 @@ extern struct timeval nfsboottime;
 extern int nfs_rootfhset;
 extern int nfsrv_enable_crossmntpt;
 extern int nfsrv_statehashsize;
+extern int nfsrv_layouthashsize;
+extern time_t nfsdev_time;
+extern struct nfsdevicehead nfsrv_devidhead;
+extern int nfsd_debuglevel;
+extern u_long sb_max_adj;
 #endif	/* !APPLEKEXT */
 
 static int	nfs_async = 0;
@@ -151,7 +156,7 @@ nfsrvd_access(struct nfsrv_descript *nd, __unused int 
 	}
 	nfsmode &= supported;
 	if (nd->nd_flag & ND_NFSV3) {
-		getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
+		getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
 		nfsrv_postopattr(nd, getret, &nva);
 	}
 	vput(vp);
@@ -235,14 +240,14 @@ nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
 		}
 	}
 	if (!nd->nd_repstat)
-		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
+		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
 	if (!nd->nd_repstat) {
 		if (nd->nd_flag & ND_NFSV4) {
 			if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
 				nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
 			if (!nd->nd_repstat)
 				nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
-				    &nva, &attrbits, nd->nd_cred, p);
+				    &nva, &attrbits, p);
 			if (nd->nd_repstat == 0) {
 				supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
 				mp = vp->v_mount;
@@ -307,6 +312,7 @@ nfsrvd_setattr(struct nfsrv_descript *nd, __unused int
 	struct nfsvattr nva, nva2;
 	u_int32_t *tl;
 	int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
+	int gotproxystateid;
 	struct timespec guard = { 0, 0 };
 	nfsattrbit_t attrbits, retbits;
 	nfsv4stateid_t stateid;
@@ -320,19 +326,32 @@ nfsrvd_setattr(struct nfsrv_descript *nd, __unused int
 	aclp = acl_alloc(M_WAITOK);
 	aclp->acl_cnt = 0;
 #endif
+	gotproxystateid = 0;
 	NFSVNO_ATTRINIT(&nva);
-	NFSZERO_ATTRBIT(&retbits);
 	if (nd->nd_flag & ND_NFSV4) {
 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
 		stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
-		NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
+		stateid.other[0] = *tl++;
+		stateid.other[1] = *tl++;
+		stateid.other[2] = *tl;
+		if (stateid.other[0] == 0x55555555 &&
+		    stateid.other[1] == 0x55555555 &&
+		    stateid.other[2] == 0x55555555 &&
+		    stateid.seqid == 0xffffffff)
+			gotproxystateid = 1;
 	}
 	error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p);
 	if (error)
 		goto nfsmout;
-	preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1);
+
+	/* For NFSv4, only va_uid is used from nva2. */
+	NFSZERO_ATTRBIT(&retbits);
+	NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
+	preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits);
 	if (!nd->nd_repstat)
 		nd->nd_repstat = preat_ret;
+
+	NFSZERO_ATTRBIT(&retbits);
 	if (nd->nd_flag & ND_NFSV3) {
 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 		gcheck = fxdr_unsigned(int, *tl);
@@ -376,7 +395,12 @@ nfsrvd_setattr(struct nfsrv_descript *nd, __unused int
 				    NFSACCCHK_VPISLOCKED, NULL);
 		}
 	}
-	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
+	/*
+	 * Proxy operations from the MDS are allowed via the all 0s special
+	 * stateid.
+	 */
+	if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0 &&
+	    gotproxystateid == 0)
 		nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
 		    &nva, &attrbits, exp, p);
 
@@ -450,7 +474,7 @@ nfsrvd_setattr(struct nfsrv_descript *nd, __unused int
 		    exp);
 	}
 	if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
-		postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
+		postat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
 		if (!nd->nd_repstat)
 			nd->nd_repstat = postat_ret;
 	}
@@ -534,8 +558,8 @@ nfsrvd_lookup(struct nfsrv_descript *nd, __unused int 
 	if (nd->nd_repstat) {
 		if (dirp) {
 			if (nd->nd_flag & ND_NFSV3)
-				dattr_ret = nfsvno_getattr(dirp, &dattr,
-				    nd->nd_cred, p, 0);
+				dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p,
+				    0, NULL);
 			vrele(dirp);
 		}
 		if (nd->nd_flag & ND_NFSV3)
@@ -556,15 +580,15 @@ nfsrvd_lookup(struct nfsrv_descript *nd, __unused int 
 	if (nd->nd_repstat == 0)
 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
 	if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
-		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
+		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
 	if (vpp != NULL && nd->nd_repstat == 0)
 		*vpp = vp;
 	else
 		vput(vp);
 	if (dirp) {
 		if (nd->nd_flag & ND_NFSV3)
-			dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred,
-			    p, 0);
+			dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 0,
+			    NULL);
 		vrele(dirp);
 	}
 	if (nd->nd_repstat) {
@@ -612,7 +636,7 @@ nfsrvd_readlink(struct nfsrv_descript *nd, __unused in
 		nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
 		    &mp, &mpend, &len);
 	if (nd->nd_flag & ND_NFSV3)
-		getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
+		getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
 	vput(vp);
 	if (nd->nd_flag & ND_NFSV3)
 		nfsrv_postopattr(nd, getret, &nva);
@@ -637,7 +661,7 @@ nfsrvd_read(struct nfsrv_descript *nd, __unused int is
     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
 {
 	u_int32_t *tl;
-	int error = 0, cnt, getret = 1, reqlen, eof = 0;
+	int error = 0, cnt, getret = 1, gotproxystateid, reqlen, eof = 0;
 	mbuf_t m2, m3;
 	struct nfsvattr nva;
 	off_t off = 0x0;
@@ -669,6 +693,7 @@ nfsrvd_read(struct nfsrv_descript *nd, __unused int is
 		error = EBADRPC;
 		goto nfsmout;
 	}
+	gotproxystateid = 0;
 	if (nd->nd_flag & ND_NFSV4) {
 		stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
 		lop->lo_flags = NFSLCK_READ;
@@ -690,6 +715,24 @@ nfsrvd_read(struct nfsrv_descript *nd, __unused int is
 			nd->nd_clientid.qval = clientid.qval;
 		}
 		stp->ls_stateid.other[2] = *tl++;
+		/*
+		 * Don't allow the client to use a special stateid for a DS op.
+		 */
+		if ((nd->nd_flag & ND_DSSERVER) != 0 &&
+		    ((stp->ls_stateid.other[0] == 0x0 &&
+		    stp->ls_stateid.other[1] == 0x0 &&
+		    stp->ls_stateid.other[2] == 0x0) ||
+		    (stp->ls_stateid.other[0] == 0xffffffff &&
+		    stp->ls_stateid.other[1] == 0xffffffff &&
+		    stp->ls_stateid.other[2] == 0xffffffff) ||
+		    stp->ls_stateid.seqid != 0))
+			nd->nd_repstat = NFSERR_BADSTATEID;
+		/* However, allow the proxy stateid. */
+		if (stp->ls_stateid.seqid == 0xffffffff &&
+		    stp->ls_stateid.other[0] == 0x55555555 &&
+		    stp->ls_stateid.other[1] == 0x55555555 &&
+		    stp->ls_stateid.other[2] == 0x55555555)
+			gotproxystateid = 1;
 		off = fxdr_hyper(tl);
 		lop->lo_first = off;
 		tl += 2;
@@ -707,7 +750,7 @@ nfsrvd_read(struct nfsrv_descript *nd, __unused int is
 			nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
 			    EINVAL;
 	}
-	getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
+	getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
 	if (!nd->nd_repstat)
 		nd->nd_repstat = getret;
 	if (!nd->nd_repstat &&
@@ -721,7 +764,12 @@ nfsrvd_read(struct nfsrv_descript *nd, __unused int is
 			    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
 			    NFSACCCHK_VPISLOCKED, NULL);
 	}
-	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
+	/*
+	 * DS reads are marked by ND_DSSERVER or use the proxy special
+	 * stateid.
+	 */
+	if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
+	    ND_NFSV4 && gotproxystateid == 0)
 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
 		    &stateid, exp, nd, p);
 	if (nd->nd_repstat) {
@@ -745,7 +793,7 @@ nfsrvd_read(struct nfsrv_descript *nd, __unused int is
 		nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
 		    &m3, &m2);
 		if (!(nd->nd_flag & ND_NFSV4)) {
-			getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
+			getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
 			if (!nd->nd_repstat)
 				nd->nd_repstat = getret;
 		}
@@ -802,17 +850,19 @@ nfsrvd_write(struct nfsrv_descript *nd, __unused int i
 	mbuf_t mp;
 	struct nfsvattr nva, forat;
 	int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
-	int stable = NFSWRITE_FILESYNC;
+	int gotproxystateid, stable = NFSWRITE_FILESYNC;
 	off_t off;
 	struct nfsstate st, *stp = &st;
 	struct nfslock lo, *lop = &lo;
 	nfsv4stateid_t stateid;
 	nfsquad_t clientid;
+	nfsattrbit_t attrbits;
 
 	if (nd->nd_repstat) {
 		nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
 		goto out;
 	}
+	gotproxystateid = 0;
 	if (nd->nd_flag & ND_NFSV2) {
 		NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
 		off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
@@ -846,6 +896,24 @@ nfsrvd_write(struct nfsrv_descript *nd, __unused int i
 			nd->nd_clientid.qval = clientid.qval;
 		}
 		stp->ls_stateid.other[2] = *tl++;
+		/*
+		 * Don't allow the client to use a special stateid for a DS op.
+		 */
+		if ((nd->nd_flag & ND_DSSERVER) != 0 &&
+		    ((stp->ls_stateid.other[0] == 0x0 &&
+		    stp->ls_stateid.other[1] == 0x0 &&
+		    stp->ls_stateid.other[2] == 0x0) ||
+		    (stp->ls_stateid.other[0] == 0xffffffff &&
+		    stp->ls_stateid.other[1] == 0xffffffff &&
+		    stp->ls_stateid.other[2] == 0xffffffff) ||
+		    stp->ls_stateid.seqid != 0))
+			nd->nd_repstat = NFSERR_BADSTATEID;
+		/* However, allow the proxy stateid. */
+		if (stp->ls_stateid.seqid == 0xffffffff &&
+		    stp->ls_stateid.other[0] == 0x55555555 &&
+		    stp->ls_stateid.other[1] == 0x55555555 &&
+		    stp->ls_stateid.other[2] == 0x55555555)
+			gotproxystateid = 1;
 		off = fxdr_hyper(tl);
 		lop->lo_first = off;
 		tl += 2;
@@ -891,7 +959,9 @@ nfsrvd_write(struct nfsrv_descript *nd, __unused int i
 			nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
 			    EINVAL;
 	}
-	forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1);
+	NFSZERO_ATTRBIT(&attrbits);
+	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
+	forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits);
 	if (!nd->nd_repstat)
 		nd->nd_repstat = forat_ret;
 	if (!nd->nd_repstat &&
@@ -900,10 +970,14 @@ nfsrvd_write(struct nfsrv_descript *nd, __unused int i
 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
 		    nd->nd_cred, exp, p,
 		    NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
-	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
+	/*
+	 * DS reads are marked by ND_DSSERVER or use the proxy special
+	 * stateid.
+	 */
+	if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
+	    ND_NFSV4 && gotproxystateid == 0)
 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
 		    &stateid, exp, nd, p);
-	}
 	if (nd->nd_repstat) {
 		vput(vp);
 		if (nd->nd_flag & ND_NFSV3)
@@ -917,7 +991,7 @@ nfsrvd_write(struct nfsrv_descript *nd, __unused int i
 	 * which is to return ok so long as there are no permission problems.
 	 */
 	if (retlen > 0) {
-		nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable,
+		nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, &stable,
 		    nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
 		error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
 		if (error)
@@ -926,7 +1000,7 @@ nfsrvd_write(struct nfsrv_descript *nd, __unused int i
 	if (nd->nd_flag & ND_NFSV4)
 		aftat_ret = 0;
 	else
-		aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
+		aftat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
 	vput(vp);
 	if (!nd->nd_repstat)
 		nd->nd_repstat = aftat_ret;
@@ -1048,8 +1122,8 @@ nfsrvd_create(struct nfsrv_descript *nd, __unused int 
 	if (nd->nd_repstat) {
 		nfsvno_relpathbuf(&named);
 		if (nd->nd_flag & ND_NFSV3) {
-			dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred,
-			    p, 1);
+			dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 1,
+			    NULL);
 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
 			    &diraft);
 		}
@@ -1063,8 +1137,8 @@ nfsrvd_create(struct nfsrv_descript *nd, __unused int 
 			vrele(dirp);
 			dirp = NULL;
 		} else {
-			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
-			    p, 0);
+			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
+			    NULL);
 		}
 	}
 	if (nd->nd_repstat) {
@@ -1102,8 +1176,8 @@ nfsrvd_create(struct nfsrv_descript *nd, __unused int 
 	if (!nd->nd_repstat) {
 		nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
 		if (!nd->nd_repstat)
-			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
-			    p, 1);
+			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
+			    NULL);
 		vput(vp);
 		if (!nd->nd_repstat) {
 			tverf[0] = nva.na_atime.tv_sec;
@@ -1119,7 +1193,7 @@ nfsrvd_create(struct nfsrv_descript *nd, __unused int 
 		if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
 		    || cverf[1] != tverf[1]))
 			nd->nd_repstat = EEXIST;
-		diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
+		diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
 		vrele(dirp);
 		if (!nd->nd_repstat) {
 			(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
@@ -1229,7 +1303,7 @@ nfsrvd_mknod(struct nfsrv_descript *nd, __unused int i
 		}
 	}
 
-	dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
+	dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
 		if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
 		    dirfor.na_gid == nva.na_gid)
@@ -1267,8 +1341,8 @@ nfsrvd_mknod(struct nfsrv_descript *nd, __unused int i
 	if (nd->nd_repstat) {
 		if (dirp) {
 			if (nd->nd_flag & ND_NFSV3)
-				dirfor_ret = nfsvno_getattr(dirp, &dirfor,
-				    nd->nd_cred, p, 0);
+				dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd,
+				    p, 0, NULL);
 			vrele(dirp);
 		}
 #ifdef NFS4_ACL_EXTATTR_NAME
@@ -1280,7 +1354,7 @@ nfsrvd_mknod(struct nfsrv_descript *nd, __unused int i
 		goto out;
 	}
 	if (dirp)
-		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
+		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
 
 	if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
 		if (vtyp == VDIR) {
@@ -1309,8 +1383,8 @@ nfsrvd_mknod(struct nfsrv_descript *nd, __unused int i
 		nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
 		if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
-			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
-			    p, 1);
+			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
+			    NULL);
 		if (vpp != NULL && nd->nd_repstat == 0) {
 			NFSVOPUNLOCK(vp, 0);
 			*vpp = vp;
@@ -1318,7 +1392,7 @@ nfsrvd_mknod(struct nfsrv_descript *nd, __unused int i
 			vput(vp);
 	}
 
-	diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
+	diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
 	vrele(dirp);
 	if (!nd->nd_repstat) {
 		if (nd->nd_flag & ND_NFSV3) {
@@ -1392,8 +1466,8 @@ nfsrvd_remove(struct nfsrv_descript *nd, __unused int 
 	}
 	if (dirp) {
 		if (!(nd->nd_flag & ND_NFSV2)) {
-			dirfor_ret = nfsvno_getattr(dirp, &dirfor,
-			    nd->nd_cred, p, 0);
+			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
+			    NULL);
 		} else {
 			vrele(dirp);
 			dirp = NULL;
@@ -1417,8 +1491,8 @@ nfsrvd_remove(struct nfsrv_descript *nd, __unused int 
 	}
 	if (!(nd->nd_flag & ND_NFSV2)) {
 		if (dirp) {
-			diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred,
-			    p, 0);
+			diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0,
+			    NULL);
 			vrele(dirp);
 		}
 		if (nd->nd_flag & ND_NFSV3) {
@@ -1464,7 +1538,7 @@ nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
 		goto out;
 	}
 	if (!(nd->nd_flag & ND_NFSV2))
-		fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1);
+		fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd, p, 1, NULL);
 	tond.ni_cnd.cn_nameiop = 0;
 	tond.ni_startdir = NULL;
 	NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
@@ -1487,11 +1561,12 @@ nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
 		tnes = *toexp;
 		if (dp != tdp) {
 			NFSVOPUNLOCK(dp, 0);
-			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
-			    p, 0);	/* Might lock tdp. */
+			/* Might lock tdp. */
+			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 0,
+			    NULL);
 		} else {
-			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
-			    p, 1);
+			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
+			    NULL);
 			NFSVOPUNLOCK(dp, 0);
 		}
 	} else {
@@ -1512,8 +1587,8 @@ nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
 			VREF(dp);
 			tdp = dp;
 			tnes = *exp;
-			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
-			    p, 1);
+			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
+			    NULL);
 			NFSVOPUNLOCK(dp, 0);
 		} else {
 			NFSVOPUNLOCK(dp, 0);
@@ -1521,8 +1596,8 @@ nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
 			nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
 			    0, p);	/* Locks tdp. */
 			if (tdp) {
-				tdirfor_ret = nfsvno_getattr(tdp, &tdirfor,
-				    nd->nd_cred, p, 1);
+				tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd,
+				    p, 1, NULL);
 				NFSVOPUNLOCK(tdp, 0);
 			}
 		}
@@ -1579,11 +1654,9 @@ nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
 	nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
 	    nd->nd_flag, nd->nd_cred, p);
 	if (fdirp)
-		fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p,
-		    0);
+		fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd, p, 0, NULL);
 	if (tdirp)
-		tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
-		    0);
+		tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd, p, 0, NULL);
 	if (fdirp)
 		vrele(fdirp);
 	if (tdirp)
@@ -1684,16 +1757,16 @@ nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
 			vrele(dirp);
 			dirp = NULL;
 		} else {
-			dirfor_ret = nfsvno_getattr(dirp, &dirfor,
-			    nd->nd_cred, p, 0);
+			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
+			    NULL);
 		}
 	}
 	if (!nd->nd_repstat)
 		nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
 	if (nd->nd_flag & ND_NFSV3)
-		getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
+		getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL);
 	if (dirp) {
-		diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
+		diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
 		vrele(dirp);
 	}
 	vrele(vp);
@@ -1763,13 +1836,13 @@ nfsrvd_symlink(struct nfsrv_descript *nd, __unused int
 	 */
 	if (!nd->nd_repstat) {
 		if (dirp != NULL)
-			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
-			    p, 0);
+			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
+			    NULL);
 		nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
 		    &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
 		    pathcp, pathlen);
 	} else if (dirp != NULL) {
-		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
+		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
 		vrele(dirp);
 	}
 	if (pathcp)
@@ -1809,7 +1882,7 @@ nfsrvd_symlinksub(struct nfsrv_descript *nd, struct na
 			nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
 			if (!nd->nd_repstat)
 				nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
-				    nvap, nd->nd_cred, p, 1);
+				    nvap, nd, p, 1, NULL);
 		}
 		if (vpp != NULL && nd->nd_repstat == 0) {
 			NFSVOPUNLOCK(ndp->ni_vp, 0);
@@ -1818,7 +1891,7 @@ nfsrvd_symlinksub(struct nfsrv_descript *nd, struct na
 			vput(ndp->ni_vp);
 	}
 	if (dirp) {
-		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
+		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
 		vrele(dirp);
 	}
 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
@@ -1882,8 +1955,8 @@ nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int i
 	}
 	if (nd->nd_repstat) {
 		if (dirp != NULL) {
-			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
-			    p, 0);
+			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
+			    NULL);
 			vrele(dirp);
 		}
 		if (nd->nd_flag & ND_NFSV3)
@@ -1892,7 +1965,7 @@ nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int i
 		goto out;
 	}
 	if (dirp != NULL)
-		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
+		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
 
 	/*
 	 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
@@ -1942,8 +2015,8 @@ nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct name
 		nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
 		if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
-			nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
-			    p, 1);
+			nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1,
+			    NULL);
 		if (vpp && !nd->nd_repstat) {
 			NFSVOPUNLOCK(vp, 0);
 			*vpp = vp;
@@ -1952,7 +2025,7 @@ nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct name
 		}
 	}
 	if (dirp) {
-		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
+		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
 		vrele(dirp);
 	}
 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
@@ -2002,10 +2075,10 @@ nfsrvd_commit(struct nfsrv_descript *nd, __unused int 
 	tl += 2;
 	cnt = fxdr_unsigned(int, *tl);
 	if (nd->nd_flag & ND_NFSV3)
-		for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
+		for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL);
 	nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
 	if (nd->nd_flag & ND_NFSV3) {
-		aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
+		aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL);
 		nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
 	}
 	vput(vp);
@@ -2044,7 +2117,7 @@ nfsrvd_statfs(struct nfsrv_descript *nd, __unused int 
 	}
 	sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
 	nd->nd_repstat = nfsvno_statfs(vp, sf);
-	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
+	getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
 	vput(vp);
 	if (nd->nd_flag & ND_NFSV3)
 		nfsrv_postopattr(nd, getret, &at);
@@ -2099,7 +2172,7 @@ nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
 		nfsrv_postopattr(nd, getret, &at);
 		goto out;
 	}
-	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
+	getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
 	nfsvno_getfs(&fs, isdgram);
 	vput(vp);
 	nfsrv_postopattr(nd, getret, &at);
@@ -2149,7 +2222,7 @@ nfsrvd_pathconf(struct nfsrv_descript *nd, __unused in
 	if (!nd->nd_repstat)
 		nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, &notrunc,
 		    nd->nd_cred, p);
-	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
+	getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
 	vput(vp);
 	nfsrv_postopattr(nd, getret, &at);
 	if (!nd->nd_repstat) {
@@ -2232,6 +2305,25 @@ nfsrvd_lock(struct nfsrv_descript *nd, __unused int is
 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 			NFSX_STATEIDOTHER);
 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
+
+		/*
+		 * For the special stateid of other all 0s and seqid == 1, set
+		 * the stateid to the current stateid, if it is set.
+		 */
+		if ((nd->nd_flag & ND_NFSV41) != 0 &&
+		    stp->ls_stateid.seqid == 1 &&
+		    stp->ls_stateid.other[0] == 0 &&
+		    stp->ls_stateid.other[1] == 0 &&
+		    stp->ls_stateid.other[2] == 0) {
+			if ((nd->nd_flag & ND_CURSTATEID) != 0) {
+				stp->ls_stateid = nd->nd_curstateid;
+				stp->ls_stateid.seqid = 0;
+			} else {
+				nd->nd_repstat = NFSERR_BADSTATEID;
+				goto nfsmout;
+			}
+		}
+
 		stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
 		clientid.lval[0] = *tl++;
 		clientid.lval[1] = *tl++;
@@ -2259,6 +2351,25 @@ nfsrvd_lock(struct nfsrv_descript *nd, __unused int is
 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 			NFSX_STATEIDOTHER);
 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
+
+		/*
+		 * For the special stateid of other all 0s and seqid == 1, set
+		 * the stateid to the current stateid, if it is set.
+		 */
+		if ((nd->nd_flag & ND_NFSV41) != 0 &&
+		    stp->ls_stateid.seqid == 1 &&
+		    stp->ls_stateid.other[0] == 0 &&
+		    stp->ls_stateid.other[1] == 0 &&
+		    stp->ls_stateid.other[2] == 0) {
+			if ((nd->nd_flag & ND_CURSTATEID) != 0) {
+				stp->ls_stateid = nd->nd_curstateid;
+				stp->ls_stateid.seqid = 0;
+			} else {
+				nd->nd_repstat = NFSERR_BADSTATEID;
+				goto nfsmout;
+			}
+		}
+
 		stp->ls_seq = fxdr_unsigned(int, *tl);
 		clientid.lval[0] = stp->ls_stateid.other[0];
 		clientid.lval[1] = stp->ls_stateid.other[1];
@@ -2325,6 +2436,11 @@ nfsrvd_lock(struct nfsrv_descript *nd, __unused int is
 	if (stp)
 		FREE((caddr_t)stp, M_NFSDSTATE);
 	if (!nd->nd_repstat) {
+		/* For NFSv4.1, set the Current StateID. */
+		if ((nd->nd_flag & ND_NFSV41) != 0) {
+			nd->nd_curstateid = stateid;
+			nd->nd_flag |= ND_CURSTATEID;
+		}
 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 		*tl++ = txdr_unsigned(stateid.seqid);
 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
@@ -2518,6 +2634,23 @@ nfsrvd_locku(struct nfsrv_descript *nd, __unused int i
 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 	    NFSX_STATEIDOTHER);
 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
+
+	/*
+	 * For the special stateid of other all 0s and seqid == 1, set the
+	 * stateid to the current stateid, if it is set.
+	 */
+	if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
+	    stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
+	    stp->ls_stateid.other[2] == 0) {
+		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
+			stp->ls_stateid = nd->nd_curstateid;
+			stp->ls_stateid.seqid = 0;
+		} else {
+			nd->nd_repstat = NFSERR_BADSTATEID;
+			goto nfsmout;
+		}
+	}
+
 	lop->lo_first = fxdr_hyper(tl);
 	tl += 2;
 	len = fxdr_hyper(tl);
@@ -2697,7 +2830,7 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int is
 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 	create = fxdr_unsigned(int, *tl);
 	if (!nd->nd_repstat)
-		nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
+		nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
 	if (create == NFSV4OPEN_CREATE) {
 		nva.na_type = VREG;
 		nva.na_mode = 0;
@@ -2896,7 +3029,7 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int is
 	}
 
 	if (!nd->nd_repstat) {
-		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
+		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
 		if (!nd->nd_repstat) {
 			tverf[0] = nva.na_atime.tv_sec;
 			tverf[1] = nva.na_atime.tv_nsec;
@@ -2922,9 +3055,13 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int is
 	if (stp)
 		FREE((caddr_t)stp, M_NFSDSTATE);
 	if (!nd->nd_repstat && dirp)
-		nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
-		    0);
+		nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
 	if (!nd->nd_repstat) {
+		/* For NFSv4.1, set the Current StateID. */
+		if ((nd->nd_flag & ND_NFSV41) != 0) {
+			nd->nd_curstateid = stateid;
+			nd->nd_flag |= ND_CURSTATEID;
+		}
 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
 		*tl++ = txdr_unsigned(stateid.seqid);
 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
@@ -3024,9 +3161,10 @@ nfsrvd_close(struct nfsrv_descript *nd, __unused int i
 {
 	u_int32_t *tl;
 	struct nfsstate st, *stp = &st;
-	int error = 0;
+	int error = 0, writeacc;
 	nfsv4stateid_t stateid;
 	nfsquad_t clientid;
+	struct nfsvattr na;
 
 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
@@ -3036,6 +3174,22 @@ nfsrvd_close(struct nfsrv_descript *nd, __unused int i
 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 	    NFSX_STATEIDOTHER);
+
+	/*
+	 * For the special stateid of other all 0s and seqid == 1, set the
+	 * stateid to the current stateid, if it is set.
+	 */
+	if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
+	    stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
+	    stp->ls_stateid.other[2] == 0) {
+		if ((nd->nd_flag & ND_CURSTATEID) != 0)
+			stp->ls_stateid = nd->nd_curstateid;
+		else {
+			nd->nd_repstat = NFSERR_BADSTATEID;
+			goto nfsmout;
+		}
+	}
+
 	stp->ls_flags = NFSLCK_CLOSE;
 	clientid.lval[0] = stp->ls_stateid.other[0];
 	clientid.lval[1] = stp->ls_stateid.other[1];
@@ -3050,9 +3204,22 @@ nfsrvd_close(struct nfsrv_descript *nd, __unused int i
 		nd->nd_flag |= ND_IMPLIEDCLID;
 		nd->nd_clientid.qval = clientid.qval;
 	}
-	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
+	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
+	    &writeacc);
+	/* For pNFS, update the attributes. */
+	if (writeacc != 0)
+		nfsrv_updatemdsattr(vp, &na, p);
 	vput(vp);
 	if (!nd->nd_repstat) {
+		/*
+		 * If the stateid that has been closed is the current stateid,
+		 * unset it.
+		 */
+		if ((nd->nd_flag & ND_CURSTATEID) != 0 &&
+		    stateid.other[0] == nd->nd_curstateid.other[0] &&
+		    stateid.other[1] == nd->nd_curstateid.other[1] &&
+		    stateid.other[2] == nd->nd_curstateid.other[2])
+			nd->nd_flag &= ~ND_CURSTATEID;
 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 		*tl++ = txdr_unsigned(stateid.seqid);
 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
@@ -3095,7 +3262,7 @@ nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused 
 		nd->nd_clientid.qval = clientid.qval;
 	}
 	nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
-	    NFSV4OP_DELEGPURGE, nd->nd_cred, p);
+	    NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL);
 nfsmout:
 	NFSEXITCODE2(error, nd);
 	return (error);
@@ -3109,9 +3276,10 @@ nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused
     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
 {
 	u_int32_t *tl;
-	int error = 0;
+	int error = 0, writeacc;
 	nfsv4stateid_t stateid;
 	nfsquad_t clientid;
+	struct nfsvattr na;
 
 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
 	stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
@@ -3130,7 +3298,10 @@ nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused
 		nd->nd_clientid.qval = clientid.qval;
 	}
 	nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
-	    NFSV4OP_DELEGRETURN, nd->nd_cred, p);
+	    NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc);
+	/* For pNFS, update the attributes. */
+	if (writeacc != 0)
+		nfsrv_updatemdsattr(vp, &na, p);
 nfsmout:
 	vput(vp);
 	NFSEXITCODE2(error, nd);
@@ -3194,7 +3365,8 @@ nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused
 		nd->nd_flag |= ND_IMPLIEDCLID;
 		nd->nd_clientid.qval = clientid.qval;
 	}
-	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
+	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
+	    NULL);
 	if (!nd->nd_repstat) {
 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 		*tl++ = txdr_unsigned(stateid.seqid);
@@ -3233,6 +3405,22 @@ nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unus
 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 	    NFSX_STATEIDOTHER);
 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
+
+	/*
+	 * For the special stateid of other all 0s and seqid == 1, set the
+	 * stateid to the current stateid, if it is set.
+	 */
+	if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
+	    stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
+	    stp->ls_stateid.other[2] == 0) {
+		if ((nd->nd_flag & ND_CURSTATEID) != 0)
+			stp->ls_stateid = nd->nd_curstateid;
+		else {
+			nd->nd_repstat = NFSERR_BADSTATEID;
+			goto nfsmout;
+		}
+	}
+
 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
 	i = fxdr_unsigned(int, *tl++);
 	switch (i) {
@@ -3281,8 +3469,13 @@ nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unus
 	}
 	if (!nd->nd_repstat)
 		nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
-		    nd, p);
+		    nd, p, NULL);
 	if (!nd->nd_repstat) {
+		/* For NFSv4.1, set the Current StateID. */
+		if ((nd->nd_flag & ND_NFSV41) != 0) {
+			nd->nd_curstateid = stateid;
+			nd->nd_flag |= ND_CURSTATEID;
+		}
 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 		*tl++ = txdr_unsigned(stateid.seqid);
 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
@@ -3609,7 +3802,7 @@ nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
 	fhandle_t fh;
 
 	sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
-	nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
+	nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
 	if (!nd->nd_repstat)
 		nd->nd_repstat = nfsvno_statfs(vp, sf);
 	if (!nd->nd_repstat)
@@ -3787,7 +3980,10 @@ nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused 
 		confirm.lval[1] = 1;
 	else
 		confirm.lval[1] = 0;
-	v41flags = NFSV4EXCH_USENONPNFS;
+	if (TAILQ_EMPTY(&nfsrv_devidhead))
+		v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS;
+ 	else
+ 		v41flags = NFSV4EXCH_USEPNFSMDS;
 	sp4type = fxdr_unsigned(uint32_t, *tl);
 	if (sp4type != NFSV4EXCH_SP4NONE) {
 		nd->nd_repstat = NFSERR_NOTSUPP;
@@ -3878,7 +4074,15 @@ nfsrvd_createsession(struct nfsrv_descript *nd, __unus
 	NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
 	tl++;					/* Header pad always 0. */
 	sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
+	if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) {
+		sep->sess_maxreq = sb_max_adj - NFS_MAXXDR;
+		printf("Consider increasing kern.ipc.maxsockbuf\n");
+	}
 	sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
+	if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) {
+		sep->sess_maxresp = sb_max_adj - NFS_MAXXDR;
+		printf("Consider increasing kern.ipc.maxsockbuf\n");
+	}
 	sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
 	sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
 	sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
@@ -4080,7 +4284,361 @@ nfsrvd_freestateid(struct nfsrv_descript *nd, __unused
 	NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
+
+	/*
+	 * For the special stateid of other all 0s and seqid == 1, set the
+	 * stateid to the current stateid, if it is set.
+	 */
+	if (stateid.seqid == 1 && stateid.other[0] == 0 &&
+	    stateid.other[1] == 0 && stateid.other[2] == 0) {
+		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
+			stateid = nd->nd_curstateid;
+			stateid.seqid = 0;
+		} else {
+			nd->nd_repstat = NFSERR_BADSTATEID;
+			goto nfsmout;
+		}
+	}
+
 	nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
+
+	/* If the current stateid has been free'd, unset it. */
+	if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 &&
+	    stateid.other[0] == nd->nd_curstateid.other[0] &&
+	    stateid.other[1] == nd->nd_curstateid.other[1] &&
+	    stateid.other[2] == nd->nd_curstateid.other[2])
+		nd->nd_flag &= ~ND_CURSTATEID;
+nfsmout:
+	NFSEXITCODE2(error, nd);
+	return (error);
+}
+
+/*
+ * nfsv4 layoutget service
+ */
+APPLESTATIC int
+nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram,
+    vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
+{
+	uint32_t *tl;
+	nfsv4stateid_t stateid;
+	int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose;
+	uint64_t offset, len, minlen;
+	char *layp = NULL;
+
+	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
+		nd->nd_repstat = NFSERR_WRONGSEC;
+		goto nfsmout;
+	}
+	NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
+	    NFSX_STATEID);
+	tl++;		/* Signal layout available. Ignore for now. */
+	layouttype = fxdr_unsigned(int, *tl++);
+	iomode = fxdr_unsigned(int, *tl++);
+	offset = fxdr_hyper(tl); tl += 2;
+	len = fxdr_hyper(tl); tl += 2;
+	minlen = fxdr_hyper(tl); tl += 2;
+	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
+	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
+	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
+	maxcnt = fxdr_unsigned(int, tl);
+	NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n",
+	    layouttype, iomode, (uintmax_t)offset, (uintmax_t)len,
+	    (uintmax_t)minlen);
+	if (len < minlen ||
+	    (minlen != UINT64_MAX && offset + minlen < offset) ||
+	    (len != UINT64_MAX && offset + len < offset)) {
+		nd->nd_repstat = NFSERR_INVAL;
+		goto nfsmout;
+	}
+
+	/*
+	 * For the special stateid of other all 0s and seqid == 1, set the
+	 * stateid to the current stateid, if it is set.
+	 */
+	if (stateid.seqid == 1 && stateid.other[0] == 0 &&
+	    stateid.other[1] == 0 && stateid.other[2] == 0) {

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



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