Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 23 Oct 2019 01:29:09 +0000 (UTC)
From:      Rick Macklem <rmacklem@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r353910 - projects/nfsv42/sys/fs/nfsclient
Message-ID:  <201910230129.x9N1T9sF086461@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rmacklem
Date: Wed Oct 23 01:29:09 2019
New Revision: 353910
URL: https://svnweb.freebsd.org/changeset/base/353910

Log:
  Add a flag for Advise not supported and fix Copy for length == 0.
  
  When an NFSv4.2 reports that the Advise operation is not supported,
  note that so that no more Advise operations will be attempted for the mount.
  For Copy where the NFSv4.2 server replies a copied length == 0, fix the
  client so that it recognizes this as "at EOF".
  This will not normally happen, since the client clips the requested
  copy length at EOF, however if another client truncates the file, this
  could happen for a Linux style NFSv4.2 server.

Modified:
  projects/nfsv42/sys/fs/nfsclient/nfs_clvnops.c
  projects/nfsv42/sys/fs/nfsclient/nfsmount.h

Modified: projects/nfsv42/sys/fs/nfsclient/nfs_clvnops.c
==============================================================================
--- projects/nfsv42/sys/fs/nfsclient/nfs_clvnops.c	Wed Oct 23 01:11:25 2019	(r353909)
+++ projects/nfsv42/sys/fs/nfsclient/nfs_clvnops.c	Wed Oct 23 01:29:09 2019	(r353910)
@@ -3475,12 +3475,21 @@ nfs_advise(struct vop_advise_args *ap)
 	else
 		len = ap->a_end - ap->a_start + 1;
 	nmp = VFSTONFS(ap->a_vp->v_mount);
+	mtx_lock(&nmp->nm_mtx);
 	if (!NFSHASNFSV4(nmp) || nmp->nm_minorvers < NFSV42_MINORVERSION ||
 	    (NFSHASPNFS(nmp) && (nmp->nm_privflag & NFSMNTP_IOADVISETHRUMDS) ==
-	    0))
+	    0) || (nmp->nm_privflag & NFSMNTP_NOADVISE) != 0) {
+		mtx_unlock(&nmp->nm_mtx);
 		return (0);
-	nfsrpc_advise(ap->a_vp, ap->a_start, len, ap->a_advice,
+	}
+	mtx_unlock(&nmp->nm_mtx);
+	error = nfsrpc_advise(ap->a_vp, ap->a_start, len, ap->a_advice,
 	    td->td_ucred, td);
+	if (error == NFSERR_NOTSUPP) {
+		mtx_lock(&nmp->nm_mtx);
+		nmp->nm_privflag |= NFSMNTP_NOADVISE;
+		mtx_unlock(&nmp->nm_mtx);
+	}
 	return (0);
 }
 
@@ -3533,10 +3542,11 @@ nfs_copy_file_range(struct vop_copy_file_range_args *a
 	struct vnode *outvp = ap->a_outvp;
 	struct mount *mp;
 	struct nfsvattr innfsva, outnfsva;
+	struct vattr *vap;
 	struct uio io;
 	struct nfsmount *nmp;
-	size_t len, len2;
-	int error, inattrflag, outattrflag, ret;
+	size_t len, len2, copiedlen;
+	int error, inattrflag, outattrflag, ret, ret2;
 	off_t inoff, outoff;
 	bool consecutive, must_commit, tryoutcred;
 
@@ -3610,6 +3620,24 @@ nfs_copy_file_range(struct vop_copy_file_range_args *a
 	outoff = *ap->a_outoffp;
 	tryoutcred = true;
 	must_commit = false;
+	if (error == 0) {
+		vap = &VTONFS(invp)->n_vattr.na_vattr;
+		error = VOP_GETATTR(invp, vap, ap->a_incred);
+		if (error == 0) {
+			/*
+			 * Clip "len" at va_size so that RFC compliant servers
+			 * will not reply NFSERR_INVAL.
+			 * Setting "len == 0" for the RPC would be preferred,
+			 * but some Linux servers do not support that,
+			 */
+			if (inoff >= vap->va_size)
+				*ap->a_lenp = len = 0;
+			else if (inoff + len > vap->va_size)
+				*ap->a_lenp = len = vap->va_size - inoff;
+		} else
+			error = 0;
+	}
+	copiedlen = 0;
 	while (len > 0 && error == 0) {
 		inattrflag = outattrflag = 0;
 		len2 = len;
@@ -3623,27 +3651,12 @@ nfs_copy_file_range(struct vop_copy_file_range_args *a
 			    outvp, ap->a_outoffp, &len2, ap->a_flags,
 			    &inattrflag, &innfsva, &outattrflag, &outnfsva,
 			    ap->a_incred, consecutive, &must_commit);
-		if (inattrflag != 0) {
+		if (inattrflag != 0)
 			ret = nfscl_loadattrcache(&invp, &innfsva, NULL, NULL,
 			    0, 1);
-			if (error == 0 && ret != 0)
-				error = ret;
-		}
-		if (outattrflag != 0) {
-			ret = nfscl_loadattrcache(&outvp, &outnfsva, NULL, NULL,
-			    1, 1);
-			if (error == 0 && ret != 0)
-				error = ret;
-		}
-		if (error == 0 && len2 == 0) {
-			/*
-			 * Some Linux NFSv4.2 servers can reply NFS_OK, but
-			 * with a copied length (wr_count) == 0 when the
-			 * offset + len is past EOF. (RFC-7862 requires a
-			 * reply of NFS4ERR_INVAL for this case.)
-			 */
-			error = NFSERR_INVAL;
-		}
+		if (outattrflag != 0)
+			ret2 = nfscl_loadattrcache(&outvp, &outnfsva, NULL,
+			    NULL, 1, 1);
 		if (error == 0) {
 			if (consecutive == false) {
 				if (len2 == len) {
@@ -3654,10 +3667,24 @@ nfs_copy_file_range(struct vop_copy_file_range_args *a
 				} else
 					error = NFSERR_OFFLOADNOREQS;
 			}
-			len -= len2;
+			/*
+			 * If the Copy returns a length == 0, it hit the
+			 * EOF on the input file.
+			 */
+			if (len2 == 0) {
+				*ap->a_lenp = copiedlen;
+				len = 0;
+			} else {
+				len -= len2;
+				copiedlen += len2;
+			}
 			if (len == 0 && must_commit && error == 0)
 				error = ncl_commit(outvp, outoff, *ap->a_lenp,
 				    ap->a_outcred, curthread);
+			if (error == 0 && ret != 0)
+				error = ret;
+			if (error == 0 && ret2 != 0)
+				error = ret2;
 		} else if (error == NFSERR_OFFLOADNOREQS && consecutive) {
 			/*
 			 * Try consecutive == false, which is ok only if all

Modified: projects/nfsv42/sys/fs/nfsclient/nfsmount.h
==============================================================================
--- projects/nfsv42/sys/fs/nfsclient/nfsmount.h	Wed Oct 23 01:11:25 2019	(r353909)
+++ projects/nfsv42/sys/fs/nfsclient/nfsmount.h	Wed Oct 23 01:29:09 2019	(r353910)
@@ -111,6 +111,7 @@ struct	nfsmount {
 #define	NFSMNTP_SEEK		0x00000020
 #define	NFSMNTP_SEEKTESTED	0x00000040
 #define	NFSMNTP_NOXATTR		0x00000080
+#define	NFSMNTP_NOADVISE	0x00000100
 
 #define	NFSMNT_DIRPATH(m)	(&((m)->nm_name[(m)->nm_krbnamelen + 1]))
 #define	NFSMNT_SRVKRBNAME(m)						\



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