brunner@bullhead.uucp (11/17/89)
Subject: Patch for NFS (MIT "hammerfix" posted as patch) Index: /sys/nfs/nfs_server.c /sys/rpc/clnt_kudp.c /sys/sys/vfs_vnode.c Description: This patch is equivalent to the files contained in the "hammerfix" compressed tar image previously installed on ibmsupt. The fix is posted here as a forward context diff for the benefit of sites which may not have known about or applied the fix. A well known NFS problem that MIT found and fixed is the occasional zeroing out of blocks of information during internodal transmission. VERY simplistically, the problem is created when a block of data is retransmitted, due to loss or timeout. Certain operations, notably "open (with trucate)" were being performed more than once on a block, causing previously received data to be truncated, and hence lost. This would show up as loader errors, RCS errors, etc. Basically, some limited transmission state information has been added (in the form of a packet timestamp) to allow checking for whether a block is an original or a retransmission. The source code changes have been ifdef'd else NOMITFIX so that the fix code would be the default. Fix: Apply the following patch to the files: /sys/nfs/nfs_server.c /sys/rpc/clnt_kudp.c /sys/sys/vfs_vnode.c Note that this may be accomplished easiest from /sys, passing the -p1 flag to patch, e.g., patch -p1 < this_file diff -r -c2 sys/nfs/nfs_server.c sys.fix/nfs/nfs_server.c *** sys/nfs/nfs_server.c Fri Dec 9 14:57:57 1988 --- sys.fix/nfs/nfs_server.c Wed Oct 25 18:00:50 1989 *************** *** 1,12 **** /* ! * 5799-WZQ (C) COPYRIGHT = NONE * LICENSED MATERIALS - PROPERTY OF IBM */ ! /* $Header:nfs_server.c 12.0$ */ ! /* $ACIS:nfs_server.c 12.0$ */ /* $Source: /ibm/acis/usr/sys/nfs/RCS/nfs_server.c,v $ */ #ifndef lint ! static char *rcsid = "$Header:nfs_server.c 12.0$"; #endif --- 1,11 ---- /* ! * P_R_P_Q_# (C) COPYRIGHT = NONE * LICENSED MATERIALS - PROPERTY OF IBM */ ! /* $Header: nfs_server.c,v 12.2 89/01/11 18:40:35 rusty Exp $ */ /* $Source: /ibm/acis/usr/sys/nfs/RCS/nfs_server.c,v $ */ #ifndef lint ! static char *rcsid = "$Header: nfs_server.c,v 12.2 89/01/11 18:40:35 rusty Exp $"; #endif *************** *** 40,44 **** #include "nfs.h" #include "mbuf.h" ! extern struct vnodeops nfs_vnodeops; --- 39,46 ---- #include "nfs.h" #include "mbuf.h" ! #ifdef NOMITFIX ! #else NOMITFIX ! #include "syslog.h" ! #endif NOMITFIX extern struct vnodeops nfs_vnodeops; *************** *** 605,608 **** --- 607,616 ---- struct vnode *vp; register struct vnode *dvp; + #ifdef NOMITFIX + #else NOMITFIX + int found = 0; + int founderror; + int mismatch = 0; + #endif NOMITFIX #ifdef NFSDEBUG *************** *** 650,653 **** --- 658,662 ---- error = EROFS; } else { + #ifdef NOMITFIX error = VOP_CREATE(dvp, args->ca_da.da_name, &va, NONEXCL, VWRITE, &vp, u.u_cred); *************** *** 662,665 **** --- 671,740 ---- } } + #else NOMITFIX + struct vattr mod_va; + if ((int)va.va_mtime.tv_sec != -1) { + /* Assume new client which breaks protocol spec.-- + Check mod. time to make sure it's still correct. */ + founderror = VOP_LOOKUP(dvp, + args->ca_da.da_name, &vp, u.u_cred); + found = 1; + if (!founderror) { + error = VOP_GETATTR(vp, &mod_va, u.u_cred); + if (!error) { + if ((va.va_mtime.tv_sec != mod_va.va_mtime.tv_sec) || + (va.va_mtime.tv_usec != mod_va.va_mtime.tv_usec)) { + log(LOG_DEBUG, + "rfs_create: modtime mismatch [%x %x] %ld.%ld %ld.%ld\n", + args->ca_da.da_fhandle.fh_fsid, + args->ca_da.da_fhandle.fh_len, + va.va_mtime.tv_sec, va.va_mtime.tv_usec, + mod_va.va_mtime.tv_sec, + mod_va.va_mtime.tv_usec); + mismatch = 1; + error = ESTALE; /* XXX */ + } + } + } + } + + /* + * jtkohl@ATHENA.MIT.EDU: Need to check for dup BEFORE + * calling VOP_CREATE, since VOP_CREATE may truncate a file. + * If retransmitted, and biod's/nfsd's scramble the ordering, + * data can be lost. + */ + /* + * check for dup request + */ + if (svckudp_dup(req)) { + if (!mismatch) + log(LOG_DEBUG, "rfs_create: dup not mismatch[%x %x]\n", + args->ca_da.da_fhandle.fh_fsid, + args->ca_da.da_fhandle.fh_len); + + if (!found) + error = VOP_LOOKUP(dvp, + args->ca_da.da_name, &vp, u.u_cred); + else + error = founderror; + } else { + if (mismatch) { + log(LOG_DEBUG, "rfs_create: mismatch not dup [%x %x]\n", + args->ca_da.da_fhandle.fh_fsid, + args->ca_da.da_fhandle.fh_len); + if (!found) + error = VOP_LOOKUP(dvp, + args->ca_da.da_name, &vp, u.u_cred); + else + error = founderror; + } else + if (found && !founderror) + /* release vnode we looked up before */ + VN_RELE(vp); + error = VOP_CREATE(dvp, args->ca_da.da_name, + &va, NONEXCL, VWRITE, &vp, u.u_cred); + } + } + #endif NOMITFIX if (!error) { error = VOP_GETATTR(vp, &va, u.u_cred); diff -r -c2 sys/rpc/clnt_kudp.c sys.fix/rpc/clnt_kudp.c *** sys/rpc/clnt_kudp.c Fri Dec 9 14:58:26 1988 --- sys.fix/rpc/clnt_kudp.c Wed Oct 25 18:01:44 1989 *************** *** 1,12 **** /* ! * 5799-WZQ (C) COPYRIGHT = NONE * LICENSED MATERIALS - PROPERTY OF IBM */ ! /* $Header:clnt_kudp.c 12.0$ */ ! /* $ACIS:clnt_kudp.c 12.0$ */ /* $Source: /ibm/acis/usr/sys/rpc/RCS/clnt_kudp.c,v $ */ #ifndef lint ! static char *rcsid = "$Header:clnt_kudp.c 12.0$"; #endif --- 1,11 ---- /* ! * P_R_P_Q_# (C) COPYRIGHT = NONE * LICENSED MATERIALS - PROPERTY OF IBM */ ! /* $Header: clnt_kudp.c,v 12.2 89/01/11 18:31:55 rusty Exp $ */ /* $Source: /ibm/acis/usr/sys/rpc/RCS/clnt_kudp.c,v $ */ #ifndef lint ! static char *rcsid = "$Header: clnt_kudp.c,v 12.2 89/01/11 18:31:55 rusty Exp $"; #endif *************** *** 109,112 **** --- 108,115 ---- #define CKU_BUFBUSY 0x008 #define CKU_BUFWANTED 0x010 + #ifdef NOMITFIX + #else NOMITFIX + #define CKU_ONCE_ONLY 0x020 + #endif NOMITFIX /* Times to retry */ *************** *** 116,119 **** --- 119,137 ---- int clntkudpxid; /* transaction id used by all clients */ + #ifdef NOMITFIX + #else NOMITFIX + clntkudp_once(cl, flag) + CLIENT *cl; + { + struct cku_private *p = (struct cku_private *)cl->cl_private; + + if (flag != 0) { + p->cku_flags |= CKU_ONCE_ONLY; + } else { + p->cku_flags &= ~CKU_ONCE_ONLY; + } + } + #endif NOMITFIX + static noop() *************** *** 282,285 **** --- 300,308 ---- p->cku_flags |= CKU_BUSY; + #ifdef NOMITFIX + #else NOMITFIX + if ((p->cku_flags & CKU_ONCE_ONLY) != 0) + stries = 1; + #endif NOMITFIX /* * Set credentials into the u structure *************** *** 413,416 **** --- 436,447 ---- rcstat.rcbadxids++; m_freem(p->cku_inmbuf); + #ifdef NOMITFIX + #else NOMITFIX + #ifdef RPCDEBUG + rpc_debug(1, "callit: bad xid %d %d\n", + *((u_long *)(p->cku_inbuf)), + *((u_long *)(p->cku_outbuf))); + #endif + #endif NOMITFIX continue; } *************** *** 484,487 **** --- 515,533 ---- } u.u_cred = tmpcred; + #ifdef NOMITFIX + #else NOMITFIX + /* + * Insure that buffer is not busy prior to releasing client handle. + */ + s = splimp(); + while (p->cku_flags & CKU_BUFBUSY) { + p->cku_flags |= CKU_BUFWANTED; + timeout(wakeup, (caddr_t)&p->cku_outbuf, hz); + (void) sleep((caddr_t)&p->cku_outbuf, PZERO-3); + sbflush(&so->so_rcv); + } + (void) splx(s); + #endif NOMITFIX + p->cku_flags &= ~CKU_BUSY; if (p->cku_flags & CKU_WANTED) { diff -r -c2 sys/sys/vfs_vnode.c sys.fix/sys/vfs_vnode.c *** sys/sys/vfs_vnode.c Fri Dec 9 15:07:22 1988 --- sys.fix/sys/vfs_vnode.c Wed Oct 25 18:02:18 1989 *************** *** 1,13 **** /* ! * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1988 * LICENSED MATERIALS - PROPERTY OF IBM * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083 */ ! /* $Header:vfs_vnode.c 12.0$ */ ! /* $ACIS:vfs_vnode.c 12.0$ */ /* $Source: /ibm/acis/usr/sys/sys/RCS/vfs_vnode.c,v $ */ ! #if !defined(lint) && !defined(NO_RCS_HDRS) ! static char *rcsid = "$Header:vfs_vnode.c 12.0$"; #endif --- 1,12 ---- /* ! * P_R_P_Q_# (C) COPYRIGHT IBM CORPORATION 1988,1989 * LICENSED MATERIALS - PROPERTY OF IBM * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083 */ ! /* $Header: vfs_vnode.c,v 12.2 89/01/11 18:43:05 rusty Exp $ */ /* $Source: /ibm/acis/usr/sys/sys/RCS/vfs_vnode.c,v $ */ ! #if !defined (lint) && !defined(NO_RCS_HDRS) ! static char *rcsid = "$Header: vfs_vnode.c,v 12.2 89/01/11 18:43:05 rusty Exp $"; #endif *************** *** 105,108 **** --- 104,111 ---- if (filemode & FCREAT) { struct vattr vattr; + #ifdef NOMITFIX + #else NOMITFIX + struct vattr extra_vattr; + #endif NOMITFIX enum vcexcl excl; *************** *** 120,124 **** excl = NONEXCL; filemode &= ~(FCREAT | FTRUNC | FEXCL); ! error = vn_create(pnamep, seg, &vattr, excl, mode, &vp); if (error) --- 123,138 ---- excl = NONEXCL; filemode &= ~(FCREAT | FTRUNC | FEXCL); ! #ifdef NOMITFIX ! #else NOMITFIX ! /* Look it up first, and include mod. time in create request.*/ ! error = lookupname(pnamep, seg, FOLLOW_LINK, ! (struct vnode **)0, &vp); ! if (!error) { ! error = VOP_GETATTR(vp, &extra_vattr, u.u_cred); ! VN_RELE(vp); ! if (!error) ! vattr.va_mtime = extra_vattr.va_mtime; ! } ! #endif NOMITFIX error = vn_create(pnamep, seg, &vattr, excl, mode, &vp); if (error) Eric Brunner, Consultant, IBM AWD Palo Alto (415) 855-4486 inet: brunner@monet.berkeley.edu uucp: uunet!ibmsupt!brunner