Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 30 Jul 1996 13:28:11 +0100 (BST)
From:      Doug Rabson <dfr@render.com>
To:        freebsd-current@freebsd.org
Subject:   NFS fixes for review
Message-ID:  <Pine.BSI.3.95.960730131214.11210E-100000@minnow.render.com>

next in thread | raw e-mail | index | archive | help
I have some fixes for NFSv3 in -current but I thought it would be a good
idea run them through a reviewer or two:

1.  Use the B_CLUSTEROK flag in nfs_doio() to allow multiple buffers to be
committed with a single rpc.

2.  Fix readdirplus in the NFSv3 server so that it is not totally broken.

3.  Some extremely primitive support for NFSv3 async mode which would
ignore the stability status from the server and always assume that the
data was stably written.  This can improve performance for a client
because it reduces pressure on the buffer cache since it doesn't have to
keep B_DELWRI|B_NEEDCOMMIT buffers around.  This should probably also
attempt a commit rpc in nfs_flush (implementation of VOP_FSYNC) but the
patch does not include this.  To use this support, a trivial change to
mount_nfs is also needed to allow the async option to be used for NFS
mounts.

4.  Use a dynamically sized array to coalesce commit requests in
nfs_flush() instead of a fixed size stack buffer.  This can improve
performance for copying large files over NFSv3 since it reduces the number
of commit rpcs sent over the wire.

5.  Fix a precedence error in nfs_writebp() which prevented proper
handling of B_DELWRI|B_NEEDCOMMIT buffers.  Also add relavent VMIO calls
to make this code actually work.  This part has already been reviewed by
Rick Macklem.

6.  Add some debug printfs to make my life easier.

7.  Import a minor fix from NetBSD to supply a definition of the NFSv3
mount protocol version.  This is required for some NetBSD fixes to
mount_nfs which I will commit seperately.


Index: nfs_bio.c
===================================================================
RCS file: /home/ncvs/src/sys/nfs/nfs_bio.c,v
retrieving revision 1.24
diff -u -r1.24 nfs_bio.c
--- nfs_bio.c	1996/07/16 10:19:43	1.24
+++ nfs_bio.c	1996/07/23 12:37:44
@@ -905,9 +905,11 @@
 		    iomode = NFSV3WRITE_FILESYNC;
 		bp->b_flags |= B_WRITEINPROG;
 		error = nfs_writerpc(vp, uiop, cr, &iomode, &must_commit);
-		if (!error && iomode == NFSV3WRITE_UNSTABLE)
+		if (!error && iomode == NFSV3WRITE_UNSTABLE) {
 		    bp->b_flags |= B_NEEDCOMMIT;
-		else
+		    if (bp->b_dirtyoff == 0 && bp->b_dirtyend == bp->b_bufsize)
+			bp->b_flags |= B_CLUSTEROK;
+		} else
 		    bp->b_flags &= ~B_NEEDCOMMIT;
 		bp->b_flags &= ~B_WRITEINPROG;
 
Index: nfs_serv.c
===================================================================
RCS file: /home/ncvs/src/sys/nfs/nfs_serv.c,v
retrieving revision 1.30
diff -u -r1.30 nfs_serv.c
--- nfs_serv.c	1996/06/08 12:16:26	1.30
+++ nfs_serv.c	1996/07/25 14:34:18
@@ -2919,6 +2919,7 @@
 		nfsm_srvpostop_attr(getret, &at);
 		return (0);
 	}
+	vput(nvp);
 	    
 	dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
 	nfsm_reply(cnt);
Index: nfs_vnops.c
===================================================================
RCS file: /home/ncvs/src/sys/nfs/nfs_vnops.c,v
retrieving revision 1.34
diff -u -r1.34 nfs_vnops.c
--- nfs_vnops.c	1996/07/16 10:19:45	1.34
+++ nfs_vnops.c	1996/07/23 12:39:28
@@ -1210,7 +1210,10 @@
 		tsiz -= len;
 	}
 nfsmout:
-	*iomode = committed;
+	if (vp->v_mount->mnt_flag & MNT_ASYNC)
+		*iomode = NFSV3WRITE_FILESYNC;
+	else
+		*iomode = committed;
 	if (error)
 		uiop->uio_resid = tsiz;
 	return (error);
@@ -2607,6 +2610,9 @@
 	int error = 0, wccflag = NFSV3_WCCRATTR;
 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 	
+#ifdef NFS_DEBUG
+	printf("nfs_commit(%x, %d, %d, %x, %x)\n", vp, (int) offset, cnt, cred, procp);
+#endif
 	if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0)
 		return (0);
 	nfsstats.rpccnt[NFSPROC_COMMIT]++;
@@ -2757,13 +2763,14 @@
 	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
 	int s, error = 0, slptimeo = 0, slpflag = 0, retv, bvecpos;
 	int passone = 1;
-	u_quad_t off = (u_quad_t)-1, endoff = 0, toff;
+	u_quad_t off, endoff, toff;
 	struct ucred* wcred = NULL;
-#ifndef NFS_COMMITBVECSIZ
-#define NFS_COMMITBVECSIZ	20
-#endif
-	struct buf *bvec[NFS_COMMITBVECSIZ];
+	struct buf **bvec = NULL;
+	int bvecsize = 0, bveccount;
 
+#ifdef NFS_DEBUG
+	printf("nfs_flush(%x, %x, %d, %x, %d)\n", vp, cred, waitfor, p, commit);
+#endif
 	if (nmp->nm_flag & NFSMNT_INT)
 		slpflag = PCATCH;
 	if (!commit)
@@ -2776,12 +2783,41 @@
 	 * job.
 	 */
 again:
+	off = (u_quad_t)-1;
+	endoff = 0;
 	bvecpos = 0;
 	if (NFS_ISV3(vp) && commit) {
 		s = splbio();
+		/*
+		 * Count up how many buffers waiting for a commit.
+		 */
+		bveccount = 0;
+		for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
+			nbp = bp->b_vnbufs.le_next;
+			if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
+			    == (B_DELWRI | B_NEEDCOMMIT))
+				bveccount++;
+		}
+		/*
+		 * Allocate space to remember the list of bufs to commit.  It is
+		 * important to use M_NOWAIT here to avoid a race with nfs_write.
+		 * If we can't get memory (for whatever reason), we will end up
+		 * committing the buffers one-by-one in the loop below.
+		 */
+		if (bveccount > bvecsize) {
+			if (bvec != NULL)
+				free(bvec, M_TEMP);
+			bvec = (struct buf **)
+				malloc(bveccount * sizeof(struct buf *),
+				       M_TEMP, M_NOWAIT);
+			if (bvec == NULL)
+				bvecsize = 0;
+			else
+				bvecsize = bveccount;
+		}
 		for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
 			nbp = bp->b_vnbufs.le_next;
-			if (bvecpos >= NFS_COMMITBVECSIZ)
+			if (bvecpos >= bvecsize)
 				break;
 			if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
 				!= (B_DELWRI | B_NEEDCOMMIT))
@@ -2822,10 +2858,14 @@
 		 * one call for all of them, otherwise commit each one
 		 * separately.
 		 */
-		if (wcred != NOCRED)
+		if (wcred != NOCRED) {
+#ifdef NFS_DEBUG
+printf("nfs_flush: calling nfs_commit(%x, %d, %d, %x, %x)\n",
+	vp, (int) off, (int) (endoff - off), wcred, p);
+#endif
 			retv = nfs_commit(vp, off, (int)(endoff - off),
 					  wcred, p);
-		else {
+		} else {
 			retv = 0;
 			for (i = 0; i < bvecpos; i++) {
 				off_t off, size;
@@ -2879,8 +2919,10 @@
 				"nfsfsync", slptimeo);
 			splx(s);
 			if (error) {
-			    if (nfs_sigintr(nmp, (struct nfsreq *)0, p))
-				return (EINTR);
+			    if (nfs_sigintr(nmp, (struct nfsreq *)0, p)) {
+				error = EINTR;
+				goto done;
+			    }
 			    if (slpflag == PCATCH) {
 				slpflag = 0;
 				slptimeo = 2 * hz;
@@ -2892,6 +2934,9 @@
 			panic("nfs_fsync: not dirty");
 		if ((passone || !commit) && (bp->b_flags & B_NEEDCOMMIT))
 			continue;
+#ifdef NFS_DEBUG
+printf("nfs_flush: writing bp=%x, bp->b_flags=%x\n", bp, bp->b_flags);
+#endif
 		bremfree(bp);
 		if (passone || !commit)
 		    bp->b_flags |= (B_BUSY|B_ASYNC);
@@ -2912,8 +2957,10 @@
 			error = tsleep((caddr_t)&vp->v_numoutput,
 				slpflag | (PRIBIO + 1), "nfsfsync", slptimeo);
 			if (error) {
-			    if (nfs_sigintr(nmp, (struct nfsreq *)0, p))
-				return (EINTR);
+			    if (nfs_sigintr(nmp, (struct nfsreq *)0, p)) {
+				error = EINTR;
+				goto done;
+			    }
 			    if (slpflag == PCATCH) {
 				slpflag = 0;
 				slptimeo = 2 * hz;
@@ -2928,6 +2975,9 @@
 		error = np->n_error;
 		np->n_flag &= ~NWRITEERR;
 	}
+done:
+	if (bvec)
+		free(bvec, M_TEMP);
 	return (error);
 }
 
@@ -3129,8 +3179,9 @@
 	 * an actual write will have to be scheduled via. VOP_STRATEGY().
 	 * If B_WRITEINPROG is already set, then push it with a write anyhow.
 	 */
-	if (oldflags & (B_NEEDCOMMIT | B_WRITEINPROG) == B_NEEDCOMMIT) {
+	if ((oldflags & (B_NEEDCOMMIT | B_WRITEINPROG)) == B_NEEDCOMMIT) {
 		off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff;
+		vfs_busy_pages(bp, 1);
 		bp->b_flags |= B_WRITEINPROG;
 		retv = nfs_commit(bp->b_vp, off, bp->b_dirtyend-bp->b_dirtyoff,
 			bp->b_wcred, bp->b_proc);
@@ -3139,8 +3190,10 @@
 			bp->b_dirtyoff = bp->b_dirtyend = 0;
 			bp->b_flags &= ~B_NEEDCOMMIT;
 			biodone(bp);
-		} else if (retv == NFSERR_STALEWRITEVERF)
+		} else if (retv == NFSERR_STALEWRITEVERF) {
 			nfs_clearcommit(bp->b_vp->v_mount);
+			vfs_unbusy_pages(bp);
+		}
 	}
 	if (retv) {
 		if (force)
Index: nfsnode.h
===================================================================
RCS file: /home/ncvs/src/sys/nfs/nfsnode.h,v
retrieving revision 1.15
diff -u -r1.15 nfsnode.h
--- nfsnode.h	1995/12/17 21:12:37	1.15
+++ nfsnode.h	1996/07/30 11:55:07
@@ -137,7 +137,7 @@
 #define	NUPD		0x0200	/* Special file updated */
 #define	NCHG		0x0400	/* Special file times changed */
 #define NLOCKED		0x0800  /* node is locked */
-#define NWANTED		0x0100  /* someone wants to lock */
+#define NWANTED		0x1000  /* someone wants to lock */
 
 /*
  * Convert between nfsnode pointers and vnode pointers
Index: rpcv2.h
===================================================================
RCS file: /home/ncvs/src/sys/nfs/rpcv2.h,v
retrieving revision 1.4
diff -u -r1.4 rpcv2.h
--- rpcv2.h	1995/06/27 11:07:02	1.4
+++ rpcv2.h	1996/07/17 14:16:14
@@ -90,6 +90,7 @@
 /* RPC Prog definitions */
 #define	RPCPROG_MNT	100005
 #define	RPCMNT_VER1	1
+#define	RPCMNT_VER3	3
 #define	RPCMNT_MOUNT	1
 #define	RPCMNT_DUMP	2
 #define	RPCMNT_UMOUNT	3


--
Doug Rabson, Microsoft RenderMorphics Ltd.	Mail:  dfr@render.com
						Phone: +44 171 251 4411
						FAX:   +44 171 251 0939




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSI.3.95.960730131214.11210E-100000>