svn commit: r355677 - in head/sys/fs: nfs nfsclient nfsserver

Rick Macklem rmacklem at FreeBSD.org
Thu Dec 12 23:22:57 UTC 2019


Author: rmacklem
Date: Thu Dec 12 23:22:55 2019
New Revision: 355677
URL: https://svnweb.freebsd.org/changeset/base/355677

Log:
  Add support for NFSv4.2 to the NFS client and server.
  
  This patch adds support for NFSv4.2 (RFC-7862) and Extended Attributes
  (RFC-8276) to the NFS client and server.
  NFSv4.2 is comprised of several optional features that can be supported
  in addition to NFSv4.1. This patch adds the following optional features:
     - posix_fadvise(POSIX_FADV_WILLNEED/POSIX_FADV_DONTNEED)
     - posix_fallocate()
     - intra server file range copying via the copy_file_range(2) syscall
       --> Avoiding data tranfer over the wire to/from the NFS client.
     - lseek(SEEK_DATA/SEEK_HOLE)
     - Extended attribute syscalls for "user" namespace attributes as defined
       by RFC-8276.
  
  Although this patch is fairly large, it should not affect support for
  the other versions of NFS. However it does add two new sysctls that allow
  a sysadmin to limit which minor versions of NFSv4 a server supports, allowing
  a sysadmin to disable NFSv4.2.
  
  Unfortunately, when the NFS stats structure was last revised, it was assumed
  that there would be no additional operations added beyond what was
  specified in RFC-7862. However RFC-8276 did add additional operations,
  forcing the NFS stats structure to revised again. It now has extra unused
  entries in all arrays, so that future extensions to NFSv4.2 can be
  accomodated without revising this structure again.
  
  A future commit will update nfsstat(1) to report counts for the new NFSv4.2
  specific operations/procedures.
  
  This patch affects the internal interface between the nfscommon, nfscl and
  nfsd modules and, as such, they all must be upgraded simultaneously.
  I will do a version bump (although arguably not needed), due to this.
  
  This code has survived a "make universe" but has not been built with a
  recent GCC. If you encounter build problems, please email me.
  
  Relnotes:	yes

Modified:
  head/sys/fs/nfs/nfs.h
  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/nfsport.h
  head/sys/fs/nfs/nfsproto.h
  head/sys/fs/nfsclient/nfs_clrpcops.c
  head/sys/fs/nfsclient/nfs_clstate.c
  head/sys/fs/nfsclient/nfs_clvfsops.c
  head/sys/fs/nfsclient/nfs_clvnops.c
  head/sys/fs/nfsclient/nfsmount.h
  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

Modified: head/sys/fs/nfs/nfs.h
==============================================================================
--- head/sys/fs/nfs/nfs.h	Thu Dec 12 22:59:22 2019	(r355676)
+++ head/sys/fs/nfs/nfs.h	Thu Dec 12 23:22:55 2019	(r355677)
@@ -668,6 +668,8 @@ struct nfsrv_descript {
 	uint32_t		*nd_sequence;	/* Sequence Op. ptr */
 	nfsv4stateid_t		nd_curstateid;	/* Current StateID */
 	nfsv4stateid_t		nd_savedcurstateid; /* Saved Current StateID */
+	uint32_t		nd_maxreq;	/* Max. request (session). */
+	uint32_t		nd_maxresp;	/* Max. reply (session). */
 };
 
 #define	nd_princlen	nd_gssnamelen

Modified: head/sys/fs/nfs/nfs_commonport.c
==============================================================================
--- head/sys/fs/nfs/nfs_commonport.c	Thu Dec 12 22:59:22 2019	(r355676)
+++ head/sys/fs/nfs/nfs_commonport.c	Thu Dec 12 23:22:55 2019	(r355677)
@@ -80,6 +80,7 @@ int nfs_pnfsio(task_fn_t *, void *);
 static int nfs_realign_test;
 static int nfs_realign_count;
 static struct ext_nfsstats oldnfsstats;
+static struct nfsstatsov1 nfsstatsov1;
 
 SYSCTL_NODE(_vfs, OID_AUTO, nfs, CTLFLAG_RW, 0, "NFS filesystem");
 SYSCTL_INT(_vfs_nfs, OID_AUTO, realign_test, CTLFLAG_RW, &nfs_realign_test,
@@ -580,11 +581,143 @@ nfssvc_call(struct thread *p, struct nfssvc_args *uap,
 		} else {
 			error = copyin(uap->argp, &nfsstatver,
 			    sizeof(nfsstatver));
-			if (error == 0 && nfsstatver.vers != NFSSTATS_V1)
-				error = EPERM;
-			if (error == 0)
-				error = copyout(&nfsstatsv1, uap->argp,
-				    sizeof (nfsstatsv1));
+			if (error == 0) {
+				if (nfsstatver.vers == NFSSTATS_OV1) {
+					/* Copy nfsstatsv1 to nfsstatsov1. */
+					nfsstatsov1.attrcache_hits =
+					    nfsstatsv1.attrcache_hits;
+					nfsstatsov1.attrcache_misses =
+					    nfsstatsv1.attrcache_misses;
+					nfsstatsov1.lookupcache_hits =
+					    nfsstatsv1.lookupcache_hits;
+					nfsstatsov1.lookupcache_misses =
+					    nfsstatsv1.lookupcache_misses;
+					nfsstatsov1.direofcache_hits =
+					    nfsstatsv1.direofcache_hits;
+					nfsstatsov1.direofcache_misses =
+					    nfsstatsv1.direofcache_misses;
+					nfsstatsov1.accesscache_hits =
+					    nfsstatsv1.accesscache_hits;
+					nfsstatsov1.accesscache_misses =
+					    nfsstatsv1.accesscache_misses;
+					nfsstatsov1.biocache_reads =
+					    nfsstatsv1.biocache_reads;
+					nfsstatsov1.read_bios =
+					    nfsstatsv1.read_bios;
+					nfsstatsov1.read_physios =
+					    nfsstatsv1.read_physios;
+					nfsstatsov1.biocache_writes =
+					    nfsstatsv1.biocache_writes;
+					nfsstatsov1.write_bios =
+					    nfsstatsv1.write_bios;
+					nfsstatsov1.write_physios =
+					    nfsstatsv1.write_physios;
+					nfsstatsov1.biocache_readlinks =
+					    nfsstatsv1.biocache_readlinks;
+					nfsstatsov1.readlink_bios =
+					    nfsstatsv1.readlink_bios;
+					nfsstatsov1.biocache_readdirs =
+					    nfsstatsv1.biocache_readdirs;
+					nfsstatsov1.readdir_bios =
+					    nfsstatsv1.readdir_bios;
+					for (i = 0; i < NFSV42_NPROCS; i++)
+						nfsstatsov1.rpccnt[i] =
+						    nfsstatsv1.rpccnt[i];
+					nfsstatsov1.rpcretries =
+					    nfsstatsv1.rpcretries;
+					for (i = 0; i < NFSV42_PURENOPS; i++)
+						nfsstatsov1.srvrpccnt[i] =
+						    nfsstatsv1.srvrpccnt[i];
+					for (i = NFSV42_NOPS,
+					     j = NFSV42_PURENOPS;
+					     i < NFSV42_NOPS + NFSV4OP_FAKENOPS;
+					     i++, j++)
+						nfsstatsov1.srvrpccnt[j] =
+						    nfsstatsv1.srvrpccnt[i];
+					nfsstatsov1.srvrpc_errs =
+					    nfsstatsv1.srvrpc_errs;
+					nfsstatsov1.srv_errs =
+					    nfsstatsv1.srv_errs;
+					nfsstatsov1.rpcrequests =
+					    nfsstatsv1.rpcrequests;
+					nfsstatsov1.rpctimeouts =
+					    nfsstatsv1.rpctimeouts;
+					nfsstatsov1.rpcunexpected =
+					    nfsstatsv1.rpcunexpected;
+					nfsstatsov1.rpcinvalid =
+					    nfsstatsv1.rpcinvalid;
+					nfsstatsov1.srvcache_inproghits =
+					    nfsstatsv1.srvcache_inproghits;
+					nfsstatsov1.srvcache_idemdonehits =
+					    nfsstatsv1.srvcache_idemdonehits;
+					nfsstatsov1.srvcache_nonidemdonehits =
+					    nfsstatsv1.srvcache_nonidemdonehits;
+					nfsstatsov1.srvcache_misses =
+					    nfsstatsv1.srvcache_misses;
+					nfsstatsov1.srvcache_tcppeak =
+					    nfsstatsv1.srvcache_tcppeak;
+					nfsstatsov1.srvcache_size =
+					    nfsstatsv1.srvcache_size;
+					nfsstatsov1.srvclients =
+					    nfsstatsv1.srvclients;
+					nfsstatsov1.srvopenowners =
+					    nfsstatsv1.srvopenowners;
+					nfsstatsov1.srvopens =
+					    nfsstatsv1.srvopens;
+					nfsstatsov1.srvlockowners =
+					    nfsstatsv1.srvlockowners;
+					nfsstatsov1.srvlocks =
+					    nfsstatsv1.srvlocks;
+					nfsstatsov1.srvdelegates =
+					    nfsstatsv1.srvdelegates;
+					for (i = 0; i < NFSV42_CBNOPS; i++)
+						nfsstatsov1.cbrpccnt[i] =
+						    nfsstatsv1.cbrpccnt[i];
+					nfsstatsov1.clopenowners =
+					    nfsstatsv1.clopenowners;
+					nfsstatsov1.clopens =
+					    nfsstatsv1.clopens;
+					nfsstatsov1.cllockowners =
+					    nfsstatsv1.cllockowners;
+					nfsstatsov1.cllocks =
+					    nfsstatsv1.cllocks;
+					nfsstatsov1.cldelegates =
+					    nfsstatsv1.cldelegates;
+					nfsstatsov1.cllocalopenowners =
+					    nfsstatsv1.cllocalopenowners;
+					nfsstatsov1.cllocalopens =
+					    nfsstatsv1.cllocalopens;
+					nfsstatsov1.cllocallockowners =
+					    nfsstatsv1.cllocallockowners;
+					nfsstatsov1.cllocallocks =
+					    nfsstatsv1.cllocallocks;
+					nfsstatsov1.srvstartcnt =
+					    nfsstatsv1.srvstartcnt;
+					nfsstatsov1.srvdonecnt =
+					    nfsstatsv1.srvdonecnt;
+					for (i = NFSV42_NOPS,
+					     j = NFSV42_PURENOPS;
+					     i < NFSV42_NOPS + NFSV4OP_FAKENOPS;
+					     i++, j++) {
+						nfsstatsov1.srvbytes[j] =
+						    nfsstatsv1.srvbytes[i];
+						nfsstatsov1.srvops[j] =
+						    nfsstatsv1.srvops[i];
+						nfsstatsov1.srvduration[j] =
+						    nfsstatsv1.srvduration[i];
+					}
+					nfsstatsov1.busyfrom =
+					    nfsstatsv1.busyfrom;
+					nfsstatsov1.busyfrom =
+					    nfsstatsv1.busyfrom;
+					error = copyout(&nfsstatsov1, uap->argp,
+					    sizeof(nfsstatsov1));
+				} else if (nfsstatver.vers != NFSSTATS_V1)
+					error = EPERM;
+				else
+					error = copyout(&nfsstatsv1, uap->argp,
+					    sizeof(nfsstatsv1));
+			}
 		}
 		if (error == 0) {
 			if ((uap->flag & NFSSVC_ZEROCLTSTATS) != 0) {

Modified: head/sys/fs/nfs/nfs_commonsubs.c
==============================================================================
--- head/sys/fs/nfs/nfs_commonsubs.c	Thu Dec 12 22:59:22 2019	(r355676)
+++ head/sys/fs/nfs/nfs_commonsubs.c	Thu Dec 12 23:22:55 2019	(r355677)
@@ -47,6 +47,8 @@ __FBSDID("$FreeBSD$");
 
 #include <fs/nfs/nfsport.h>
 
+#include <sys/extattr.h>
+
 #include <security/mac/mac_framework.h>
 
 /*
@@ -91,6 +93,10 @@ int nfsrv_maxpnfsmirror = 1;
 SYSCTL_INT(_vfs_nfs, OID_AUTO, pnfsmirror, CTLFLAG_RD,
     &nfsrv_maxpnfsmirror, 0, "Mirror level for pNFS service");
 
+int nfs_maxcopyrange = 10 * 1024 * 1024;
+SYSCTL_INT(_vfs_nfs, OID_AUTO, maxcopyrange, CTLFLAG_RW,
+    &nfs_maxcopyrange, 0, "Max size of a Copy so RPC times reasonable");
+
 /*
  * This array of structures indicates, for V4:
  * retfh - which of 3 types of calling args are used
@@ -108,7 +114,7 @@ SYSCTL_INT(_vfs_nfs, OID_AUTO, pnfsmirror, CTLFLAG_RD,
  * non-idempotent Ops.
  * Define it here, since it is used by both the client and server.
  */
-struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
+struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = {
 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* undef */
 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* undef */
 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* undef */
@@ -168,6 +174,23 @@ struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Want Delegation */
 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },		/* Destroy ClientID */
 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Reclaim Complete */
+	{ 0, 1, 1, 1, LK_EXCLUSIVE, 1, 0 },		/* Allocate */
+	{ 2, 1, 1, 0, LK_SHARED, 1, 0 },		/* Copy */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Copy Notify */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Deallocate */
+	{ 0, 1, 0, 0, LK_SHARED, 1, 0 },		/* IO Advise */
+	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Layout Error */
+	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Layout Stats */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Offload Cancel */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Offload Status */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Read Plus */
+	{ 0, 1, 0, 0, LK_SHARED, 1, 0 },		/* Seek */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Write Same */
+	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Clone */
+	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Getxattr */
+	{ 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Setxattr */
+	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Listxattrs */
+	{ 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Removexattr */
 };
 #endif	/* !APPLEKEXT */
 
@@ -192,9 +215,10 @@ static struct nfsrv_lughash	*nfsgroupnamehash;
  * marked 0 in this array, the code will still work, just not quite as
  * efficiently.)
  */
-static int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
+static int nfs_bigreply[NFSV42_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 };
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+    1, 0, 0, 1 };
 
 /* local functions */
 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
@@ -211,7 +235,7 @@ static struct {
 	int	opcnt;
 	const u_char *tag;
 	int	taglen;
-} nfsv4_opmap[NFSV41_NPROCS] = {
+} nfsv4_opmap[NFSV42_NPROCS] = {
 	{ 0, 1, "Null", 4 },
 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
 	{ NFSV4OP_SETATTR, 2, "Setattr", 7, },
@@ -268,15 +292,24 @@ static struct {
 	{ NFSV4OP_COMMIT, 1, "CommitDS", 8, },
 	{ NFSV4OP_OPEN, 3, "OpenLayoutGet", 13, },
 	{ NFSV4OP_OPEN, 8, "CreateLayGet", 12, },
+	{ NFSV4OP_IOADVISE, 1, "Advise", 6, },
+	{ NFSV4OP_ALLOCATE, 2, "Allocate", 8, },
+	{ NFSV4OP_SAVEFH, 5, "Copy", 4, },
+	{ NFSV4OP_SEEK, 2, "Seek", 4, },
+	{ NFSV4OP_SEEK, 1, "SeekDS", 6, },
+	{ NFSV4OP_GETXATTR, 2, "Getxattr", 8, },
+	{ NFSV4OP_SETXATTR, 2, "Setxattr", 8, },
+	{ NFSV4OP_REMOVEXATTR, 2, "Rmxattr", 7, },
+	{ NFSV4OP_LISTXATTRS, 2, "Listxattr", 9, },
 };
 
 /*
  * NFS RPCS that have large request message size.
  */
-static int nfs_bigrequest[NFSV41_NPROCS] = {
+static int nfs_bigrequest[NFSV42_NPROCS] = {
 	0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0
+	0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0
 };
 
 /*
@@ -301,13 +334,17 @@ nfscl_reqstart(struct nfsrv_descript *nd, int procnum,
 		nd->nd_flag = ND_NFSV4 | ND_NFSCL;
 		if (minorvers == NFSV41_MINORVERSION)
 			nd->nd_flag |= ND_NFSV41;
+		else if (minorvers == NFSV42_MINORVERSION)
+			nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
 	} else if (vers == NFS_VER3)
 		nd->nd_flag = ND_NFSV3 | ND_NFSCL;
 	else {
 		if (NFSHASNFSV4(nmp)) {
 			nd->nd_flag = ND_NFSV4 | ND_NFSCL;
-			if (NFSHASNFSV4N(nmp))
+			if (nmp->nm_minorvers == 1)
 				nd->nd_flag |= ND_NFSV41;
+			else if (nmp->nm_minorvers == 2)
+				nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
 		} else if (NFSHASNFSV3(nmp))
 			nd->nd_flag = ND_NFSV3 | ND_NFSCL;
 		else
@@ -356,7 +393,9 @@ nfscl_reqstart(struct nfsrv_descript *nd, int procnum,
 		(void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
 			nfsv4_opmap[procnum].taglen);
 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
-		if ((nd->nd_flag & ND_NFSV41) != 0)
+		if ((nd->nd_flag & ND_NFSV42) != 0)
+			*tl++ = txdr_unsigned(NFSV42_MINORVERSION);
+		else if ((nd->nd_flag & ND_NFSV41) != 0)
 			*tl++ = txdr_unsigned(NFSV41_MINORVERSION);
 		else
 			*tl++ = txdr_unsigned(NFSV4_MINORVERSION);
@@ -409,7 +448,7 @@ nfscl_reqstart(struct nfsrv_descript *nd, int procnum,
 	} else {
 		(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
 	}
-	if (procnum < NFSV41_NPROCS)
+	if (procnum < NFSV42_NPROCS)
 		NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
 }
 
@@ -2449,6 +2488,8 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount
 	struct nfsfsinfo fsinf;
 	struct timespec temptime;
 	NFSACL_T *aclp, *naclp = NULL;
+	size_t atsiz;
+	bool xattrsupp;
 #ifdef QUOTA
 	struct dqblk dqb;
 	uid_t savuid;
@@ -2523,6 +2564,18 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount
 		}
 	}
 
+	/* Check to see if Extended Attributes are supported. */
+	xattrsupp = false;
+	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_XATTRSUPPORT)) {
+		if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
+			error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER,
+			    "xxx", NULL, &atsiz, cred, p);
+			NFSVOPUNLOCK(vp, 0);
+			if (error != EOPNOTSUPP)
+				xattrsupp = true;
+		}
+	}
+	
 	/*
 	 * Put out the attribute bitmap for the ones being filled in
 	 * and get the field for the number of attributes returned.
@@ -2972,6 +3025,14 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount
 			*tl = txdr_unsigned(NFS_SRVMAXIO);
 			retnum += NFSX_UNSIGNED;
 			break;
+		case NFSATTRBIT_XATTRSUPPORT:
+			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
+			if (xattrsupp)
+				*tl = newnfs_true;
+			else
+				*tl = newnfs_false;
+			retnum += NFSX_UNSIGNED;
+			break;
 		default:
 			printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
 		}
@@ -4629,6 +4690,8 @@ nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_d
 
 	error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
 	    sessionid);
+	nd->nd_maxreq = sep->nfsess_maxreq;
+	nd->nd_maxresp = sep->nfsess_maxresp;
 
 	/* Build the Sequence arguments. */
 	NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);

Modified: head/sys/fs/nfs/nfs_var.h
==============================================================================
--- head/sys/fs/nfs/nfs_var.h	Thu Dec 12 22:59:22 2019	(r355676)
+++ head/sys/fs/nfs/nfs_var.h	Thu Dec 12 23:22:55 2019	(r355677)
@@ -128,7 +128,8 @@ void nfsrv_setupstable(NFSPROC_T *);
 void nfsrv_updatestable(NFSPROC_T *);
 void nfsrv_writestable(u_char *, int, int, NFSPROC_T *);
 void nfsrv_throwawayopens(NFSPROC_T *);
-int nfsrv_checkremove(vnode_t, int, NFSPROC_T *);
+int nfsrv_checkremove(vnode_t, int, struct nfsrv_descript *, nfsquad_t,
+    NFSPROC_T *);
 void nfsd_recalldelegation(vnode_t, NFSPROC_T *);
 void nfsd_disabledelegation(vnode_t, NFSPROC_T *);
 int nfsrv_checksetattr(vnode_t, struct nfsrv_descript *,
@@ -161,6 +162,7 @@ void nfsrv_freealllayoutsanddevids(void);
 void nfsrv_freefilelayouts(fhandle_t *);
 int nfsrv_deldsserver(int, char *, NFSPROC_T *);
 struct nfsdevice *nfsrv_deldsnmp(int, struct nfsmount *, NFSPROC_T *);
+int nfsrv_delds(char *, NFSPROC_T *);
 int nfsrv_createdevids(struct nfsd_nfsd_args *, NFSPROC_T *);
 int nfsrv_checkdsattr(vnode_t, NFSPROC_T *);
 int nfsrv_copymr(vnode_t, vnode_t, vnode_t, struct nfsdevice *,
@@ -268,8 +270,28 @@ int nfsrvd_layoutcommit(struct nfsrv_descript *, int,
     vnode_t, struct nfsexstuff *);
 int nfsrvd_layoutreturn(struct nfsrv_descript *, int,
     vnode_t, struct nfsexstuff *);
+int nfsrvd_ioadvise(struct nfsrv_descript *, int,
+    vnode_t, struct nfsexstuff *);
+int nfsrvd_layouterror(struct nfsrv_descript *, int,
+    vnode_t, struct nfsexstuff *);
+int nfsrvd_layoutstats(struct nfsrv_descript *, int,
+    vnode_t, struct nfsexstuff *);
 int nfsrvd_teststateid(struct nfsrv_descript *, int,
     vnode_t, struct nfsexstuff *);
+int nfsrvd_allocate(struct nfsrv_descript *, int,
+    vnode_t, struct nfsexstuff *);
+int nfsrvd_copy_file_range(struct nfsrv_descript *, int,
+    vnode_t, vnode_t, struct nfsexstuff *, struct nfsexstuff *);
+int nfsrvd_seek(struct nfsrv_descript *, int,
+    vnode_t, struct nfsexstuff *);
+int nfsrvd_getxattr(struct nfsrv_descript *, int,
+    vnode_t, struct nfsexstuff *);
+int nfsrvd_setxattr(struct nfsrv_descript *, int,
+    vnode_t, struct nfsexstuff *);
+int nfsrvd_rmxattr(struct nfsrv_descript *, int,
+    vnode_t, struct nfsexstuff *);
+int nfsrvd_listxattr(struct nfsrv_descript *, int,
+    vnode_t, struct nfsexstuff *);
 int nfsrvd_notsupp(struct nfsrv_descript *, int,
     vnode_t, struct nfsexstuff *);
 
@@ -501,10 +523,11 @@ int nfsrpc_delegreturn(struct nfscldeleg *, struct ucr
 int nfsrpc_getacl(vnode_t, struct ucred *, NFSPROC_T *, NFSACL_T *, void *);
 int nfsrpc_setacl(vnode_t, struct ucred *, NFSPROC_T *, NFSACL_T *, void *);
 int nfsrpc_exchangeid(struct nfsmount *, struct nfsclclient *,
-    struct nfssockreq *, uint32_t, struct nfsclds **, struct ucred *,
+    struct nfssockreq *, int, uint32_t, struct nfsclds **, struct ucred *,
     NFSPROC_T *);
 int nfsrpc_createsession(struct nfsmount *, struct nfsclsession *,
-    struct nfssockreq *, uint32_t, int, struct ucred *, NFSPROC_T *);
+    struct nfssockreq *, struct nfsclds *, uint32_t, int, struct ucred *,
+    NFSPROC_T *);
 int nfsrpc_destroysession(struct nfsmount *, struct nfsclclient *,
     struct ucred *, NFSPROC_T *);
 int nfsrpc_destroyclient(struct nfsmount *, struct nfsclclient *,
@@ -518,11 +541,27 @@ int nfsrpc_layoutreturn(struct nfsmount *, uint8_t *, 
     int, uint64_t, uint64_t, nfsv4stateid_t *, struct ucred *, NFSPROC_T *,
     uint32_t, uint32_t, char *);
 int nfsrpc_reclaimcomplete(struct nfsmount *, struct ucred *, NFSPROC_T *);
+int nfsrpc_advise(vnode_t, off_t, uint64_t, int, struct ucred *, NFSPROC_T *);
 int nfscl_doiods(vnode_t, struct uio *, int *, int *, uint32_t, int,
     struct ucred *, NFSPROC_T *);
 int nfscl_findlayoutforio(struct nfscllayout *, uint64_t, uint32_t,
     struct nfsclflayout **);
 void nfscl_freenfsclds(struct nfsclds *);
+int nfsrpc_allocate(vnode_t, off_t, off_t, struct nfsvattr *, int *,
+    struct ucred *, NFSPROC_T *, void *);
+int nfsrpc_copy_file_range(vnode_t, off_t *, vnode_t, off_t *, size_t *,
+    unsigned int, int *, struct nfsvattr *, int *, struct nfsvattr *,
+    struct ucred *, bool, bool *);
+int nfsrpc_seek(vnode_t, off_t *, bool *, int, struct ucred *,
+    struct nfsvattr *, int *);
+int nfsrpc_getextattr(vnode_t, const char *, struct uio *, ssize_t *,
+    struct nfsvattr *, int *, struct ucred *, NFSPROC_T *);
+int nfsrpc_setextattr(vnode_t, const char *, struct uio *, struct nfsvattr *,
+    int *, struct ucred *, NFSPROC_T *);
+int nfsrpc_listextattr(vnode_t, uint64_t *, struct uio *, size_t *, bool *,
+    struct nfsvattr *, int *, struct ucred *, NFSPROC_T *);
+int nfsrpc_rmextattr(vnode_t, const char *, struct nfsvattr *, int *,
+    struct ucred *, NFSPROC_T *);
 
 /* nfs_clstate.c */
 int nfscl_open(vnode_t, u_int8_t *, int, u_int32_t, int,
@@ -644,8 +683,8 @@ int nfsvno_readlink(vnode_t, struct ucred *, NFSPROC_T
     mbuf_t *, int *);
 int nfsvno_read(vnode_t, off_t, int, struct ucred *, NFSPROC_T *,
     mbuf_t *, mbuf_t *);
-int nfsvno_write(vnode_t, off_t, int, int, int *, mbuf_t,
-    char *, struct ucred *, NFSPROC_T *);
+int nfsvno_write(vnode_t, off_t, int, int *, mbuf_t, char *, struct ucred *,
+    NFSPROC_T *);
 int nfsvno_createsub(struct nfsrv_descript *, struct nameidata *,
     vnode_t *, struct nfsvattr *, int *, int32_t *, NFSDEV_T,
     struct nfsexstuff *);
@@ -704,6 +743,17 @@ int nfsrv_dscreate(struct vnode *, struct vattr *, str
 int nfsrv_updatemdsattr(struct vnode *, struct nfsvattr *, NFSPROC_T *);
 void nfsrv_killrpcs(struct nfsmount *);
 int nfsrv_setacl(struct vnode *, NFSACL_T *, struct ucred *, NFSPROC_T *);
+int nfsvno_seek(struct nfsrv_descript *, struct vnode *, u_long, off_t *, int,
+    bool *, struct ucred *, NFSPROC_T *);
+int nfsvno_allocate(struct vnode *, off_t, off_t, struct ucred *, NFSPROC_T *);
+int nfsvno_getxattr(struct vnode *, char *, uint32_t, struct ucred *,
+    struct thread *, struct mbuf **, struct mbuf **, int *);
+int nfsvno_setxattr(struct vnode *, char *, int, struct mbuf *, char *,
+    struct ucred *, struct thread *);
+int nfsvno_rmxattr(struct nfsrv_descript *, struct vnode *, char *,
+    struct ucred *, struct thread *);
+int nfsvno_listxattr(struct vnode *, uint64_t, struct ucred *, struct thread *,
+    u_char **, uint32_t *, bool *);
 
 /* nfs_commonkrpc.c */
 int newnfs_nmcancelreqs(struct nfsmount *);

Modified: head/sys/fs/nfs/nfsclstate.h
==============================================================================
--- head/sys/fs/nfs/nfsclstate.h	Thu Dec 12 22:59:22 2019	(r355676)
+++ head/sys/fs/nfs/nfsclstate.h	Thu Dec 12 23:22:55 2019	(r355677)
@@ -64,6 +64,8 @@ struct nfsclsession {
 	uint64_t	nfsess_slots;
 	uint32_t	nfsess_sequenceid;
 	uint32_t	nfsess_maxcache;	/* Max size for cached reply. */
+	uint32_t	nfsess_maxreq;		/* Max request size. */
+	uint32_t	nfsess_maxresp;		/* Max reply size. */
 	uint16_t	nfsess_foreslots;
 	uint16_t	nfsess_backslots;
 	uint8_t		nfsess_sessionid[NFSX_V4SESSIONID];
@@ -72,7 +74,7 @@ struct nfsclsession {
 
 /*
  * This structure holds the session, clientid and related information
- * needed for an NFSv4.1 Meta Data Server (MDS) or Data Server (DS).
+ * needed for an NFSv4.1 or NFSv4.2 Meta Data Server (MDS) or Data Server (DS).
  * It is malloc'd to the correct length.
  */
 struct nfsclds {
@@ -95,6 +97,7 @@ struct nfsclds {
 #define	NFSCLDS_DS		0x0004
 #define	NFSCLDS_CLOSED		0x0008
 #define	NFSCLDS_SAMECONN	0x0010
+#define	NFSCLDS_MINORV2		0x0020
 
 struct nfsclclient {
 	LIST_ENTRY(nfsclclient) nfsc_list;

Modified: head/sys/fs/nfs/nfsport.h
==============================================================================
--- head/sys/fs/nfs/nfsport.h	Thu Dec 12 22:59:22 2019	(r355676)
+++ head/sys/fs/nfs/nfsport.h	Thu Dec 12 23:22:55 2019	(r355677)
@@ -289,7 +289,7 @@
 /*
  * Must be one more than the last NFSv4.2 op#.
  */
-#define	NFSV42_NOPS		72
+#define	NFSV42_NOPS		76
 
 /* Quirky case if the illegal op code */
 #define	NFSV4OP_OPILLEGAL	10044
@@ -423,10 +423,10 @@
 #endif	/* NFS_V3NPROCS */
 
 /*
- * New stats structure.
+ * Newest stats structure.
  * The vers field will be set to NFSSTATS_V1 by the caller.
  */
-#define	NFSSTATS_V1	1
+#define	NFSSTATS_V1	2
 struct nfsstatsv1 {
 	int		vers;	/* Set to version requested by caller. */
 	uint64_t	attrcache_hits;
@@ -447,9 +447,9 @@ struct nfsstatsv1 {
 	uint64_t	readlink_bios;
 	uint64_t	biocache_readdirs;
 	uint64_t	readdir_bios;
-	uint64_t	rpccnt[NFSV41_NPROCS + 13];
+	uint64_t	rpccnt[NFSV42_NPROCS + 15];
 	uint64_t	rpcretries;
-	uint64_t	srvrpccnt[NFSV42_NOPS + NFSV4OP_FAKENOPS];
+	uint64_t	srvrpccnt[NFSV42_NOPS + NFSV4OP_FAKENOPS + 15];
 	uint64_t	srvrpc_errs;
 	uint64_t	srv_errs;
 	uint64_t	rpcrequests;
@@ -468,6 +468,71 @@ struct nfsstatsv1 {
 	uint64_t	srvlockowners;
 	uint64_t	srvlocks;
 	uint64_t	srvdelegates;
+	uint64_t	cbrpccnt[NFSV42_CBNOPS + 10];
+	uint64_t	clopenowners;
+	uint64_t	clopens;
+	uint64_t	cllockowners;
+	uint64_t	cllocks;
+	uint64_t	cldelegates;
+	uint64_t	cllocalopenowners;
+	uint64_t	cllocalopens;
+	uint64_t	cllocallockowners;
+	uint64_t	cllocallocks;
+	uint64_t	srvstartcnt;
+	uint64_t	srvdonecnt;
+	uint64_t	srvbytes[NFSV42_NOPS + NFSV4OP_FAKENOPS + 15];
+	uint64_t	srvops[NFSV42_NOPS + NFSV4OP_FAKENOPS + 15];
+	struct bintime	srvduration[NFSV42_NOPS + NFSV4OP_FAKENOPS + 15];
+	struct bintime	busyfrom;
+	struct bintime	busytime;
+};
+
+/*
+ * Newer stats structure.
+ * The vers field will be set to NFSSTATS_OV1 by the caller.
+ */
+#define	NFSSTATS_OV1	1
+struct nfsstatsov1 {
+	int		vers;	/* Set to version requested by caller. */
+	uint64_t	attrcache_hits;
+	uint64_t	attrcache_misses;
+	uint64_t	lookupcache_hits;
+	uint64_t	lookupcache_misses;
+	uint64_t	direofcache_hits;
+	uint64_t	direofcache_misses;
+	uint64_t	accesscache_hits;
+	uint64_t	accesscache_misses;
+	uint64_t	biocache_reads;
+	uint64_t	read_bios;
+	uint64_t	read_physios;
+	uint64_t	biocache_writes;
+	uint64_t	write_bios;
+	uint64_t	write_physios;
+	uint64_t	biocache_readlinks;
+	uint64_t	readlink_bios;
+	uint64_t	biocache_readdirs;
+	uint64_t	readdir_bios;
+	uint64_t	rpccnt[NFSV42_NPROCS + 4];
+	uint64_t	rpcretries;
+	uint64_t	srvrpccnt[NFSV42_PURENOPS + NFSV4OP_FAKENOPS];
+	uint64_t	srvrpc_errs;
+	uint64_t	srv_errs;
+	uint64_t	rpcrequests;
+	uint64_t	rpctimeouts;
+	uint64_t	rpcunexpected;
+	uint64_t	rpcinvalid;
+	uint64_t	srvcache_inproghits;
+	uint64_t	srvcache_idemdonehits;
+	uint64_t	srvcache_nonidemdonehits;
+	uint64_t	srvcache_misses;
+	uint64_t	srvcache_tcppeak;
+	int		srvcache_size;	/* Updated by atomic_xx_int(). */
+	uint64_t	srvclients;
+	uint64_t	srvopenowners;
+	uint64_t	srvopens;
+	uint64_t	srvlockowners;
+	uint64_t	srvlocks;
+	uint64_t	srvdelegates;
 	uint64_t	cbrpccnt[NFSV42_CBNOPS];
 	uint64_t	clopenowners;
 	uint64_t	clopens;
@@ -480,9 +545,9 @@ struct nfsstatsv1 {
 	uint64_t	cllocallocks;
 	uint64_t	srvstartcnt;
 	uint64_t	srvdonecnt;
-	uint64_t	srvbytes[NFSV42_NOPS + NFSV4OP_FAKENOPS];
-	uint64_t	srvops[NFSV42_NOPS + NFSV4OP_FAKENOPS];
-	struct bintime	srvduration[NFSV42_NOPS + NFSV4OP_FAKENOPS];
+	uint64_t	srvbytes[NFSV42_PURENOPS + NFSV4OP_FAKENOPS];
+	uint64_t	srvops[NFSV42_PURENOPS + NFSV4OP_FAKENOPS];
+	struct bintime	srvduration[NFSV42_PURENOPS + NFSV4OP_FAKENOPS];
 	struct bintime	busyfrom;
 	struct bintime	busytime;
 };

Modified: head/sys/fs/nfs/nfsproto.h
==============================================================================
--- head/sys/fs/nfs/nfsproto.h	Thu Dec 12 22:59:22 2019	(r355676)
+++ head/sys/fs/nfs/nfsproto.h	Thu Dec 12 23:22:55 2019	(r355677)
@@ -1070,7 +1070,7 @@ struct nfsv3_sattr {
 /* Not sure what attribute bit#81/0x00020000 is? */
 #define	NFSATTRBM_XATTRSUPPORT		0x00040000
 
-#define	NFSATTRBIT_MAX			77
+#define	NFSATTRBIT_MAX			83
 
 /*
  * Sets of attributes that are supported, by words in the bitmap.

Modified: head/sys/fs/nfsclient/nfs_clrpcops.c
==============================================================================
--- head/sys/fs/nfsclient/nfs_clrpcops.c	Thu Dec 12 22:59:22 2019	(r355676)
+++ head/sys/fs/nfsclient/nfs_clrpcops.c	Thu Dec 12 23:22:55 2019	(r355677)
@@ -48,6 +48,8 @@ __FBSDID("$FreeBSD$");
 #include "opt_inet6.h"
 
 #include <fs/nfs/nfsport.h>
+#include <fs/nfsclient/nfs.h>
+#include <sys/extattr.h>
 #include <sys/sysctl.h>
 #include <sys/taskqueue.h>
 
@@ -72,6 +74,8 @@ extern int nfsrv_useacl;
 extern char nfsv4_callbackaddr[INET6_ADDRSTRLEN];
 extern int nfscl_debuglevel;
 extern int nfs_pnfsiothreads;
+extern u_long sb_max_adj;
+extern int nfs_maxcopyrange;
 NFSCLSTATEMUTEX;
 int nfstest_outofseq = 0;
 int nfscl_assumeposixlocks = 1;
@@ -110,6 +114,9 @@ struct nfsclwritedsdorpc {
 	struct nfsclds		*dsp;
 	uint64_t		off;
 	int			len;
+#ifdef notyet
+	int			advise;
+#endif
 	struct nfsfh		*fhp;
 	struct mbuf		*m;
 	int			vers;
@@ -142,7 +149,8 @@ static int nfsrpc_getlayout(struct nfsmount *, vnode_t
     uint32_t *, nfsv4stateid_t *, uint64_t, struct nfscllayout **,
     struct ucred *, NFSPROC_T *);
 static int nfsrpc_fillsa(struct nfsmount *, struct sockaddr_in *,
-    struct sockaddr_in6 *, sa_family_t, int, struct nfsclds **, NFSPROC_T *);
+    struct sockaddr_in6 *, sa_family_t, int, int, struct nfsclds **,
+    NFSPROC_T *);
 static void nfscl_initsessionslots(struct nfsclsession *);
 static int nfscl_doflayoutio(vnode_t, struct uio *, int *, int *, int *,
     nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *,
@@ -172,12 +180,21 @@ static int nfsio_commitds(vnode_t, uint64_t, int, stru
     NFSPROC_T *);
 static int nfsrpc_commitds(vnode_t, uint64_t, int, struct nfsclds *,
     struct nfsfh *, int, int, struct ucred *, NFSPROC_T *);
+#ifdef notyet
+static int nfsio_adviseds(vnode_t, uint64_t, int, int, struct nfsclds *,
+    struct nfsfh *, int, int, struct nfsclwritedsdorpc *, struct ucred *,
+    NFSPROC_T *);
+static int nfsrpc_adviseds(vnode_t, uint64_t, int, int, struct nfsclds *,
+    struct nfsfh *, int, int, struct ucred *, NFSPROC_T *);
+#endif
+static int nfsrpc_allocaterpc(vnode_t, off_t, off_t, nfsv4stateid_t *,
+    struct nfsvattr *, int *, struct ucred *, NFSPROC_T *, void *);
 static void nfsrv_setuplayoutget(struct nfsrv_descript *, int, uint64_t,
     uint64_t, uint64_t, nfsv4stateid_t *, int, int, int);
 static int nfsrv_parseug(struct nfsrv_descript *, int, uid_t *, gid_t *,
     NFSPROC_T *);
-static int nfsrv_parselayoutget(struct nfsrv_descript *, nfsv4stateid_t *,
-    int *, struct nfsclflayouthead *);
+static int nfsrv_parselayoutget(struct nfsmount *, struct nfsrv_descript *,
+    nfsv4stateid_t *, int *, struct nfsclflayouthead *);
 static int nfsrpc_getopenlayout(struct nfsmount *, vnode_t, u_int8_t *,
     int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int,
     struct nfscldeleg **, struct ucred *, NFSPROC_T *);
@@ -200,6 +217,11 @@ static int nfsrpc_layoutget(struct nfsmount *, uint8_t
 static int nfsrpc_layoutgetres(struct nfsmount *, vnode_t, uint8_t *,
     int, nfsv4stateid_t *, int, uint32_t *, struct nfscllayout **,
     struct nfsclflayouthead *, int, int, int *, struct ucred *, NFSPROC_T *);
+static int nfsrpc_copyrpc(vnode_t, off_t, vnode_t, off_t, size_t *,
+    nfsv4stateid_t *, nfsv4stateid_t *, struct nfsvattr *, int *,
+    struct nfsvattr *, int *, bool, int *, struct ucred *, NFSPROC_T *);
+static int nfsrpc_seekrpc(vnode_t, off_t *, nfsv4stateid_t *, bool *,
+    int, struct nfsvattr *, int *, struct ucred *);
 
 int nfs_pnfsio(task_fn_t *, void *);
 
@@ -935,12 +957,12 @@ nfsrpc_setclient(struct nfsmount *nmp, struct nfsclcli
 		 * previous session has failed, so...
 		 * do an ExchangeID followed by the CreateSession.
 		 */
-		error = nfsrpc_exchangeid(nmp, clp, &nmp->nm_sockreq,
+		error = nfsrpc_exchangeid(nmp, clp, &nmp->nm_sockreq, 0,
 		    NFSV4EXCH_USEPNFSMDS | NFSV4EXCH_USENONPNFS, &dsp, cred, p);
 		NFSCL_DEBUG(1, "aft exch=%d\n", error);
 		if (error == 0)
 			error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
-			    &nmp->nm_sockreq,
+			    &nmp->nm_sockreq, NULL,
 			    dsp->nfsclds_sess.nfsess_sequenceid, 1, cred, p);
 		if (error == 0) {
 			NFSLOCKMNT(nmp);
@@ -4647,8 +4669,8 @@ nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPR
  */
 int
 nfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclclient *clp,
-    struct nfssockreq *nrp, uint32_t exchflags, struct nfsclds **dspp,
-    struct ucred *cred, NFSPROC_T *p)
+    struct nfssockreq *nrp, int minorvers, uint32_t exchflags,
+    struct nfsclds **dspp, struct ucred *cred, NFSPROC_T *p)
 {
 	uint32_t *tl, v41flags;
 	struct nfsrv_descript nfsd;
@@ -4658,7 +4680,10 @@ nfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclcl
 	int error, len;
 
 	*dspp = NULL;
-	nfscl_reqstart(nd, NFSPROC_EXCHANGEID, nmp, NULL, 0, NULL, NULL, 0, 0);
+	if (minorvers == 0)
+		minorvers = nmp->nm_minorvers;
+	nfscl_reqstart(nd, NFSPROC_EXCHANGEID, nmp, NULL, 0, NULL, NULL,
+	    NFS_VER4, minorvers);
 	NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 	*tl++ = txdr_unsigned(nfsboottime.tv_sec);	/* Client owner */
 	*tl = txdr_unsigned(clp->nfsc_rev);
@@ -4709,6 +4734,8 @@ nfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclcl
 		}
 		if ((v41flags & NFSV4EXCH_USEPNFSDS) != 0)
 			dsp->nfsclds_flags |= NFSCLDS_DS;
+		if (minorvers == NFSV42_MINORVERSION)
+			dsp->nfsclds_flags |= NFSCLDS_MINORV2;
 		if (len > 0)
 			nd->nd_repstat = nfsrv_mtostr(nd,
 			    dsp->nfsclds_serverown, len);
@@ -4732,21 +4759,27 @@ nfsmout:
  */
 int
 nfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep,
-    struct nfssockreq *nrp, uint32_t sequenceid, int mds, struct ucred *cred,
-    NFSPROC_T *p)
+    struct nfssockreq *nrp, struct nfsclds *dsp, uint32_t sequenceid, int mds,
+    struct ucred *cred, NFSPROC_T *p)
 {
 	uint32_t crflags, maxval, *tl;
 	struct nfsrv_descript nfsd;
 	struct nfsrv_descript *nd = &nfsd;
-	int error, irdcnt;
+	int error, irdcnt, minorvers;
 
 	/* Make sure nm_rsize, nm_wsize is set. */
 	if (nmp->nm_rsize > NFS_MAXBSIZE || nmp->nm_rsize == 0)
 		nmp->nm_rsize = NFS_MAXBSIZE;
 	if (nmp->nm_wsize > NFS_MAXBSIZE || nmp->nm_wsize == 0)
 		nmp->nm_wsize = NFS_MAXBSIZE;
-	nfscl_reqstart(nd, NFSPROC_CREATESESSION, nmp, NULL, 0, NULL, NULL, 0,
-	    0);
+	if (dsp == NULL)
+		minorvers = nmp->nm_minorvers;
+	else if ((dsp->nfsclds_flags & NFSCLDS_MINORV2) != 0)
+		minorvers = NFSV42_MINORVERSION;
+	else
+		minorvers = NFSV41_MINORVERSION;
+	nfscl_reqstart(nd, NFSPROC_CREATESESSION, nmp, NULL, 0, NULL, NULL,
+	    NFS_VER4, minorvers);
 	NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
 	*tl++ = sep->nfsess_clientid.lval[0];
 	*tl++ = sep->nfsess_clientid.lval[1];
@@ -4759,8 +4792,18 @@ nfsrpc_createsession(struct nfsmount *nmp, struct nfsc
 	/* Fill in fore channel attributes. */
 	NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED);
 	*tl++ = 0;				/* Header pad size */
-	*tl++ = txdr_unsigned(nmp->nm_wsize + NFS_MAXXDR);/* Max request size */
-	*tl++ = txdr_unsigned(nmp->nm_rsize + NFS_MAXXDR);/* Max reply size */
+	if ((nd->nd_flag & ND_NFSV42) != 0 && mds != 0 && sb_max_adj >=
+	    nmp->nm_wsize && sb_max_adj >= nmp->nm_rsize) {
+		/*
+		 * NFSv4.2 Extended Attribute operations may want to do
+		 * requests/replies that are larger than nm_rsize/nm_wsize.
+		 */
+		*tl++ = txdr_unsigned(sb_max_adj - NFS_MAXXDR);
+		*tl++ = txdr_unsigned(sb_max_adj - NFS_MAXXDR);
+	} else {
+		*tl++ = txdr_unsigned(nmp->nm_wsize + NFS_MAXXDR);
+		*tl++ = txdr_unsigned(nmp->nm_rsize + NFS_MAXXDR);
+	}
 	*tl++ = txdr_unsigned(4096);		/* Max response size cached */
 	*tl++ = txdr_unsigned(20);		/* Max operations */
 	*tl++ = txdr_unsigned(64);		/* Max slots */
@@ -4817,6 +4860,7 @@ nfsrpc_createsession(struct nfsmount *nmp, struct nfsc
 			else
 				break;
 		}
+		sep->nfsess_maxreq = maxval;
 
 		/* Make sure nm_rsize is small enough. */
 		maxval = fxdr_unsigned(uint32_t, *tl++);
@@ -4826,6 +4870,7 @@ nfsrpc_createsession(struct nfsmount *nmp, struct nfsc
 			else
 				break;
 		}
+		sep->nfsess_maxresp = maxval;
 
 		sep->nfsess_maxcache = fxdr_unsigned(int, *tl++);
 		tl++;
@@ -4928,7 +4973,8 @@ nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, i
 	if (error != 0)
 		return (error);
 	if (nd->nd_repstat == 0)
-		error = nfsrv_parselayoutget(nd, stateidp, retonclosep, flhp);
+		error = nfsrv_parselayoutget(nmp, nd, stateidp, retonclosep,
+		    flhp);
 	if (error == 0 && nd->nd_repstat != 0)
 		error = nd->nd_repstat;
 	mbuf_freem(nd->nd_mrep);
@@ -4950,7 +4996,8 @@ nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *de
 	struct sockaddr_in6 sin6, ssin6;
 	struct nfsclds *dsp = NULL, **dspp, **gotdspp;
 	struct nfscldevinfo *ndi;
-	int addrcnt = 0, bitcnt, error, gotvers, i, isudp, j, stripecnt;
+	int addrcnt = 0, bitcnt, error, gotminor, gotvers, i, isudp, j;
+	int stripecnt;
 	uint8_t stripeindex;
 	sa_family_t af, safilled;
 
@@ -5082,7 +5129,8 @@ nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *de
 			}
 		}
 
-		gotvers = NFS_VER4;	/* Always NFSv4 for File Layout. */
+		gotvers = NFS_VER4;	/* Default NFSv4.1 for File Layout. */
+		gotminor = NFSV41_MINORVERSION;
 		/* For Flex File, we will take one of the versions to use. */
 		if (layouttype == NFSLAYOUT_FLEXFILE) {
 			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
@@ -5093,14 +5141,19 @@ nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *de
 				goto nfsmout;
 			}
 			gotvers = 0;
+			gotminor = 0;
 			for (i = 0; i < j; i++) {
 				NFSM_DISSECT(tl, uint32_t *, 5 * NFSX_UNSIGNED);
 				vers = fxdr_unsigned(uint32_t, *tl++);
 				minorvers = fxdr_unsigned(uint32_t, *tl++);
-				if ((vers == NFS_VER4 && minorvers ==
-				    NFSV41_MINORVERSION) || (vers == NFS_VER3 &&
-				    gotvers == 0)) {
+				if (vers == NFS_VER3)
+					minorvers = 0;
+				if ((vers == NFS_VER4 && ((minorvers ==
+				    NFSV41_MINORVERSION && gotminor == 0) ||
+				    minorvers == NFSV42_MINORVERSION)) ||
+				    (vers == NFS_VER3 && gotvers == 0)) {
 					gotvers = vers;
+					gotminor = minorvers;
 					/* We'll take this one. */
 					ndi->nfsdi_versindex = i;
 					ndi->nfsdi_vers = vers;
@@ -5118,7 +5171,7 @@ nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *de
 				}
 			}
 			if (gotvers == 0) {
-				printf("pNFS: no NFSv3 or NFSv4.1\n");
+				printf("pNFS: no NFSv3, NFSv4.1 or NFSv4.2\n");
 				error = NFSERR_BADXDR;
 				goto nfsmout;
 			}
@@ -5144,7 +5197,7 @@ nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *de
 			 * NFS version and IP address.
 			 */
 			error = nfsrpc_fillsa(nmp, &ssin, &ssin6, safilled,
-			    gotvers, &dsp, p);
+			    gotvers, gotminor, &dsp, p);
 		}
 		if (error == 0) {
 			KASSERT(gotdspp != NULL, ("gotdspp is NULL"));
@@ -5373,15 +5426,15 @@ nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, str
  */
 static int
 nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_in *sin,
-    struct sockaddr_in6 *sin6, sa_family_t af, int vers, struct nfsclds **dspp,
-    NFSPROC_T *p)
+    struct sockaddr_in6 *sin6, sa_family_t af, int vers, int minorvers,
+    struct nfsclds **dspp, NFSPROC_T *p)
 {
 	struct sockaddr_in *msad, *sad;
 	struct sockaddr_in6 *msad6, *sad6;
 	struct nfsclclient *clp;
 	struct nfssockreq *nrp;
 	struct nfsclds *dsp, *tdsp;
-	int error;
+	int error, firsttry;
 	enum nfsclds_state retv;
 	uint32_t sequenceid;
 
@@ -5492,9 +5545,16 @@ nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_in
 	/* Now, do the exchangeid and create session. */
 	if (error == 0) {
 		if (vers == NFS_VER4) {
-			error = nfsrpc_exchangeid(nmp, clp, nrp,
-			    NFSV4EXCH_USEPNFSDS, &dsp, nrp->nr_cred, p);
-			NFSCL_DEBUG(3, "DS exchangeid=%d\n", error);
+			firsttry = 0;
+			do {
+				error = nfsrpc_exchangeid(nmp, clp, nrp, 
+				    minorvers, NFSV4EXCH_USEPNFSDS, &dsp,
+				    nrp->nr_cred, p);
+				NFSCL_DEBUG(3, "DS exchangeid=%d\n", error);
+				if (error == NFSERR_MINORVERMISMATCH)
+					minorvers = NFSV42_MINORVERSION;
+			} while (error == NFSERR_MINORVERMISMATCH &&
+			    firsttry++ == 0);
 			if (error != 0)
 				newnfs_disconnect(nrp);
 		} else {
@@ -5534,7 +5594,7 @@ nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_in
 				    dsp->nfsclds_sess.nfsess_sequenceid;
 			NFSUNLOCKMNT(nmp);
 			error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
-			    nrp, sequenceid, 0, nrp->nr_cred, p);
+			    nrp, dsp, sequenceid, 0, nrp->nr_cred, p);
 			NFSCL_DEBUG(3, "DS createsess=%d\n", error);
 		}
 	} else {
@@ -5896,7 +5956,7 @@ nfscl_findlayoutforio(struct nfscllayout *lyp, uint64_
 }
 
 /*
- * Do I/O using an NFSv4.1 file layout.
+ * Do I/O using an NFSv4.1 or NFSv4.2 file layout.
  */
 static int
 nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
@@ -5905,7 +5965,7 @@ nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *i
     uint64_t len, int docommit, struct ucred *cred, NFSPROC_T *p)
 {
 	uint64_t io_off, rel_off, stripe_unit_size, transfer, xfer;
-	int commit_thru_mds, error, stripe_index, stripe_pos;
+	int commit_thru_mds, error, stripe_index, stripe_pos, minorvers;
 	struct nfsnode *np;
 	struct nfsfh *fhp;
 	struct nfsclds **dspp;
@@ -5922,6 +5982,10 @@ nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *i
 	while (len > 0 && error == 0) {
 		stripe_index = nfsfldi_stripeindex(dp, stripe_pos);
 		dspp = nfsfldi_addr(dp, stripe_index);
+		if (((*dspp)->nfsclds_flags & NFSCLDS_MINORV2) != 0)
+			minorvers = NFSV42_MINORVERSION;
+		else
+			minorvers = NFSV41_MINORVERSION;
 		if (len > transfer && docommit == 0)
 			xfer = transfer;
 		else
@@ -5959,7 +6023,7 @@ nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *i
 		if (docommit != 0) {
 			if (error == 0)
 				error = nfsrpc_commitds(vp, io_off, xfer,
-				    *dspp, fhp, 0, 0, cred, p);
+				    *dspp, fhp, NFS_VER4, minorvers, cred, p);
 			if (error == 0) {
 				/*
 				 * Set both eof and uio_resid = 0 to end any
@@ -5974,11 +6038,11 @@ nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *i
 			}
 		} else if (rwflag == NFSV4OPEN_ACCESSREAD)
 			error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp,
-			    io_off, xfer, fhp, 0, 0, 0, cred, p);

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


More information about the svn-src-all mailing list