NFS truncates files

Matthew Dillon dillon at apollo.backplane.com
Tue Oct 7 18:30:22 PDT 2003


    Here is a tentitive patch for NFS.  Basically what this patch does is
    record the ucred whenever read and/or write access is granted, then
    uses the ucred for read and write rpcs.

    This is essentially what FreeBSD does in another way.  FreeBSD records the
    ucreds used for operations all over the place... it records them in
    the buffer cache, it passes them to VOP_READ/VOP_WRITE, etc.... all so
    NFS can get a ucred for its read and write rpc.  But even though this
    handles most of the cases in FreeBSD it doesn't handle all the cases.
    For example, it does not handle pageout operations in the buffer
    reconstitution case (which causes the ucred in the buffer cache buffer
    to be lost) to NFS files that have been mounted without -maproot.

    What I do here is record the 'most likely to work' ucred for use in
    read and write ops.  It is still a bad hack, but at least it is a hack
    that is restricted to the NFS code and not strewn all around the kernel
    proper!! :-).  It could very well be that I break some other
    esoteric misfeature of NFS, in which case I would like to hear about it.

    I'll commit this at the end of the week if no problems crop up with it.

					-Matt

Index: vfs/nfs/nfs_node.c
===================================================================
RCS file: /cvs/src/sys/vfs/nfs/nfs_node.c,v
retrieving revision 1.7
diff -u -r1.7 nfs_node.c
--- vfs/nfs/nfs_node.c	7 Aug 2003 21:17:42 -0000	1.7
+++ vfs/nfs/nfs_node.c	8 Oct 2003 00:59:45 -0000
@@ -53,8 +53,8 @@
 #include "rpcv2.h"
 #include "nfsproto.h"
 #include "nfs.h"
-#include "nfsnode.h"
 #include "nfsmount.h"
+#include "nfsnode.h"
 
 static vm_zone_t nfsnode_zone;
 static LIST_HEAD(nfsnodehashhead, nfsnode) *nfsnodehashtbl;
@@ -277,6 +277,14 @@
 	}
 	if (np->n_fhsize > NFS_SMALLFH) {
 		FREE((caddr_t)np->n_fhp, M_NFSBIGFH);
+	}
+	if (np->n_rucred) {
+		crfree(np->n_rucred);
+		np->n_rucred = NULL;
+	}
+	if (np->n_wucred) {
+		crfree(np->n_wucred);
+		np->n_wucred = NULL;
 	}
 
 	cache_purge(vp);
Index: vfs/nfs/nfs_nqlease.c
===================================================================
RCS file: /cvs/src/sys/vfs/nfs/nfs_nqlease.c,v
retrieving revision 1.11
diff -u -r1.11 nfs_nqlease.c
--- vfs/nfs/nfs_nqlease.c	3 Sep 2003 14:30:57 -0000	1.11
+++ vfs/nfs/nfs_nqlease.c	8 Oct 2003 00:59:51 -0000
@@ -73,8 +73,8 @@
 #include "nfsm_subs.h"
 #include "xdr_subs.h"
 #include "nqnfs.h"
-#include "nfsnode.h"
 #include "nfsmount.h"
+#include "nfsnode.h"
 
 static MALLOC_DEFINE(M_NQMHOST, "NQNFS Host", "Nqnfs host address table");
 
@@ -872,7 +872,7 @@
 	*tl++ = txdr_unsigned(rwflag);
 	*tl = txdr_unsigned(nmp->nm_leaseterm);
 	reqtime = time_second;
-	nfsm_request(vp, NQNFSPROC_GETLEASE, td, NFSVPCRED(vp));
+	nfsm_request(vp, NQNFSPROC_GETLEASE, td, nfs_vpcred(vp, rwflag));
 	np = VTONFS(vp);
 	nfsm_dissect(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
 	cachable = fxdr_unsigned(int, *tl++);
Index: vfs/nfs/nfs_subs.c
===================================================================
RCS file: /cvs/src/sys/vfs/nfs/nfs_subs.c,v
retrieving revision 1.9
diff -u -r1.9 nfs_subs.c
--- vfs/nfs/nfs_subs.c	23 Sep 2003 05:03:53 -0000	1.9
+++ vfs/nfs/nfs_subs.c	8 Oct 2003 01:00:03 -0000
@@ -69,10 +69,10 @@
 #include "rpcv2.h"
 #include "nfsproto.h"
 #include "nfs.h"
+#include "nfsmount.h"
 #include "nfsnode.h"
 #include "xdr_subs.h"
 #include "nfsm_subs.h"
-#include "nfsmount.h"
 #include "nqnfs.h"
 #include "nfsrtt.h"
 
Index: vfs/nfs/nfs_vfsops.c
===================================================================
RCS file: /cvs/src/sys/vfs/nfs/nfs_vfsops.c,v
retrieving revision 1.8
diff -u -r1.8 nfs_vfsops.c
--- vfs/nfs/nfs_vfsops.c	20 Aug 2003 09:56:33 -0000	1.8
+++ vfs/nfs/nfs_vfsops.c	8 Oct 2003 01:00:11 -0000
@@ -64,8 +64,8 @@
 #include "rpcv2.h"
 #include "nfsproto.h"
 #include "nfs.h"
-#include "nfsnode.h"
 #include "nfsmount.h"
+#include "nfsnode.h"
 #include "xdr_subs.h"
 #include "nfsm_subs.h"
 #include "nfsdiskless.h"
@@ -333,7 +333,7 @@
 	nfsstats.rpccnt[NFSPROC_FSINFO]++;
 	nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1));
 	nfsm_fhtom(vp, 1);
-	nfsm_request(vp, NFSPROC_FSINFO, td, NFSVPCRED(vp));
+	nfsm_request(vp, NFSPROC_FSINFO, td, nfs_vpcred(vp, ND_READ));
 	nfsm_postop_attr(vp, retattr);
 	if (!error) {
 		nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
Index: vfs/nfs/nfs_vnops.c
===================================================================
RCS file: /cvs/src/sys/vfs/nfs/nfs_vnops.c,v
retrieving revision 1.12
diff -u -r1.12 nfs_vnops.c
--- vfs/nfs/nfs_vnops.c	23 Sep 2003 05:03:53 -0000	1.12
+++ vfs/nfs/nfs_vnops.c	8 Oct 2003 01:22:16 -0000
@@ -75,8 +75,8 @@
 #include "rpcv2.h"
 #include "nfsproto.h"
 #include "nfs.h"
-#include "nfsnode.h"
 #include "nfsmount.h"
+#include "nfsnode.h"
 #include "xdr_subs.h"
 #include "nfsm_subs.h"
 #include "nqnfs.h"
@@ -397,7 +397,6 @@
 				}
 			}
 		}
-		return (error);
 	} else {
 		if ((error = nfsspec_access(ap)) != 0)
 			return (error);
@@ -425,22 +424,41 @@
 			auio.uio_rw = UIO_READ;
 			auio.uio_td = ap->a_td;
 
-			if (vp->v_type == VREG)
+			if (vp->v_type == VREG) {
 				error = nfs_readrpc(vp, &auio);
-			else if (vp->v_type == VDIR) {
+			} else if (vp->v_type == VDIR) {
 				char* bp;
 				bp = malloc(NFS_DIRBLKSIZ, M_TEMP, M_WAITOK);
 				aiov.iov_base = bp;
 				aiov.iov_len = auio.uio_resid = NFS_DIRBLKSIZ;
 				error = nfs_readdirrpc(vp, &auio);
 				free(bp, M_TEMP);
-			} else if (vp->v_type == VLNK)
+			} else if (vp->v_type == VLNK) {
 				error = nfs_readlinkrpc(vp, &auio);
-			else
+			} else {
 				error = EACCES;
+			}
 		}
-		return (error);
 	}
+	/*
+	 * [re]record creds for reading and/or writing if access
+	 * was granted.
+	 */
+	if (error == 0) {
+		if ((ap->a_mode & VREAD) && ap->a_cred != np->n_rucred) {
+			crhold(ap->a_cred);
+			if (np->n_rucred)
+				crfree(np->n_rucred);
+			np->n_rucred = ap->a_cred;
+		}
+		if ((ap->a_mode & VWRITE) && ap->a_cred != np->n_wucred) {
+			crhold(ap->a_cred);
+			if (np->n_wucred)
+				crfree(np->n_wucred);
+			np->n_wucred = ap->a_cred;
+		}
+	}
+	return(error);
 }
 
 /*
@@ -637,7 +655,7 @@
 
 	if (v3 && nfsaccess_cache_timeout > 0) {
 		nfsstats.accesscache_misses++;
-		nfs3_access_otw(vp, NFSV3ACCESS_ALL, ap->a_td, NFSVPCRED(vp));
+		nfs3_access_otw(vp, NFSV3ACCESS_ALL, ap->a_td, nfs_vpcred(vp, ND_CHECK));
 		if (nfs_getattrcache(vp, ap->a_vap) == 0)
 			return (0);
 	}
@@ -645,7 +663,7 @@
 	nfsstats.rpccnt[NFSPROC_GETATTR]++;
 	nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH(v3));
 	nfsm_fhtom(vp, v3);
-	nfsm_request(vp, NFSPROC_GETATTR, ap->a_td, NFSVPCRED(vp));
+	nfsm_request(vp, NFSPROC_GETATTR, ap->a_td, nfs_vpcred(vp, ND_CHECK));
 	if (!error) {
 		nfsm_loadattr(vp, ap->a_vap);
 	}
@@ -1056,7 +1074,7 @@
 	nfsstats.rpccnt[NFSPROC_READLINK]++;
 	nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH(v3));
 	nfsm_fhtom(vp, v3);
-	nfsm_request(vp, NFSPROC_READLINK, uiop->uio_td, NFSVPCRED(vp));
+	nfsm_request(vp, NFSPROC_READLINK, uiop->uio_td, nfs_vpcred(vp, ND_CHECK));
 	if (v3)
 		nfsm_postop_attr(vp, attrflag);
 	if (!error) {
@@ -1109,7 +1127,7 @@
 			*tl++ = txdr_unsigned(len);
 			*tl = 0;
 		}
-		nfsm_request(vp, NFSPROC_READ, uiop->uio_td, NFSVPCRED(vp));
+		nfsm_request(vp, NFSPROC_READ, uiop->uio_td, nfs_vpcred(vp, ND_READ));
 		if (v3) {
 			nfsm_postop_attr(vp, attrflag);
 			if (error) {
@@ -1188,7 +1206,7 @@
 			*tl = x;	/* size of this write */
 		}
 		nfsm_uiotom(uiop, len);
-		nfsm_request(vp, NFSPROC_WRITE, uiop->uio_td, NFSVPCRED(vp));
+		nfsm_request(vp, NFSPROC_WRITE, uiop->uio_td, nfs_vpcred(vp, ND_WRITE));
 		if (v3) {
 			wccflag = NFSV3_WCCCHK;
 			nfsm_wcc_data(vp, wccflag);
@@ -1467,6 +1485,16 @@
 	if (!error) {
 		if (cnp->cn_flags & CNP_MAKEENTRY)
 			cache_enter(dvp, newvp, cnp);
+		/*
+		 * The new np may have enough info for access
+		 * checks, make sure rucred and wucred are
+		 * initialized for read and write rpc's.
+		 */
+		np = VTONFS(newvp);
+		if (np->n_rucred == NULL)
+			np->n_rucred = crhold(cnp->cn_cred);
+		if (np->n_wucred == NULL)
+			np->n_wucred = crhold(cnp->cn_cred);
 		*ap->a_vpp = newvp;
 	}
 	VTONFS(dvp)->n_flag |= NMODIFIED;
@@ -2124,7 +2152,7 @@
 			*tl++ = cookie.nfsuquad[0];
 		}
 		*tl = txdr_unsigned(nmp->nm_readdirsize);
-		nfsm_request(vp, NFSPROC_READDIR, uiop->uio_td, NFSVPCRED(vp));
+		nfsm_request(vp, NFSPROC_READDIR, uiop->uio_td, nfs_vpcred(vp, ND_READ));
 		if (v3) {
 			nfsm_postop_attr(vp, attrflag);
 			if (!error) {
@@ -2311,7 +2339,7 @@
 		*tl++ = dnp->n_cookieverf.nfsuquad[1];
 		*tl++ = txdr_unsigned(nmp->nm_readdirsize);
 		*tl = txdr_unsigned(nmp->nm_rsize);
-		nfsm_request(vp, NFSPROC_READDIRPLUS, uiop->uio_td, NFSVPCRED(vp));
+		nfsm_request(vp, NFSPROC_READDIRPLUS, uiop->uio_td, nfs_vpcred(vp, ND_READ));
 		nfsm_postop_attr(vp, attrflag);
 		if (error) {
 			m_freem(mrep);
@@ -2642,7 +2670,7 @@
 	txdr_hyper(offset, tl);
 	tl += 2;
 	*tl = txdr_unsigned(cnt);
-	nfsm_request(vp, NFSPROC_COMMIT, td, NFSVPCRED(vp));
+	nfsm_request(vp, NFSPROC_COMMIT, td, nfs_vpcred(vp, ND_WRITE));
 	nfsm_wcc_data(vp, wccflag);
 	if (!error) {
 		nfsm_dissect(tl, u_int32_t *, NFSX_V3WRITEVERF);
@@ -3267,7 +3295,7 @@
 				vattr.va_atime = np->n_atim;
 			if (np->n_flag & NUPD)
 				vattr.va_mtime = np->n_mtim;
-			(void)VOP_SETATTR(vp, &vattr, NFSVPCRED(vp), ap->a_td);
+			(void)VOP_SETATTR(vp, &vattr, nfs_vpcred(vp, ND_WRITE), ap->a_td);
 		}
 	}
 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
@@ -3349,7 +3377,7 @@
 				vattr.va_atime = np->n_atim;
 			if (np->n_flag & NUPD)
 				vattr.va_mtime = np->n_mtim;
-			(void)VOP_SETATTR(vp, &vattr, NFSVPCRED(vp), ap->a_td);
+			(void)VOP_SETATTR(vp, &vattr, nfs_vpcred(vp, ND_WRITE), ap->a_td);
 		}
 	}
 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
Index: vfs/nfs/nfsmount.h
===================================================================
RCS file: /cvs/src/sys/vfs/nfs/nfsmount.h,v
retrieving revision 1.3
diff -u -r1.3 nfsmount.h
--- vfs/nfs/nfsmount.h	26 Jun 2003 05:55:18 -0000	1.3
+++ vfs/nfs/nfsmount.h	8 Oct 2003 00:52:19 -0000
@@ -103,7 +103,6 @@
  * Convert mount ptr to nfsmount ptr.
  */
 #define VFSTONFS(mp)	((struct nfsmount *)((mp)->mnt_data))
-#define NFSVPCRED(vp)	(VFSTONFS((vp)->v_mount)->nm_cred)
 extern void nfs_free_mount(struct nfsmount *nmp);
 
 #endif
Index: vfs/nfs/nfsnode.h
===================================================================
RCS file: /cvs/src/sys/vfs/nfs/nfsnode.h,v
retrieving revision 1.5
diff -u -r1.5 nfsnode.h
--- vfs/nfs/nfsnode.h	20 Aug 2003 09:56:33 -0000	1.5
+++ vfs/nfs/nfsnode.h	8 Oct 2003 01:01:34 -0000
@@ -75,16 +75,19 @@
 
 /*
  * The nfsnode is the nfs equivalent to ufs's inode. Any similarity
- * is purely coincidental.
- * There is a unique nfsnode allocated for each active file,
- * each current directory, each mounted-on file, text file, and the root.
+ * is purely coincidental.  There is a unique nfsnode allocated for
+ * each active file, each current directory, each mounted-on file,
+ * text file, and the root.
+ *
  * An nfsnode is 'named' by its file handle. (nget/nfs_node.c)
- * If this structure exceeds 256 bytes (it is currently 256 using 4.4BSD-Lite
- * type definitions), file handles of > 32 bytes should probably be split out
- * into a separate MALLOC()'d data structure. (Reduce the size of nfsfh_t by
- * changing the definition in nfsproto.h of NFS_SMALLFH.)
- * NB: Hopefully the current order of the fields is such that everything will
- *     be well aligned and, therefore, tightly packed.
+ *
+ * File handles are accessed via n_fhp, which will point to n_fh if the
+ * file handle is small enough (<= NFS_SMALLFH).  Otherwise the file handle 
+ * will be allocated.
+ *
+ * DragonFly does not pass ucreds to read and write operations, since such
+ * operations are not possible unless the ucred has already been validated.
+ * Validating ucreds are stored in nfsnode to pass on to NFS read/write RPCs.
  */
 struct nfsnode {
 	struct lock		n_lock;
@@ -102,6 +105,8 @@
 	time_t			n_ctime;	/* Prev create time. */
 	time_t			n_expiry;	/* Lease expiry time */
 	nfsfh_t			*n_fhp;		/* NFS File Handle */
+	struct ucred		*n_rucred;
+	struct ucred		*n_wucred;
 	struct vnode		*n_vnode;	/* associated vnode */
 	struct lockf		*n_lockf;	/* Locking record of file */
 	int			n_error;	/* Save write error value */
@@ -145,6 +150,7 @@
 #define	NCHG		0x0400	/* Special file times changed */
 #define NLOCKED		0x0800  /* node is locked */
 #define NWANTED		0x0100  /* someone wants to lock */
+#define NUSECRED	0x0200	/* use n_rucred/n_wucred, else use root */
 
 /*
  * Convert between nfsnode pointers and vnode pointers
@@ -183,6 +189,19 @@
 nfs_rsunlock(struct nfsnode *np, struct thread *td)
 {
 	(void)lockmgr(&np->n_rslock, LK_RELEASE, NULL, td);
+}
+
+static __inline
+struct ucred *
+nfs_vpcred(struct vnode *vp, int ndflag)
+{
+	struct nfsnode *np = VTONFS(vp);
+
+	if (np && (ndflag & ND_WRITE) && np->n_wucred)
+		return(np->n_wucred);
+	if (np && (ndflag & ND_READ) && np->n_rucred)
+		return(np->n_rucred);
+	return(VFSTONFS((vp)->v_mount)->nm_cred);
 }
 
 extern	vop_t	**fifo_nfsv2nodeop_p;





More information about the Bugs mailing list