Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 13 Jul 1996 11:47:02 +0100
From:      Doug Rabson <dfr@nlsys.demon.co.uk>
To:        current@freebsd.org
Cc:        dfr@render.com
Subject:   NFSv3 fixes for review
Message-ID:  <31E77EA6.41C67EA6@nlsys.demon.co.uk>

next in thread | raw e-mail | index | archive | help
I have just integrated some fixes to the NFSv3 code from Frank van der
Linden (frank@fwi.uva.nl).  The first bug is the same one as the
'corrupt output from makesyscalls.sh on an nfsv3 mount' bug.  I have
verified this one by testing on a loopback mount (which is all I can
do from my home machine).  I have not tried to reproduce the second
two problems but the fixes seem safe.

While I was here, I also fixed the truncated 32bit minor numbers on
nfsv3 mount bug.  I believe that Bruce originally suggested the fix
for this?

Could someone please review these changes (diffs included) so that I
can commit them.

P.S.  Is there a policy on using remote cvs to freefall?  I don't have
a cvs tree at home, so I used remote cvs to checkout the nfs source
and produce diffs.  What about commits via remote cvs?


Date: Fri, 12 Jan 1996 02:17:04 +0100 (MET)
From: frank@fwi.uva.nl (Frank van der Linden)
Subject: Re: nfs v3 bug


Thanks for the suggestions on the bug I reported. Too bad you don't have
a machine around there anymore on which you run the code (well.. unless
you get that VaxStation port going ;-))

Anyway, I think I found the bug. The scenario is as follows:

        - a process opens a file over NFS for writing, using v3
        - at some point it calls nfs_write(), which partially fills a buffer
          with bdwrite
        - an nfsiod grabs it, because it was doing an operation anyway,
          and it checks if more buffers are available
        - nfssvc_iod calls nfs_doio, and the buffer gets written to
          the server, but not committed to the server. The buffer
          will now have B_DELWRI and B_NEEDCOMMIT set
        - the process does another nfs_write, resulting in another
          bdwrite() into the same buffer.
        - there is now a buffer which still has B_DELWRI and
          B_NEEDCOMMIT set, and thus is looked at as being
          'written to the server but not committed'. This is
          wrong, because the buffer now contains more data than
          was originally written to the server.
        - when nfs_flush() is called, the buffer is only committed,
          the extra data never makes it to the server.

The fix I applied was simply clearing B_NEEDCOMMIT in bdwrite(). Perhaps
this was already done on the systems (BSDI, 4.4BSD?) you tested the code
on.

- Frank

----
Date: Mon, 1 Jul 1996 11:42:05 +0200 (MET DST)
From: frank@fwi.uva.nl (Frank van der Linden)
Subject: NFSv3 bugfix


Hi,

Here's an NFSv3 code bugfix I thought you should know about. The bug was,
that whenever a server (for whatever reason) returned an answer to a
write RPC that implied that fewer bytes than requested were written, bad
things would happen.

Following happened:

- nfs_writerpc sees that not all data was written
- it backs up the counter and pointer in the iov struct part of the uiop
- the write loop is entered again
- nfsm_uiotom is entered again (i.e. nfsm_uiotombuf())
- the first time that was called, uio_iov was incremented, because
  the iov had been completely 'emptied' into mbufs, so normally you'd
  move on to the next. however, iovcnt is always 1 in this case
  --> uio_iov is a bogus pointer now, pointing somewhere on the stack
  of nfs_doio(), where a local iov was used in the uio structure
- bad things happen when the bogus pointer is referenced.

Fix: make sure that iovcnt is always 1, and don't increment uio_iov, since
this should never happen. I also added a comment noting that nfsm_uiotombuf()
can only handle iovcnt == 1.

The fix is appended at the end of this mail.

---
Date: Wed, 10 Jul 1996 11:08:55 +0200 (MET DST)
From: frank@fwi.uva.nl (Frank van der Linden)
Subject: Some new fixes


Hi,

I know that you don't have the time currently to look at it, but i thought
I'd mail you these patches for the NFSv3 code anyway. There were 2 problems:

1) The setattr operation passed on the atime in stead of the mtime to
   the server. The fix is trivial.
2) XIDs always started at 0, but this caused some servers (older DEC OSF/1 3.0
   so I've been told) who had very long-lasting XID caches to get confused
   if, after a reboot of a BSD client, RPCs came in with a XID that had
   in the past been used before from that client. Patch is to use the
   current time in seconds as a starting point for XIDs. The patch below
   is not perfect, because it requires the root fs to be mounted first. This
   is because of the check BSD systems do, comparing FS time to system time.

The patches are appended below.

- Frank

Index: nfs_bio.c
===================================================================
RCS file: /home/ncvs/src/sys/nfs/nfs_bio.c,v
retrieving revision 1.23
diff -c -r1.23 nfs_bio.c
*** nfs_bio.c	1996/06/08 05:59:04	1.23
--- nfs_bio.c	1996/07/13 10:35:53
***************
*** 584,589 ****
--- 584,596 ----
  			bp->b_validoff = min(bp->b_validoff, bp->b_dirtyoff);
  			bp->b_validend = max(bp->b_validend, bp->b_dirtyend);
  		}
+ 
+ 		/*
+ 		 * Since this block is being modified, it must be written
+ 		 * again and not just committed.
+ 		 */
+ 		bp->b_flags &= ~B_NEEDCOMMIT;
+ 
  		/*
  		 * If the lease is non-cachable or IO_SYNC do bwrite().
  		 */
Index: nfs_subs.c
===================================================================
RCS file: /home/ncvs/src/sys/nfs/nfs_subs.c,v
retrieving revision 1.30
diff -c -r1.30 nfs_subs.c
*** nfs_subs.c	1996/06/23 17:19:25	1.30
--- nfs_subs.c	1996/07/13 10:37:48
***************
*** 53,58 ****
--- 53,59 ----
  #include <sys/socket.h>
  #include <sys/stat.h>
  #include <sys/malloc.h>
+ #include <sys/time.h>
  #ifdef VFS_LKM
  #include <sys/sysent.h>
  #include <sys/syscall.h>
***************
*** 635,640 ****
--- 636,643 ----
  	register int i;
  	struct mbuf *mreq, *mb2;
  	int siz, grpsiz, authsiz;
+ 	struct timeval tv;
+ 	static u_long base;
  
  	authsiz = nfsm_rndup(auth_len);
  	MGETHDR(mb, M_WAIT, MT_DATA);
***************
*** 653,660 ****
--- 656,677 ----
  	 * First the RPC header.
  	 */
  	nfsm_build(tl, u_long *, 8 * NFSX_UNSIGNED);
+ 
+ 	/*
+ 	 * derive initial xid from system time
+ 	 * XXX time is invalid if root not yet mounted
+ 	 */
+ 	if (!base && (rootvp)) {
+ 		microtime(&tv);
+ 		base = tv.tv_sec << 12;
+ 		nfs_xid = base;
+ 	}
+ 	/*
+ 	 * Skip zero xid if it should ever happen.
+ 	 */
  	if (++nfs_xid == 0)
  		nfs_xid++;
+ 
  	*tl++ = *xidp = txdr_unsigned(nfs_xid);
  	*tl++ = rpc_call;
  	*tl++ = rpc_vers;
***************
*** 834,840 ****
  }
  
  /*
!  * copies a uio scatter/gather list to an mbuf chain...
   */
  int
  nfsm_uiotombuf(uiop, mq, siz, bpos)
--- 851,858 ----
  }
  
  /*
!  * copies a uio scatter/gather list to an mbuf chain.
!  * NOTE: can ony handle iovcnt == 1
   */
  int
  nfsm_uiotombuf(uiop, mq, siz, bpos)
***************
*** 849,854 ****
--- 867,877 ----
  	int uiosiz, clflg, rem;
  	char *cp;
  
+ #ifdef DIAGNOSTIC
+ 	if (uiop->uio_iovcnt != 1)
+ 		panic("nfsm_uiotombuf: iovcnt != 1");
+ #endif
+ 
  	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
  		clflg = 1;
  	else
***************
*** 856,863 ****
  	rem = nfsm_rndup(siz)-siz;
  	mp = mp2 = *mq;
  	while (siz > 0) {
- 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
- 			return (EINVAL);
  		left = uiop->uio_iov->iov_len;
  		uiocp = uiop->uio_iov->iov_base;
  		if (left > siz)
--- 879,884 ----
***************
*** 892,904 ****
  			uiop->uio_offset += xfer;
  			uiop->uio_resid -= xfer;
  		}
! 		if (uiop->uio_iov->iov_len <= siz) {
! 			uiop->uio_iovcnt--;
! 			uiop->uio_iov++;
! 		} else {
! 			uiop->uio_iov->iov_base += uiosiz;
! 			uiop->uio_iov->iov_len -= uiosiz;
! 		}
  		siz -= uiosiz;
  	}
  	if (rem > 0) {
--- 913,920 ----
  			uiop->uio_offset += xfer;
  			uiop->uio_resid -= xfer;
  		}
! 		uiop->uio_iov->iov_base += uiosiz;
! 		uiop->uio_iov->iov_len -= uiosiz;
  		siz -= uiosiz;
  	}
  	if (rem > 0) {
***************
*** 1218,1225 ****
  	if (v3) {
  		vtyp = nfsv3tov_type(fp->fa_type);
  		vmode = fxdr_unsigned(u_short, fp->fa_mode);
! 		rdev = makedev(fxdr_unsigned(int, fp->fa3_rdev.specdata1),
! 			fxdr_unsigned(int, fp->fa3_rdev.specdata2));
  		fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
  	} else {
  		vtyp = nfsv2tov_type(fp->fa_type);
--- 1234,1241 ----
  	if (v3) {
  		vtyp = nfsv3tov_type(fp->fa_type);
  		vmode = fxdr_unsigned(u_short, fp->fa_mode);
! 		rdev = makedev(fxdr_unsigned(u_int, fp->fa3_rdev.specdata1),
! 			fxdr_unsigned(u_int, fp->fa3_rdev.specdata2));
  		fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
  	} else {
  		vtyp = nfsv2tov_type(fp->fa_type);
Index: nfs_vnops.c
===================================================================
RCS file: /home/ncvs/src/sys/nfs/nfs_vnops.c,v
retrieving revision 1.33
diff -c -r1.33 nfs_vnops.c
*** nfs_vnops.c	1996/01/25 00:45:37	1.33
--- nfs_vnops.c	1996/07/13 10:40:38
***************
*** 757,763 ****
  			if (vap->va_mtime.ts_sec != time.tv_sec) {
  				nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
  				*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
! 				txdr_nfsv3time(&vap->va_atime, tl);
  			} else {
  				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
  				*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
--- 757,763 ----
  			if (vap->va_mtime.ts_sec != time.tv_sec) {
  				nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
  				*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
! 				txdr_nfsv3time(&vap->va_mtime, tl);
  			} else {
  				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
  				*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);

-- 
Doug Rabson				Mail:  dfr@nlsys.demon.co.uk
					Phone: +44 181 951 1891



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?31E77EA6.41C67EA6>