Revert "viced: avoid crash if missing volume header"
[openafs.git] / src / viced / afsfileprocs.c
index 74fef85..69aff57 100644 (file)
 /* ********************************************************************** */
 
 /*
+ * GetVolumePackage disables Rx keepalives; PutVolumePackage re-enables.
+ * If callbacks are to be broken, keepalives should be enabled in the
+ * stub while that occurs; disabled while disk I/O is in process.
+ */
+
+/*
  * in Check_PermissionRights, certain privileges are afforded to the owner
  * of the volume, or the owner of a file.  Are these considered "use of
  * privilege"?
 
 #include <afsconfig.h>
 #include <afs/param.h>
+#include <afs/stds.h>
 
+#include <roken.h>
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
 #ifdef AFS_SGI_ENV
 #undef SHARED                  /* XXX */
 #endif
-#ifdef AFS_NT40_ENV
-#include <fcntl.h>
-#else
-#include <sys/param.h>
-#include <sys/file.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <string.h>
-
-#ifndef AFS_LINUX20_ENV
+
+#ifdef HAVE_NET_IF_H
 #include <net/if.h>
-#ifndef AFS_ARM_DARWIN_ENV
+#endif
+
+#ifdef HAVE_NETINET_IF_ETHER_H
 #include <netinet/if_ether.h>
 #endif
+
+#if !defined(AFS_SGI_ENV) && defined(HAVE_SYS_MAP_H)
+#include <sys/map.h>
 #endif
+
+#ifdef HAVE_SYS_STATFS_H
+#include <sys/statfs.h>
+#endif
+
+#ifdef HAVE_SYS_LOCKF_H
+#include <sys/lockf.h>
+#endif
+
+#ifdef HAVE_SYS_DK_H
+#include <sys/dk.h>
 #endif
+
 #ifdef AFS_HPUX_ENV
 /* included early because of name conflict on IOPEN */
 #include <sys/inode.h>
 #undef IOPEN
 #endif
 #endif /* AFS_HPUX_ENV */
-#include <afs/stds.h>
+
 #include <rx/xdr.h>
 #include <afs/nfs.h>
-#include <afs/afs_assert.h>
 #include <lwp.h>
 #include <lock.h>
 #include <afs/afsint.h>
 #include <afs/acl.h>
 #include <rx/rx.h>
 #include <rx/rx_globals.h>
-#include <sys/stat.h>
-#if ! defined(AFS_SGI_ENV) && ! defined(AFS_AIX32_ENV) && ! defined(AFS_NT40_ENV) && ! defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
-#include <sys/map.h>
-#endif
-#if !defined(AFS_NT40_ENV)
-#include <unistd.h>
-#endif
-#if !defined(AFS_SGI_ENV) && !defined(AFS_NT40_ENV)
-#ifdef AFS_AIX_ENV
-#include <sys/statfs.h>
-#include <sys/lockf.h>
-#else
-#if !defined(AFS_SUN5_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
-#include <sys/dk.h>
-#endif
-#endif
-#endif
+
 #include <afs/cellconfig.h>
 #include <afs/keys.h>
 
-#include <signal.h>
 #include <afs/partition.h>
 #include "viced_prototypes.h"
 #include "viced.h"
@@ -114,20 +107,7 @@ extern void SetDirHandle(DirHandle * dir, Vnode * vnode);
 extern void FidZap(DirHandle * file);
 extern void FidZero(DirHandle * file);
 
-#ifdef AFS_PTHREAD_ENV
 pthread_mutex_t fileproc_glock_mutex;
-#endif /* AFS_PTHREAD_ENV */
-
-#ifdef O_LARGEFILE
-#define afs_stat       stat64
-#define afs_fstat      fstat64
-#define afs_open       open64
-#else /* !O_LARGEFILE */
-#define afs_stat       stat
-#define afs_fstat      fstat
-#define afs_open       open
-#endif /* !O_LARGEFILE */
-
 
 /* Useful local defines used by this module */
 
@@ -175,13 +155,9 @@ extern afs_int32 dataVersionHigh;
 
 extern int SystemId;
 static struct AFSCallStatistics AFSCallStats;
-#if FS_STATS_DETAILED
 struct fs_stats_FullPerfStats afs_FullPerfStats;
 extern int AnonymousID;
-#endif /* FS_STATS_DETAILED */
-#if OPENAFS_VOL_STATS
 static const char nullString[] = "";
-#endif /* OPENAFS_VOL_STATS */
 
 struct afs_FSStats {
     afs_int32 NothingYet;
@@ -207,25 +183,19 @@ extern int CEs, CEBlocks;
 
 extern int HTs, HTBlocks;
 
-afs_int32 FetchData_RXStyle(Volume * volptr, Vnode * targetptr,
-                           struct rx_call *Call, afs_sfsize_t Pos,
-                           afs_sfsize_t Len, afs_int32 Int64Mode,
-#if FS_STATS_DETAILED
-                           afs_sfsize_t * a_bytesToFetchP,
-                           afs_sfsize_t * a_bytesFetchedP
-#endif                         /* FS_STATS_DETAILED */
-    );
-
-afs_int32 StoreData_RXStyle(Volume * volptr, Vnode * targetptr,
-                           struct AFSFid *Fid, struct client *client,
-                           struct rx_call *Call, afs_fsize_t Pos,
-                           afs_fsize_t Length, afs_fsize_t FileLength,
-                           int sync,
-#if FS_STATS_DETAILED
-                           afs_sfsize_t * a_bytesToStoreP,
-                           afs_sfsize_t * a_bytesStoredP
-#endif                         /* FS_STATS_DETAILED */
-    );
+static afs_int32 FetchData_RXStyle(Volume * volptr, Vnode * targetptr,
+                                  struct rx_call *Call, afs_sfsize_t Pos,
+                                  afs_sfsize_t Len, afs_int32 Int64Mode,
+                                  afs_sfsize_t * a_bytesToFetchP,
+                                  afs_sfsize_t * a_bytesFetchedP);
+
+static afs_int32 StoreData_RXStyle(Volume * volptr, Vnode * targetptr,
+                                  struct AFSFid *Fid, struct client *client,
+                                  struct rx_call *Call, afs_fsize_t Pos,
+                                  afs_fsize_t Length, afs_fsize_t FileLength,
+                                  int sync,
+                                  afs_sfsize_t * a_bytesToStoreP,
+                                  afs_sfsize_t * a_bytesStoredP);
 
 #ifdef AFS_SGI_XFS_IOPS_ENV
 #include <afs/xfsattrs.h>
@@ -287,6 +257,65 @@ SetVolumeSync(struct AFSVolSync *async, Volume * avol)
     FS_UNLOCK;
 }                              /*SetVolumeSync */
 
+/**
+ * Verify that the on-disk size for a vnode matches the length in the vnode
+ * index.
+ *
+ * @param[in] vp   Volume pointer
+ * @param[in] vnp  Vnode pointer
+ * @param[in] alen Size of the vnode on disk, if known. If unknown, give -1,
+ *                 and CheckLength itself will determine the on-disk size.
+ *
+ * @return operation status
+ *  @retval 0 lengths match
+ *  @retval nonzero Error; either the lengths do not match or there was an
+ *                  error determining the on-disk size. The volume should be
+ *                  taken offline and salvaged.
+ */
+static int
+CheckLength(struct Volume *vp, struct Vnode *vnp, afs_sfsize_t alen)
+{
+    afs_sfsize_t vlen;
+    VN_GET_LEN(vlen, vnp);
+
+    if (alen < 0) {
+       FdHandle_t *fdP;
+
+       fdP = IH_OPEN(vnp->handle);
+       if (fdP == NULL) {
+           ViceLog(0, ("CheckLength: cannot open inode for fid %lu.%lu.%lu\n",
+                       afs_printable_uint32_lu(vp->hashid),
+                       afs_printable_uint32_lu(Vn_id(vnp)),
+                       afs_printable_uint32_lu(vnp->disk.uniquifier)));
+           return -1;
+       }
+       alen = FDH_SIZE(fdP);
+       FDH_CLOSE(fdP);
+       if (alen < 0) {
+           afs_int64 alen64 = alen;
+           ViceLog(0, ("CheckLength: cannot get size for inode for fid "
+                       "%lu.%lu.%lu; FDH_SIZE returned %" AFS_INT64_FMT "\n",
+                       afs_printable_uint32_lu(vp->hashid),
+                       afs_printable_uint32_lu(Vn_id(vnp)),
+                       afs_printable_uint32_lu(vnp->disk.uniquifier),
+                       alen64));
+           return -1;
+       }
+    }
+
+    if (alen != vlen) {
+       afs_int64 alen64 = alen, vlen64 = vlen;
+       ViceLog(0, ("Fid %lu.%lu.%lu has inconsistent length (index "
+                   "%lld inode %lld ); volume must be salvaged\n",
+                   afs_printable_uint32_lu(vp->hashid),
+                   afs_printable_uint32_lu(Vn_id(vnp)),
+                   afs_printable_uint32_lu(vnp->disk.uniquifier),
+                   vlen64, alen64));
+       return -1;
+    }
+    return 0;
+}
+
 /*
  * Note that this function always returns a held host, so
  * that CallPostamble can block without the host's disappearing.
@@ -301,9 +330,7 @@ CallPreamble(struct rx_call *acall, int activecall,
     int retry_flag = 1;
     int code = 0;
     char hoststr[16], hoststr2[16];
-#ifdef AFS_PTHREAD_ENV
     struct ubik_client *uclient;
-#endif
     *ahostp = NULL;
 
     if (!tconn) {
@@ -316,7 +343,7 @@ CallPreamble(struct rx_call *acall, int activecall,
   retry:
     tclient = h_FindClient_r(*tconn);
     if (!tclient) {
-       ViceLog(0, ("CallPreamble: Couldn't get CPS. Too many lockers\n"));
+       ViceLog(0, ("CallPreamble: Couldn't get client.\n"));
        H_UNLOCK;
        return VBUSY;
     }
@@ -334,7 +361,6 @@ CallPreamble(struct rx_call *acall, int activecall,
        /* Take down the old connection and re-read the key file */
        ViceLog(0,
                ("CallPreamble: Couldn't get CPS. Reconnect to ptserver\n"));
-#ifdef AFS_PTHREAD_ENV
        uclient = (struct ubik_client *)pthread_getspecific(viced_uclient_key);
 
        /* Is it still necessary to drop this? We hit the net, we should... */
@@ -348,9 +374,7 @@ CallPreamble(struct rx_call *acall, int activecall,
        if (!code)
            osi_Assert(pthread_setspecific(viced_uclient_key, (void *)uclient) == 0);
        H_LOCK;
-#else
-       code = pr_Initialize(2, AFSDIR_SERVER_ETC_DIRPATH, 0);
-#endif
+
        if (code) {
            h_ReleaseClient_r(tclient);
            h_Release_r(thost);
@@ -470,7 +494,8 @@ CallPostamble(struct rx_connection *aconn, afs_int32 ret,
  * are incremented and they must be eventualy released.
  */
 static afs_int32
-CheckVnode(AFSFid * fid, Volume ** volptr, Vnode ** vptr, int lock)
+CheckVnodeWithCall(AFSFid * fid, Volume ** volptr, struct VCallByVol *cbv,
+                   Vnode ** vptr, int lock)
 {
     Error fileCode = 0;
     Error local_errorCode, errorCode = -1;
@@ -489,9 +514,12 @@ CheckVnode(AFSFid * fid, Volume ** volptr, Vnode ** vptr, int lock)
                VRESTARTING
 #endif
                ;
+           static const struct timespec timeout_ts = { 0, 0 };
+           static const struct timespec * const ts = &timeout_ts;
 
            errorCode = 0;
-           *volptr = VGetVolumeNoWait(&local_errorCode, &errorCode, (afs_int32) fid->Volume);
+           *volptr = VGetVolumeWithCall(&local_errorCode, &errorCode,
+                                              fid->Volume, ts, cbv);
            if (!errorCode) {
                osi_Assert(*volptr);
                break;
@@ -601,6 +629,12 @@ CheckVnode(AFSFid * fid, Volume ** volptr, Vnode ** vptr, int lock)
     return (0);
 }                              /*CheckVnode */
 
+static_inline afs_int32
+CheckVnode(AFSFid * fid, Volume ** volptr, Vnode ** vptr, int lock)
+{
+    return CheckVnodeWithCall(fid, volptr, NULL, vptr, lock);
+}
+
 /*
  * This routine returns the ACL associated with the targetptr. If the
  * targetptr isn't a directory, we access its parent dir and get the ACL
@@ -685,9 +719,6 @@ GetRights(struct client *client, struct acl_accessList *ACL,
 {
     extern prlist SystemAnyUserCPS;
     afs_int32 hrights = 0;
-#ifndef AFS_PTHREAD_ENV
-    int code;
-#endif
 
     if (acl_CheckRights(ACL, &SystemAnyUserCPS, anyrights) != 0) {
        ViceLog(0, ("CheckRights failed\n"));
@@ -701,13 +732,7 @@ GetRights(struct client *client, struct acl_accessList *ACL,
     H_LOCK;
     while (client->host->hostFlags & HCPS_INPROGRESS) {
        client->host->hostFlags |= HCPS_WAITING;        /* I am waiting */
-#ifdef AFS_PTHREAD_ENV
        CV_WAIT(&client->host->cond, &host_glock_mutex);
-#else /* AFS_PTHREAD_ENV */
-       if ((code =
-            LWP_WaitProcess(&(client->host->hostFlags))) != LWP_SUCCESS)
-           ViceLog(0, ("LWP_WaitProcess returned %d\n", code));
-#endif /* AFS_PTHREAD_ENV */
     }
 
     if (!client->host->hcps.prlist_len || !client->host->hcps.prlist_val) {
@@ -745,73 +770,157 @@ VanillaUser(struct client *client)
 }                              /*VanillaUser */
 
 
-/*
- * This unusual afs_int32-parameter routine encapsulates all volume package related
- * operations together in a single function; it's called by almost all AFS
- * interface calls.
- */
+/*------------------------------------------------------------------------
+ * GetVolumePackageWithCall
+ *
+ * Description:
+ *      This unusual afs_int32-parameter routine encapsulates all volume
+ *      package related operations together in a single function; it's
+ *      called by almost all AFS interface calls.
+ *
+ * Arguments:
+ *      acall               : Ptr to Rx call on which this request came in.
+ *      cbv                 : struct containing the RX call for offline cancels
+ *      Fid                 : the AFS fid the caller is acting on
+ *      volptr              : returns a pointer to the volume struct
+ *      targetptr           : returns a pointer to the vnode struct
+ *      chkforDir           : whether to check for if vnode is a dir
+ *      parent              : returns a pointer to the parent of this vnode
+ *      client              : returns a pointer to the calling client
+ *      locktype            : indicates what kind of lock to take on vnodes
+ *      rights              : returns a pointer to caller's rights
+ *      anyrights           : returns a pointer to anonymous' rights
+ *      remote             : indicates that the volume is a remote RW replica
+ *
+ * Returns:
+ *      0 on success
+ *      appropriate error based on permission or invalid operation.
+ *
+ * Environment:
+ *      Nothing interesting.
+ *
+ * Side Effects:
+ *      On success, disables keepalives on the call. Caller should re-enable
+ *      after completing disk I/O.
+ *------------------------------------------------------------------------*/
 static afs_int32
-GetVolumePackage(struct rx_connection *tcon, AFSFid * Fid, Volume ** volptr,
-                Vnode ** targetptr, int chkforDir, Vnode ** parent,
-                struct client **client, int locktype, afs_int32 * rights,
-                afs_int32 * anyrights)
+GetVolumePackageWithCall(struct rx_call *acall, struct VCallByVol *cbv,
+                         AFSFid * Fid, Volume ** volptr, Vnode ** targetptr,
+                         int chkforDir, Vnode ** parent,
+                        struct client **client, int locktype,
+                        afs_int32 * rights, afs_int32 * anyrights, int remote)
 {
     struct acl_accessList *aCL;        /* Internal access List */
     int aCLSize;               /* size of the access list */
     Error errorCode = 0;               /* return code to caller */
+    struct rx_connection *tcon = rx_ConnectionOf(acall);
+
+    rx_KeepAliveOff(acall);
+
+    if ((errorCode = CheckVnodeWithCall(Fid, volptr, cbv, targetptr, locktype)))
+       goto gvpdone;
 
-    if ((errorCode = CheckVnode(Fid, volptr, targetptr, locktype)))
-       return (errorCode);
     if (chkforDir) {
        if (chkforDir == MustNOTBeDIR
-           && ((*targetptr)->disk.type == vDirectory))
-           return (EISDIR);
+           && ((*targetptr)->disk.type == vDirectory)) {
+           errorCode = EISDIR;
+           goto gvpdone;
+       }
        else if (chkforDir == MustBeDIR
-                && ((*targetptr)->disk.type != vDirectory))
-           return (ENOTDIR);
-    }
-    if ((errorCode =
-        SetAccessList(targetptr, volptr, &aCL, &aCLSize, parent,
-                      (chkforDir == MustBeDIR ? (AFSFid *) 0 : Fid),
-                      (chkforDir == MustBeDIR ? 0 : locktype))) != 0)
-       return (errorCode);
-    if (chkforDir == MustBeDIR)
-       osi_Assert((*parent) == 0);
-    if (!(*client)) {
-       if ((errorCode = GetClient(tcon, client)) != 0)
-           return (errorCode);
-       if (!(*client))
-           return (EINVAL);
-    }
-    GetRights(*client, aCL, rights, anyrights);
-    /* ok, if this is not a dir, set the PRSFS_ADMINISTER bit iff we're the owner */
-    if ((*targetptr)->disk.type != vDirectory) {
-       /* anyuser can't be owner, so only have to worry about rights, not anyrights */
-       if ((*targetptr)->disk.owner == (*client)->ViceId)
-           (*rights) |= PRSFS_ADMINISTER;
-       else
-           (*rights) &= ~PRSFS_ADMINISTER;
+                && ((*targetptr)->disk.type != vDirectory)) {
+           errorCode = ENOTDIR;
+           goto gvpdone;
+       }
     }
+    /*
+     * If the remote flag is set, the current call is dealing with a remote RW
+     * replica, and it can be assumed that the appropriate access checks were
+     * done by the calling server hosting the master volume.
+     */
+    if (!remote) {
+       if ((errorCode = SetAccessList(targetptr, volptr, &aCL, &aCLSize, parent,
+               (chkforDir == MustBeDIR ? (AFSFid *) 0 : Fid),
+               (chkforDir == MustBeDIR ? 0 : locktype))) != 0)
+           goto gvpdone;
+       if (chkforDir == MustBeDIR)
+           osi_Assert((*parent) == 0);
+       if (!(*client)) {
+           if ((errorCode = GetClient(tcon, client)) != 0)
+               goto gvpdone;
+           if (!(*client))
+               errorCode = EINVAL;
+               goto gvpdone;
+       }
+       GetRights(*client, aCL, rights, anyrights);
+       /* ok, if this is not a dir, set the PRSFS_ADMINISTER bit iff we're the owner */
+       if ((*targetptr)->disk.type != vDirectory) {
+           /* anyuser can't be owner, so only have to worry about rights, not anyrights */
+           if ((*targetptr)->disk.owner == (*client)->ViceId)
+               (*rights) |= PRSFS_ADMINISTER;
+           else
+               (*rights) &= ~PRSFS_ADMINISTER;
+       }
 #ifdef ADMIN_IMPLICIT_LOOKUP
-    /* admins get automatic lookup on everything */
-    if (!VanillaUser(*client))
-       (*rights) |= PRSFS_LOOKUP;
+       /* admins get automatic lookup on everything */
+       if (!VanillaUser(*client))
+           (*rights) |= PRSFS_LOOKUP;
 #endif /* ADMIN_IMPLICIT_LOOKUP */
+gvpdone:
+    if (errorCode)
+       rx_KeepAliveOn(acall);
+    }
     return errorCode;
 
 }                              /*GetVolumePackage */
 
+static_inline afs_int32
+GetVolumePackage(struct rx_call *acall, AFSFid * Fid, Volume ** volptr,
+                Vnode ** targetptr, int chkforDir, Vnode ** parent,
+                struct client **client, int locktype, afs_int32 * rights,
+                afs_int32 * anyrights)
+{
+    return GetVolumePackageWithCall(acall, NULL, Fid, volptr, targetptr,
+                                    chkforDir, parent, client, locktype,
+                                    rights, anyrights, 0);
+}
+
 
-/*
- * This is the opposite of GetVolumePackage(), and is always used at the end of
- * AFS calls to put back all used vnodes and the volume in the proper order!
- */
+/*------------------------------------------------------------------------
+ * PutVolumePackageWithCall
+ *
+ * Description:
+ *      This is the opposite of GetVolumePackage(), and is always used at
+ *      the end of AFS calls to put back all used vnodes and the volume
+ *      in the proper order!
+ *
+ * Arguments:
+ *      acall               : Ptr to Rx call on which this request came in.
+ *      parentwhentargetnotdir : a pointer to the parent when the target isn't
+ *                            a directory vnode
+ *      targetptr           : a pointer to the vnode struct
+ *      parentptr           : a pointer to the parent of this vnode
+ *      volptr              : a pointer to the volume structure
+ *      client              : a pointer to the calling client
+ *      cbv                 : struct containing the RX call for offline cancels
+ *
+ * Returns:
+ *      Nothing
+ *
+ * Environment:
+ *      Nothing interesting.
+ *
+ * Side Effects:
+ *      Enables keepalives on the call.
+ *------------------------------------------------------------------------*/
 static void
-PutVolumePackage(Vnode * parentwhentargetnotdir, Vnode * targetptr,
-                Vnode * parentptr, Volume * volptr, struct client **client)
+PutVolumePackageWithCall(struct rx_call *acall, Vnode *
+                        parentwhentargetnotdir, Vnode * targetptr,
+                         Vnode * parentptr, Volume * volptr,
+                         struct client **client, struct VCallByVol *cbv)
 {
     Error fileCode = 0;                /* Error code returned by the volume package */
 
+    rx_KeepAliveOff(acall);
     if (parentwhentargetnotdir) {
        VPutVnode(&fileCode, parentwhentargetnotdir);
        osi_Assert(!fileCode || (fileCode == VSALVAGE));
@@ -825,13 +934,24 @@ PutVolumePackage(Vnode * parentwhentargetnotdir, Vnode * targetptr,
        osi_Assert(!fileCode || (fileCode == VSALVAGE));
     }
     if (volptr) {
-       VPutVolume(volptr);
+       VPutVolumeWithCall(volptr, cbv);
     }
+    rx_KeepAliveOn(acall);
+
     if (*client) {
        PutClient(client);
     }
 }                              /*PutVolumePackage */
 
+static_inline void
+PutVolumePackage(struct rx_call *acall, Vnode * parentwhentargetnotdir,
+                Vnode * targetptr, Vnode * parentptr, Volume * volptr,
+                struct client **client)
+{
+    PutVolumePackageWithCall(acall, parentwhentargetnotdir, targetptr,
+                            parentptr, volptr, client, NULL);
+}
+
 static int
 VolumeOwner(struct client *client, Vnode * targetptr)
 {
@@ -891,7 +1011,8 @@ Check_PermissionRights(Vnode * targetptr, struct client *client,
            } else {            /* file */
                /* must have read access, or be owner and have insert access */
                if (!(rights & PRSFS_READ)
-                   && !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT)))
+                   && !((OWNSp(client, targetptr) && (rights & PRSFS_INSERT)
+                         && (client->ViceId != AnonymousID))))
                    return (EACCES);
            }
            if (CallingRoutine == CHK_FETCHDATA
@@ -1110,7 +1231,8 @@ RXStore_AccessList(Vnode * targetptr, struct AFSOpaque *AccessList)
 static int
 CopyOnWrite(Vnode * targetptr, Volume * volptr, afs_foff_t off, afs_fsize_t len)
 {
-    Inode ino, nearInode;
+    Inode ino;
+    Inode nearInode AFS_UNUSED;
     ssize_t rdlen;
     ssize_t wrlen;
     afs_fsize_t size;
@@ -1210,7 +1332,7 @@ CopyOnWrite(Vnode * targetptr, Volume * volptr, afs_foff_t off, afs_fsize_t len)
                IH_RELEASE(newH);
                FDH_REALLYCLOSE(targFdP);
                rc = IH_DEC(V_linkHandle(volptr), ino, V_parentId(volptr));
-               if (!rc) {
+               if (rc) {
                    ViceLog(0,
                            ("CopyOnWrite failed: error %u after i_dec on disk full, volume %u in partition %s needs salvage\n",
                             rc, V_id(volptr), volptr->partition->name));
@@ -1242,9 +1364,6 @@ CopyOnWrite(Vnode * targetptr, Volume * volptr, afs_foff_t off, afs_fsize_t len)
                return EIO;
            }
        }
-#ifndef AFS_PTHREAD_ENV
-       IOMGR_Poll();
-#endif /* !AFS_PTHREAD_ENV */
     }
     FDH_REALLYCLOSE(targFdP);
     rc = IH_DEC(V_linkHandle(volptr), VN_GET_INO(targetptr),
@@ -1264,48 +1383,6 @@ CopyOnWrite(Vnode * targetptr, Volume * volptr, afs_foff_t off, afs_fsize_t len)
     return 0;                  /* success */
 }                              /*CopyOnWrite */
 
-static int
-CopyOnWrite2(FdHandle_t *targFdP, FdHandle_t *newFdP, afs_foff_t off,
-             afs_sfsize_t size)
-{
-    char *buff = malloc(COPYBUFFSIZE);
-    size_t length;
-    ssize_t rdlen;
-    ssize_t wrlen;
-    int rc = 0;
-    afs_foff_t done = off;
-
-    if (size > FDH_SIZE(targFdP) - off)
-       size = FDH_SIZE(targFdP) - off;
-
-    while (size > 0) {
-       if (size > COPYBUFFSIZE) {      /* more than a buffer */
-           length = COPYBUFFSIZE;
-           size -= COPYBUFFSIZE;
-       } else {
-           length = size;
-           size = 0;
-       }
-       rdlen = FDH_PREAD(targFdP, buff, length, done);
-       if (rdlen == length) {
-           wrlen = FDH_PWRITE(newFdP, buff, length, done);
-           done += rdlen;
-       }
-       else
-           wrlen = 0;
-
-       if ((rdlen != length) || (wrlen != length)) {
-           /* no error recovery, at the worst we'll have a "hole"
-            * in the file */
-           rc = 1;
-           break;
-       }
-    }
-    free(buff);
-    return rc;
-}
-
-
 /*
  * Common code to handle with removing the Name (file when it's called from
  * SAFS_RemoveFile() or an empty dir when called from SAFS_rmdir()) from a
@@ -1324,6 +1401,12 @@ DeleteTarget(Vnode * parentptr, Volume * volptr, Vnode ** targetptr,
     /* watch for invalid names */
     if (!strcmp(Name, ".") || !strcmp(Name, ".."))
        return (EINVAL);
+
+    if (CheckLength(volptr, parentptr, -1)) {
+       VTakeOffline(volptr);
+       return VSALVAGE;
+    }
+
     if (parentptr->disk.cloned) {
        ViceLog(25, ("DeleteTarget : CopyOnWrite called\n"));
        if ((errorCode = CopyOnWrite(parentptr, volptr, 0, MAXFSIZE))) {
@@ -1336,7 +1419,7 @@ DeleteTarget(Vnode * parentptr, Volume * volptr, Vnode ** targetptr,
 
     /* check that the file is in the directory */
     SetDirHandle(dir, parentptr);
-    if (Lookup(dir, Name, fileFid))
+    if (afs_dir_Lookup(dir, Name, fileFid))
        return (ENOENT);
     fileFid->Volume = V_id(volptr);
 
@@ -1370,9 +1453,9 @@ DeleteTarget(Vnode * parentptr, Volume * volptr, Vnode ** targetptr,
 
     if (ChkForDir == MustBeDIR) {
        SetDirHandle(&childdir, *targetptr);
-       if (IsEmpty(&childdir) != 0)
+       if (afs_dir_IsEmpty(&childdir) != 0)
            return (EEXIST);
-       DZap((afs_int32 *) &childdir);
+       DZap(&childdir);
        FidZap(&childdir);
        (*targetptr)->delete = 1;
     } else if ((--(*targetptr)->disk.linkCount) == 0)
@@ -1412,7 +1495,7 @@ DeleteTarget(Vnode * parentptr, Volume * volptr, Vnode ** targetptr,
 
     (*targetptr)->changed_newTime = 1; /* Status change of deleted file/dir */
 
-    code = Delete(dir, (char *)Name);
+    code = afs_dir_Delete(dir, Name);
     if (code) {
        ViceLog(0,
                ("Error %d deleting %s\n", code,
@@ -1440,23 +1523,17 @@ DeleteTarget(Vnode * parentptr, Volume * volptr, Vnode ** targetptr,
  */
 static void
 Update_ParentVnodeStatus(Vnode * parentptr, Volume * volptr, DirHandle * dir,
-                        int author, int linkcount,
-#if FS_STATS_DETAILED
-                        char a_inSameNetwork
-#endif                         /* FS_STATS_DETAILED */
-    )
+                        int author, int linkcount, char a_inSameNetwork)
 {
     afs_fsize_t newlength;     /* Holds new directory length */
     afs_fsize_t parentLength;
     Error errorCode;
-#if FS_STATS_DETAILED
     Date currDate;             /*Current date */
     int writeIdx;              /*Write index to bump */
     int timeIdx;               /*Authorship time index to bump */
-#endif /* FS_STATS_DETAILED */
 
     parentptr->disk.dataVersion++;
-    newlength = (afs_fsize_t) Length(dir);
+    newlength = (afs_fsize_t) afs_dir_Length(dir);
     /*
      * This is a called on both dir removals (i.e. remove, removedir, rename) but also in dir additions
      * (create, symlink, link, makedir) so we need to check if we have enough space
@@ -1471,7 +1548,6 @@ Update_ParentVnodeStatus(Vnode * parentptr, Volume * volptr, DirHandle * dir,
     }
     VN_SET_LEN(parentptr, newlength);
 
-#if FS_STATS_DETAILED
     /*
      * Update directory write stats for this volume.  Note that the auth
      * counter is located immediately after its associated ``distance''
@@ -1503,7 +1579,6 @@ Update_ParentVnodeStatus(Vnode * parentptr, Volume * volptr, DirHandle * dir,
     } else {
        V_stat_dirDiffAuthor(volptr, timeIdx)++;
     }
-#endif /* FS_STATS_DETAILED */
 
     parentptr->disk.author = author;
     parentptr->disk.linkCount = linkcount;
@@ -1517,6 +1592,8 @@ Update_ParentVnodeStatus(Vnode * parentptr, Volume * volptr, DirHandle * dir,
  * Update the target file's (or dir's) status block after the specified
  * operation is complete. Note that some other fields maybe updated by
  * the individual module.
+ * If remote is set, the volume is a RW replica and access checks can
+ * be skipped.
  */
 
 /* XXX INCOMPLETE - More attention is needed here! */
@@ -1524,13 +1601,11 @@ static void
 Update_TargetVnodeStatus(Vnode * targetptr, afs_uint32 Caller,
                         struct client *client, AFSStoreStatus * InStatus,
                         Vnode * parentptr, Volume * volptr,
-                        afs_fsize_t length)
+                        afs_fsize_t length, int remote)
 {
-#if FS_STATS_DETAILED
     Date currDate;             /*Current date */
     int writeIdx;              /*Write index to bump */
     int timeIdx;               /*Authorship time index to bump */
-#endif /* FS_STATS_DETAILED */
 
     if (Caller & (TVS_CFILE | TVS_SLINK | TVS_MKDIR)) {        /* initialize new file */
        targetptr->disk.parent = parentptr->vnodeNumber;
@@ -1542,7 +1617,6 @@ Update_TargetVnodeStatus(Vnode * targetptr, afs_uint32 Caller,
        targetptr->disk.linkCount = (Caller & TVS_MKDIR ? 2 : 1);
        /* the inode was created in Alloc_NewVnode() */
     }
-#if FS_STATS_DETAILED
     /*
      * Update file write stats for this volume.  Note that the auth
      * counter is located immediately after its associated ``distance''
@@ -1583,13 +1657,12 @@ Update_TargetVnodeStatus(Vnode * targetptr, afs_uint32 Caller,
            V_stat_fileDiffAuthor(volptr, timeIdx)++;
        }
     }
-#endif /* FS_STATS_DETAILED */
 
     if (!(Caller & TVS_SSTATUS))
        targetptr->disk.author = client->ViceId;
     if (Caller & TVS_SDATA) {
        targetptr->disk.dataVersion++;
-       if (VanillaUser(client)) {
+       if (!remote && VanillaUser(client)) {
            targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */
 #ifdef CREATE_SGUID_ADMIN_ONLY
            targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */
@@ -1607,7 +1680,7 @@ Update_TargetVnodeStatus(Vnode * targetptr, afs_uint32 Caller,
     }
     if (InStatus->Mask & AFS_SETOWNER) {
        /* admin is allowed to do chmod, chown as well as chown, chmod. */
-       if (VanillaUser(client)) {
+       if (!remote && VanillaUser(client)) {
            targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */
 #ifdef CREATE_SGUID_ADMIN_ONLY
            targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */
@@ -1625,10 +1698,10 @@ Update_TargetVnodeStatus(Vnode * targetptr, afs_uint32 Caller,
        int modebits = InStatus->UnixModeBits;
 #define        CREATE_SGUID_ADMIN_ONLY 1
 #ifdef CREATE_SGUID_ADMIN_ONLY
-       if (VanillaUser(client))
+       if (!remote && VanillaUser(client))
            modebits = modebits & 0777;
 #endif
-       if (VanillaUser(client)) {
+       if (!remote && VanillaUser(client)) {
            targetptr->disk.modeBits = modebits;
        } else {
            targetptr->disk.modeBits = modebits;
@@ -1723,19 +1796,25 @@ Alloc_NewVnode(Vnode * parentptr, DirHandle * dir, Volume * volptr,
     Error errorCode = 0;               /* Error code returned back */
     Error temp;
     Inode inode = 0;
-    Inode nearInode;           /* hint for inode allocation in solaris */
+    Inode nearInode AFS_UNUSED;         /* hint for inode allocation in solaris */
     afs_ino_str_t stmp;
 
     if ((errorCode =
         AdjustDiskUsage(volptr, BlocksPreallocatedForVnode,
                         BlocksPreallocatedForVnode))) {
        ViceLog(25,
-               ("Insufficient space to allocate %" AFS_INT64_FMT " blocks\n",
+               ("Insufficient space to allocate %lld blocks\n",
                 (afs_intmax_t) BlocksPreallocatedForVnode));
        return (errorCode);
     }
 
-    *targetptr = VAllocVnode(&errorCode, volptr, FileType);
+    if (CheckLength(volptr, parentptr, -1)) {
+       VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
+       VTakeOffline(volptr);
+       return VSALVAGE;
+    }
+
+    *targetptr = VAllocVnode(&errorCode, volptr, FileType, 0, 0);
     if (errorCode != 0) {
        VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
        return (errorCode);
@@ -1789,7 +1868,7 @@ Alloc_NewVnode(Vnode * parentptr, DirHandle * dir, Volume * volptr,
 
     /* add the name to the directory */
     SetDirHandle(dir, parentptr);
-    if ((errorCode = Create(dir, (char *)Name, OutFid))) {
+    if ((errorCode = afs_dir_Create(dir, Name, OutFid))) {
        (*targetptr)->delete = 1;
        VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
        IH_REALLYCLOSE((*targetptr)->handle);
@@ -1903,16 +1982,10 @@ RXUpdate_VolumeStatus(Volume * volptr, AFSStoreVolumeStatus * StoreVolStatus,
     if (strlen(Name) > 0) {
        strcpy(V_name(volptr), Name);
     }
-#if OPENAFS_VOL_STATS
     /*
      * We don't overwrite the motd field, since it's now being used
      * for stats
      */
-#else
-    if (strlen(Motd) > 0) {
-       strcpy(V_motd(volptr), Motd);
-    }
-#endif /* FS_STATS_DETAILED */
     VUpdateVolume(&errorCode, volptr);
     return (errorCode);
 
@@ -1938,40 +2011,27 @@ RXGetVolumeStatus(AFSFetchVolumeStatus * status, char **name, char **offMsg,
     status->MinQuota = V_minquota(volptr);
     status->MaxQuota = V_maxquota(volptr);
     status->BlocksInUse = V_diskused(volptr);
-    status->PartBlocksAvail = RoundInt64ToInt32(volptr->partition->free);
-    status->PartMaxBlocks = RoundInt64ToInt32(volptr->partition->totalUsable);
+    status->PartBlocksAvail = RoundInt64ToInt31(volptr->partition->free);
+    status->PartMaxBlocks = RoundInt64ToInt31(volptr->partition->totalUsable);
 
     /* now allocate and copy these things; they're freed by the RXGEN stub */
     temp = strlen(V_name(volptr)) + 1;
     *name = malloc(temp);
     if (!*name) {
-       ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
-       osi_Panic("Failed malloc in RXGetVolumeStatus\n");
+       ViceLogThenPanic(0, ("Failed malloc in RXGetVolumeStatus\n"));
     }
     strcpy(*name, V_name(volptr));
     temp = strlen(V_offlineMessage(volptr)) + 1;
     *offMsg = malloc(temp);
     if (!*offMsg) {
-       ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
-       osi_Panic("Failed malloc in RXGetVolumeStatus\n");
+       ViceLogThenPanic(0, ("Failed malloc in RXGetVolumeStatus\n"));
     }
     strcpy(*offMsg, V_offlineMessage(volptr));
-#if OPENAFS_VOL_STATS
     *motd = malloc(1);
     if (!*motd) {
-       ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
-       osi_Panic("Failed malloc in RXGetVolumeStatus\n");
+       ViceLogThenPanic(0, ("Failed malloc in RXGetVolumeStatus\n"));
     }
     strcpy(*motd, nullString);
-#else
-    temp = strlen(V_motd(volptr)) + 1;
-    *motd = malloc(temp);
-    if (!*motd) {
-       ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
-       osi_Panic("Failed malloc in RXGetVolumeStatus\n");
-    }
-    strcpy(*motd, V_motd(volptr));
-#endif /* FS_STATS_DETAILED */
     return 0;
 }                              /*RXGetVolumeStatus */
 
@@ -2057,8 +2117,7 @@ AllocSendBuffer(void)
        FS_UNLOCK;
        tmp = malloc(sendBufSize);
        if (!tmp) {
-           ViceLog(0, ("Failed malloc in AllocSendBuffer\n"));
-           osi_Panic("Failed malloc in AllocSendBuffer\n");
+           ViceLogThenPanic(0, ("Failed malloc in AllocSendBuffer\n"));
        }
        return tmp;
     }
@@ -2080,6 +2139,8 @@ static
 GetStatus(Vnode * targetptr, AFSFetchStatus * status, afs_int32 rights,
          afs_int32 anyrights, Vnode * parentptr)
 {
+    int Time =FT_ApproxTime();
+
     /* initialize return status from a vnode  */
     status->InterfaceVersion = 1;
     status->SyncCounter = status->dataVersionHigh = status->lockCount =
@@ -2114,13 +2175,12 @@ GetStatus(Vnode * targetptr, AFSFetchStatus * status, afs_int32 rights,
         Directory ? targetptr->disk.uniquifier : parentptr->disk.uniquifier);
     status->ServerModTime = targetptr->disk.serverModifyTime;
     status->Group = targetptr->disk.group;
-    status->lockCount = targetptr->disk.lock.lockCount;
+    status->lockCount = Time > targetptr->disk.lock.lockTime ? 0 : targetptr->disk.lock.lockCount;
     status->errorCode = 0;
 
 }                              /*GetStatus */
 
-static
-  afs_int32
+static afs_int32
 common_FetchData64(struct rx_call *acall, struct AFSFid *Fid,
                   afs_sfsize_t Pos, afs_sfsize_t Len,
                   struct AFSFetchStatus *OutStatus,
@@ -2139,28 +2199,14 @@ common_FetchData64(struct rx_call *acall, struct AFSFid *Fid,
     afs_int32 rights, anyrights;       /* rights for this and any user */
     struct client *t_client = NULL;    /* tmp ptr to client data */
     struct in_addr logHostAddr;        /* host ip holder for inet_ntoa */
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct fs_stats_xferData *xferP;   /* Ptr to this op's byte size struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval xferStartTime, xferStopTime;        /* Start/stop times for xfer portion */
-    struct timeval elapsedTime;        /* Transfer time */
-    afs_sfsize_t bytesToXfer;  /* # bytes to xfer */
-    afs_sfsize_t bytesXferred; /* # bytes actually xferred */
+    struct VCallByVol tcbv, *cbv = NULL;
+    static int remainder = 0;  /* shared access protected by FS_LOCK */
+    struct fsstats fsstats;
+    afs_sfsize_t bytesToXfer;  /* # bytes to xfer */
+    afs_sfsize_t bytesXferred; /* # bytes actually xferred */
     int readIdx;               /* Index of read stats array to bump */
-    static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
 
-    /*
-     * Set our stats pointers, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHDATA]);
-    xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_FETCHDATA]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_FETCHDATA);
 
     ViceLog(1,
            ("SRXAFS_FetchData, Fid = %u.%u.%u\n", Fid->Volume, Fid->Vnode,
@@ -2178,19 +2224,23 @@ common_FetchData64(struct rx_call *acall, struct AFSFid *Fid,
            ("SRXAFS_FetchData, Fid = %u.%u.%u, Host %s:%d, Id %d\n",
             Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
             ntohs(rxr_PortOf(tcon)), t_client->ViceId));
+
+    queue_NodeInit(&tcbv);
+    tcbv.call = acall;
+    cbv = &tcbv;
+
     /*
      * Get volume/vnode for the fetched file; caller's access rights to
      * it are also returned
      */
     if ((errorCode =
-        GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
+        GetVolumePackageWithCall(acall, cbv, Fid, &volptr, &targetptr, DONTCHECK,
                          &parentwhentargetnotdir, &client, READ_LOCK,
-                         &rights, &anyrights)))
+                         &rights, &anyrights, 0)))
        goto Bad_FetchData;
 
     SetVolumeSync(Sync, volptr);
 
-#if FS_STATS_DETAILED
     /*
      * Remember that another read operation was performed.
      */
@@ -2204,7 +2254,6 @@ common_FetchData64(struct rx_call *acall, struct AFSFid *Fid,
        V_stat_reads(volptr, readIdx + 1)++;
     }
     FS_UNLOCK;
-#endif /* FS_STATS_DETAILED */
     /* Check whether the caller has permission access to fetch the data */
     if ((errorCode =
         Check_PermissionRights(targetptr, client, rights, CHK_FETCHDATA, 0)))
@@ -2220,95 +2269,26 @@ common_FetchData64(struct rx_call *acall, struct AFSFid *Fid,
        osi_Assert(!fileCode || (fileCode == VSALVAGE));
        parentwhentargetnotdir = NULL;
     }
-#if FS_STATS_DETAILED
-    /*
-     * Remember when the data transfer started.
-     */
-    FT_GetTimeOfDay(&xferStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+
+    fsstats_StartXfer(&fsstats, FS_STATS_XFERIDX_FETCHDATA);
 
     /* actually do the data transfer */
-#if FS_STATS_DETAILED
     errorCode =
        FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type,
                          &bytesToXfer, &bytesXferred);
-#else
-    if ((errorCode =
-        FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type)))
-       goto Bad_FetchData;
-#endif /* FS_STATS_DETAILED */
-
-#if FS_STATS_DETAILED
-    /*
-     * At this point, the data transfer is done, for good or ill.  Remember
-     * when the transfer ended, bump the number of successes/failures, and
-     * integrate the transfer size and elapsed time into the stats.  If the
-     * operation failed, we jump to the appropriate point.
-     */
-    FT_GetTimeOfDay(&xferStopTime, 0);
-    FS_LOCK;
-    (xferP->numXfers)++;
-    if (!errorCode) {
-       (xferP->numSuccesses)++;
-
-       /*
-        * Bump the xfer sum by the number of bytes actually sent, NOT the
-        * target number.
-        */
-       tot_bytesXferred += bytesXferred;
-       (xferP->sumBytes) += (tot_bytesXferred >> 10);
-       tot_bytesXferred &= 0x3FF;
-       if (bytesXferred < xferP->minBytes)
-           xferP->minBytes = bytesXferred;
-       if (bytesXferred > xferP->maxBytes)
-           xferP->maxBytes = bytesXferred;
 
-       /*
-        * Tally the size of the object.  Note: we tally the actual size,
-        * NOT the number of bytes that made it out over the wire.
-        */
-       if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
-           (xferP->count[0])++;
-       else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
-           (xferP->count[1])++;
-       else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
-           (xferP->count[2])++;
-       else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
-           (xferP->count[3])++;
-       else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
-           (xferP->count[4])++;
-       else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
-           (xferP->count[5])++;
-       else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
-           (xferP->count[6])++;
-       else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
-           (xferP->count[7])++;
-       else
-           (xferP->count[8])++;
+    fsstats_FinishXfer(&fsstats, errorCode, bytesToXfer, bytesXferred,
+                      &remainder);
 
-       fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
-       fs_stats_AddTo((xferP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
-           fs_stats_TimeAssign((xferP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
-           fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
-       }
-    }
-    FS_UNLOCK;
-    /*
-     * Finally, go off to tell our caller the bad news in case the
-     * fetch failed.
-     */
     if (errorCode)
        goto Bad_FetchData;
-#endif /* FS_STATS_DETAILED */
 
     /* write back  the OutStatus from the target vnode  */
     GetStatus(targetptr, OutStatus, rights, anyrights,
              &tparentwhentargetnotdir);
 
+    rx_KeepAliveOn(acall); /* I/O done */
+
     /* if a r/w volume, promise a callback to the caller */
     if (VolumeWriteable(volptr))
        SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
@@ -2321,28 +2301,12 @@ common_FetchData64(struct rx_call *acall, struct AFSFid *Fid,
 
   Bad_FetchData:
     /* Update and store volume/vnode and parent vnodes back */
-    (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
-                          volptr, &client);
+    (void)PutVolumePackageWithCall(acall, parentwhentargetnotdir, targetptr,
+                                   (Vnode *) 0, volptr, &client, cbv);
     ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode));
     errorCode = CallPostamble(tcon, errorCode, thost);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (errorCode == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, errorCode);
 
     osi_auditU(acall, FetchDataEvent, errorCode,
                AUD_ID, t_client ? t_client->ViceId : 0,
@@ -2392,21 +2356,9 @@ SRXAFS_FetchACL(struct rx_call * acall, struct AFSFid * Fid,
     struct host *thost;
     struct client *t_client = NULL;    /* tmp ptr to client data */
     struct in_addr logHostAddr;        /* host ip holder for inet_ntoa */
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHACL]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_FETCHACL);
 
     ViceLog(1,
            ("SAFS_FetchACL, Fid = %u.%u.%u\n", Fid->Volume, Fid->Vnode,
@@ -2428,8 +2380,7 @@ SRXAFS_FetchACL(struct rx_call * acall, struct AFSFid * Fid,
     AccessList->AFSOpaque_len = 0;
     AccessList->AFSOpaque_val = malloc(AFSOPAQUEMAX);
     if (!AccessList->AFSOpaque_val) {
-       ViceLog(0, ("Failed malloc in SRXAFS_FetchACL\n"));
-       osi_Panic("Failed malloc in SRXAFS_FetchACL\n");
+       ViceLogThenPanic(0, ("Failed malloc in SRXAFS_FetchACL\n"));
     }
 
     /*
@@ -2437,7 +2388,7 @@ SRXAFS_FetchACL(struct rx_call * acall, struct AFSFid * Fid,
      * are also returned
      */
     if ((errorCode =
-        GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
+        GetVolumePackage(acall, Fid, &volptr, &targetptr, DONTCHECK,
                          &parentwhentargetnotdir, &client, READ_LOCK,
                          &rights, &anyrights)))
        goto Bad_FetchACL;
@@ -2460,30 +2411,14 @@ SRXAFS_FetchACL(struct rx_call * acall, struct AFSFid * Fid,
 
   Bad_FetchACL:
     /* Update and store volume/vnode and parent vnodes back */
-    (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
-                          volptr, &client);
+    (void)PutVolumePackage(acall, parentwhentargetnotdir, targetptr,
+                          (Vnode *) 0, volptr, &client);
     ViceLog(2,
            ("SAFS_FetchACL returns %d (ACL=%s)\n", errorCode,
             AccessList->AFSOpaque_val));
     errorCode = CallPostamble(tcon, errorCode, thost);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (errorCode == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, errorCode);
 
     osi_auditU(acall, FetchACLEvent, errorCode,
                AUD_ID, t_client ? t_client->ViceId : 0,
@@ -2497,8 +2432,7 @@ SRXAFS_FetchACL(struct rx_call * acall, struct AFSFid * Fid,
  * This routine is called exclusively by SRXAFS_FetchStatus(), and should be
  * merged into it when possible.
  */
-static
-  afs_int32
+static afs_int32
 SAFSS_FetchStatus(struct rx_call *acall, struct AFSFid *Fid,
                  struct AFSFetchStatus *OutStatus,
                  struct AFSCallBack *CallBack, struct AFSVolSync *Sync)
@@ -2528,11 +2462,13 @@ SAFSS_FetchStatus(struct rx_call *acall, struct AFSFid *Fid,
      * also returned
      */
     if ((errorCode =
-        GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
+        GetVolumePackage(acall, Fid, &volptr, &targetptr, DONTCHECK,
                          &parentwhentargetnotdir, &client, READ_LOCK,
                          &rights, &anyrights)))
        goto Bad_FetchStatus;
 
+    rx_KeepAliveOn(acall);
+
     /* set volume synchronization information */
     SetVolumeSync(Sync, volptr);
 
@@ -2563,8 +2499,8 @@ SAFSS_FetchStatus(struct rx_call *acall, struct AFSFid *Fid,
 
   Bad_FetchStatus:
     /* Update and store volume/vnode and parent vnodes back */
-    (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
-                          volptr, &client);
+    (void)PutVolumePackage(acall, parentwhentargetnotdir, targetptr,
+                          (Vnode *) 0, volptr, &client);
     ViceLog(2, ("SAFS_FetchStatus returns %d\n", errorCode));
     return errorCode;
 
@@ -2588,21 +2524,9 @@ SRXAFS_BulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
     struct rx_connection *tcon = rx_ConnectionOf(acall);
     struct host *thost;
     struct client *t_client = NULL;     /* tmp pointer to the client data */
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_BULKSTATUS);
 
     ViceLog(1, ("SAFS_BulkStatus\n"));
     FS_LOCK;
@@ -2618,15 +2542,13 @@ SRXAFS_BulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
        malloc(nfiles * sizeof(struct AFSFetchStatus));
     if (!OutStats->AFSBulkStats_val) {
-       ViceLog(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
-       osi_Panic("Failed malloc in SRXAFS_BulkStatus\n");
+       ViceLogThenPanic(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
     }
     OutStats->AFSBulkStats_len = nfiles;
     CallBacks->AFSCBs_val = (struct AFSCallBack *)
        malloc(nfiles * sizeof(struct AFSCallBack));
     if (!CallBacks->AFSCBs_val) {
-       ViceLog(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
-       osi_Panic("Failed malloc in SRXAFS_BulkStatus\n");
+       ViceLogThenPanic(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
     }
     CallBacks->AFSCBs_len = nfiles;
 
@@ -2640,10 +2562,13 @@ SRXAFS_BulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
         * are also returned
         */
        if ((errorCode =
-            GetVolumePackage(tcon, tfid, &volptr, &targetptr, DONTCHECK,
+            GetVolumePackage(acall, tfid, &volptr, &targetptr, DONTCHECK,
                              &parentwhentargetnotdir, &client, READ_LOCK,
                              &rights, &anyrights)))
            goto Bad_BulkStatus;
+
+       rx_KeepAliveOn(acall);
+
        /* set volume synchronization information, but only once per call */
        if (i == 0)
            SetVolumeSync(Sync, volptr);
@@ -2676,8 +2601,8 @@ SRXAFS_BulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
        }
 
        /* put back the file ID and volume */
-       (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
-                              volptr, &client);
+       (void)PutVolumePackage(acall, parentwhentargetnotdir, targetptr,
+                              (Vnode *) 0, volptr, &client);
        parentwhentargetnotdir = (Vnode *) 0;
        targetptr = (Vnode *) 0;
        volptr = (Volume *) 0;
@@ -2686,29 +2611,13 @@ SRXAFS_BulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
 
   Bad_BulkStatus:
     /* Update and store volume/vnode and parent vnodes back */
-    (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
-                          volptr, &client);
+    (void)PutVolumePackage(acall, parentwhentargetnotdir, targetptr,
+                          (Vnode *) 0, volptr, &client);
     errorCode = CallPostamble(tcon, errorCode, thost);
 
     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (errorCode == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, errorCode);
 
   Audit_and_Return:
     ViceLog(2, ("SAFS_BulkStatus       returns %d\n", errorCode));
@@ -2739,21 +2648,9 @@ SRXAFS_InlineBulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
     struct client *t_client = NULL;    /* tmp ptr to client data */
     AFSFetchStatus *tstatus;
     int VolSync_set = 0;
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_BULKSTATUS);
 
     ViceLog(1, ("SAFS_InlineBulkStatus\n"));
     FS_LOCK;
@@ -2769,15 +2666,13 @@ SRXAFS_InlineBulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
        malloc(nfiles * sizeof(struct AFSFetchStatus));
     if (!OutStats->AFSBulkStats_val) {
-       ViceLog(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
-       osi_Panic("Failed malloc in SRXAFS_FetchStatus\n");
+       ViceLogThenPanic(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
     }
     OutStats->AFSBulkStats_len = nfiles;
     CallBacks->AFSCBs_val = (struct AFSCallBack *)
        malloc(nfiles * sizeof(struct AFSCallBack));
     if (!CallBacks->AFSCBs_val) {
-       ViceLog(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
-       osi_Panic("Failed malloc in SRXAFS_FetchStatus\n");
+       ViceLogThenPanic(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
     }
     CallBacks->AFSCBs_len = nfiles;
 
@@ -2797,13 +2692,19 @@ SRXAFS_InlineBulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
         * are also returned
         */
        if ((errorCode =
-            GetVolumePackage(tcon, tfid, &volptr, &targetptr, DONTCHECK,
+            GetVolumePackage(acall, tfid, &volptr, &targetptr, DONTCHECK,
                              &parentwhentargetnotdir, &client, READ_LOCK,
                              &rights, &anyrights))) {
            tstatus = &OutStats->AFSBulkStats_val[i];
-           tstatus->errorCode = errorCode;
-           PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
-                            volptr, &client);
+
+           if (thost->hostFlags & HERRORTRANS) {
+               tstatus->errorCode = sys_error_to_et(errorCode);
+           } else {
+               tstatus->errorCode = errorCode;
+           }
+
+           PutVolumePackage(acall, parentwhentargetnotdir, targetptr,
+                            (Vnode *) 0, volptr, &client);
            parentwhentargetnotdir = (Vnode *) 0;
            targetptr = (Vnode *) 0;
            volptr = (Volume *) 0;
@@ -2811,6 +2712,8 @@ SRXAFS_InlineBulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
            continue;
        }
 
+       rx_KeepAliveOn(acall);
+
        /* set volume synchronization information, but only once per call */
        if (!VolSync_set) {
            SetVolumeSync(Sync, volptr);
@@ -2823,9 +2726,16 @@ SRXAFS_InlineBulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
                 Check_PermissionRights(targetptr, client, rights,
                                        CHK_FETCHSTATUS, 0))) {
                tstatus = &OutStats->AFSBulkStats_val[i];
-               tstatus->errorCode = errorCode;
-               (void)PutVolumePackage(parentwhentargetnotdir, targetptr,
-                                      (Vnode *) 0, volptr, &client);
+
+               if (thost->hostFlags & HERRORTRANS) {
+                   tstatus->errorCode = sys_error_to_et(errorCode);
+               } else {
+                   tstatus->errorCode = errorCode;
+               }
+
+               (void)PutVolumePackage(acall, parentwhentargetnotdir,
+                                      targetptr, (Vnode *) 0, volptr,
+                                      &client);
                parentwhentargetnotdir = (Vnode *) 0;
                targetptr = (Vnode *) 0;
                volptr = (Volume *) 0;
@@ -2852,46 +2762,31 @@ SRXAFS_InlineBulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
        }
 
        /* put back the file ID and volume */
-       (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
-                              volptr, &client);
+       (void)PutVolumePackage(acall, parentwhentargetnotdir, targetptr,
+                              (Vnode *) 0, volptr, &client);
        parentwhentargetnotdir = (Vnode *) 0;
        targetptr = (Vnode *) 0;
        volptr = (Volume *) 0;
        client = (struct client *)0;
     }
+    errorCode = 0;
 
   Bad_InlineBulkStatus:
     /* Update and store volume/vnode and parent vnodes back */
-    (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
-                          volptr, &client);
+    (void)PutVolumePackage(acall, parentwhentargetnotdir, targetptr,
+                          (Vnode *) 0, volptr, &client);
     errorCode = CallPostamble(tcon, errorCode, thost);
 
     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (errorCode == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, errorCode);
 
   Audit_and_Return:
     ViceLog(2, ("SAFS_InlineBulkStatus returns %d\n", errorCode));
     osi_auditU(acall, InlineBulkFetchStatusEvent, errorCode,
                AUD_ID, t_client ? t_client->ViceId : 0,
                AUD_FIDS, Fids, AUD_END);
-    return 0;
+    return errorCode;
 
 }                              /*SRXAFS_InlineBulkStatus */
 
@@ -2905,21 +2800,9 @@ SRXAFS_FetchStatus(struct rx_call * acall, struct AFSFid * Fid,
     struct rx_connection *tcon;
     struct host *thost;
     struct client *t_client = NULL;    /* tmp ptr to client data */
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHSTATUS]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_FETCHSTATUS);
 
     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
        goto Bad_FetchStatus;
@@ -2931,23 +2814,7 @@ SRXAFS_FetchStatus(struct rx_call * acall, struct AFSFid * Fid,
 
     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (code == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, code);
 
     osi_auditU(acall, FetchStatusEvent, code,
                AUD_ID, t_client ? t_client->ViceId : 0,
@@ -2975,30 +2842,16 @@ common_StoreData64(struct rx_call *acall, struct AFSFid *Fid,
     struct in_addr logHostAddr;        /* host ip holder for inet_ntoa */
     struct rx_connection *tcon;
     struct host *thost;
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct fs_stats_xferData *xferP;   /* Ptr to this op's byte size struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval xferStartTime, xferStopTime;        /* Start/stop times for xfer portion */
-    struct timeval elapsedTime;        /* Transfer time */
-    afs_sfsize_t bytesToXfer;  /* # bytes to xfer */
-    afs_sfsize_t bytesXferred; /* # bytes actually xfer */
-    static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
+    struct fsstats fsstats;
+    afs_sfsize_t bytesToXfer;
+    afs_sfsize_t bytesXferred;
+    static int remainder = 0;
 
-    /*
-     * Set our stats pointers, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREDATA]);
-    xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_STOREDATA]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
     ViceLog(1,
            ("StoreData: Fid = %u.%u.%u\n", Fid->Volume, Fid->Vnode,
             Fid->Unique));
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_STOREDATA);
 
     FS_LOCK;
     AFSCallStats.StoreData++, AFSCallStats.TotalCalls++;
@@ -3019,16 +2872,18 @@ common_StoreData64(struct rx_call *acall, struct AFSFid *Fid,
      * are also returned
      */
     if ((errorCode =
-        GetVolumePackage(tcon, Fid, &volptr, &targetptr, MustNOTBeDIR,
+        GetVolumePackage(acall, Fid, &volptr, &targetptr, MustNOTBeDIR,
                          &parentwhentargetnotdir, &client, WRITE_LOCK,
                          &rights, &anyrights))) {
        goto Bad_StoreData;
     }
 
+    rx_KeepAliveOn(acall);
+
     /* set volume synchronization information */
     SetVolumeSync(Sync, volptr);
 
-    if ((targetptr->disk.type == vSymlink)) {
+    if (targetptr->disk.type == vSymlink) {
        /* Should we return a better error code here??? */
        errorCode = EISDIR;
        goto Bad_StoreData;
@@ -3047,100 +2902,31 @@ common_StoreData64(struct rx_call *acall, struct AFSFid *Fid,
      */
     if (parentwhentargetnotdir != NULL) {
        tparentwhentargetnotdir = *parentwhentargetnotdir;
+       rx_KeepAliveOff(acall);
        VPutVnode(&fileCode, parentwhentargetnotdir);
+       rx_KeepAliveOn(acall);
        osi_Assert(!fileCode || (fileCode == VSALVAGE));
        parentwhentargetnotdir = NULL;
     }
-#if FS_STATS_DETAILED
-    /*
-     * Remember when the data transfer started.
-     */
-    FT_GetTimeOfDay(&xferStartTime, 0);
-#endif /* FS_STATS_DETAILED */
 
-    /* Do the actual storing of the data */
-#if FS_STATS_DETAILED
+    fsstats_StartXfer(&fsstats, FS_STATS_XFERIDX_STOREDATA);
+
     errorCode =
        StoreData_RXStyle(volptr, targetptr, Fid, client, acall, Pos, Length,
                          FileLength, (InStatus->Mask & AFS_FSYNC),
                          &bytesToXfer, &bytesXferred);
-#else
-    errorCode =
-       StoreData_RXStyle(volptr, targetptr, Fid, client, acall, Pos, Length,
-                         FileLength, (InStatus->Mask & AFS_FSYNC));
-    if (errorCode && (!targetptr->changed_newTime))
-       goto Bad_StoreData;
-#endif /* FS_STATS_DETAILED */
-#if FS_STATS_DETAILED
-    /*
-     * At this point, the data transfer is done, for good or ill.  Remember
-     * when the transfer ended, bump the number of successes/failures, and
-     * integrate the transfer size and elapsed time into the stats.  If the
-     * operation failed, we jump to the appropriate point.
-     */
-    FT_GetTimeOfDay(&xferStopTime, 0);
-    FS_LOCK;
-    (xferP->numXfers)++;
-    if (!errorCode) {
-       (xferP->numSuccesses)++;
 
-       /*
-        * Bump the xfer sum by the number of bytes actually sent, NOT the
-        * target number.
-        */
-       tot_bytesXferred += bytesXferred;
-       (xferP->sumBytes) += (tot_bytesXferred >> 10);
-       tot_bytesXferred &= 0x3FF;
-       if (bytesXferred < xferP->minBytes)
-           xferP->minBytes = bytesXferred;
-       if (bytesXferred > xferP->maxBytes)
-           xferP->maxBytes = bytesXferred;
+    fsstats_FinishXfer(&fsstats, errorCode, bytesToXfer, bytesXferred,
+                      &remainder);
 
-       /*
-        * Tally the size of the object.  Note: we tally the actual size,
-        * NOT the number of bytes that made it out over the wire.
-        */
-       if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
-           (xferP->count[0])++;
-       else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
-           (xferP->count[1])++;
-       else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
-           (xferP->count[2])++;
-       else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
-           (xferP->count[3])++;
-       else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
-           (xferP->count[4])++;
-       else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
-           (xferP->count[5])++;
-       else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
-           (xferP->count[6])++;
-       else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
-           (xferP->count[7])++;
-       else
-           (xferP->count[8])++;
-
-       fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
-       fs_stats_AddTo((xferP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
-           fs_stats_TimeAssign((xferP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
-           fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
-       }
-    }
-    FS_UNLOCK;
-    /*
-     * Finally, go off to tell our caller the bad news in case the
-     * store failed.
-     */
     if (errorCode && (!targetptr->changed_newTime))
        goto Bad_StoreData;
-#endif /* FS_STATS_DETAILED */
 
+    rx_KeepAliveOff(acall);
     /* Update the status of the target's vnode */
     Update_TargetVnodeStatus(targetptr, TVS_SDATA, client, InStatus,
-                            targetptr, volptr, 0);
+                            targetptr, volptr, 0, 0);
+    rx_KeepAliveOn(acall);
 
     /* Get the updated File's status back to the caller */
     GetStatus(targetptr, OutStatus, rights, anyrights,
@@ -3148,29 +2934,14 @@ common_StoreData64(struct rx_call *acall, struct AFSFid *Fid,
 
   Bad_StoreData:
     /* Update and store volume/vnode and parent vnodes back */
-    (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
-                          volptr, &client);
+    (void)PutVolumePackage(acall, parentwhentargetnotdir, targetptr,
+                          (Vnode *) 0, volptr, &client);
     ViceLog(2, ("SAFS_StoreData        returns %d\n", errorCode));
 
     errorCode = CallPostamble(tcon, errorCode, thost);
-
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (errorCode == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+
+    fsstats_FinishOp(&fsstats, errorCode);
+
     osi_auditU(acall, StoreDataEvent, errorCode,
                AUD_ID, t_client ? t_client->ViceId : 0,
                AUD_FID, Fid, AUD_END);
@@ -3229,21 +3000,10 @@ SRXAFS_StoreACL(struct rx_call * acall, struct AFSFid * Fid,
     struct host *thost;
     struct client *t_client = NULL;    /* tmp ptr to client data */
     struct in_addr logHostAddr;        /* host ip holder for inet_ntoa */
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
+
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_STOREACL);
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREACL]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
        goto Bad_StoreACL;
 
@@ -3264,7 +3024,7 @@ SRXAFS_StoreACL(struct rx_call * acall, struct AFSFid * Fid,
      * are also returned.
      */
     if ((errorCode =
-        GetVolumePackage(tcon, Fid, &volptr, &targetptr, MustBeDIR,
+        GetVolumePackage(acall, Fid, &volptr, &targetptr, MustBeDIR,
                          &parentwhentargetnotdir, &client, WRITE_LOCK,
                          &rights, &anyrights))) {
        goto Bad_StoreACL;
@@ -3291,6 +3051,8 @@ SRXAFS_StoreACL(struct rx_call * acall, struct AFSFid * Fid,
     VVnodeWriteToRead(&errorCode, targetptr);
     osi_Assert(!errorCode || errorCode == VSALVAGE);
 
+    rx_KeepAliveOn(acall);
+
     /* break call backs on the directory  */
     BreakCallBack(client->host, Fid, 0);
 
@@ -3299,28 +3061,12 @@ SRXAFS_StoreACL(struct rx_call * acall, struct AFSFid * Fid,
 
   Bad_StoreACL:
     /* Update and store volume/vnode and parent vnodes back */
-    PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
+    PutVolumePackage(acall, parentwhentargetnotdir, targetptr, (Vnode *) 0,
                     volptr, &client);
     ViceLog(2, ("SAFS_StoreACL returns %d\n", errorCode));
     errorCode = CallPostamble(tcon, errorCode, thost);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (errorCode == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, errorCode);
 
     osi_auditU(acall, StoreACLEvent, errorCode,
                AUD_ID, t_client ? t_client->ViceId : 0,
@@ -3364,7 +3110,7 @@ SAFSS_StoreStatus(struct rx_call *acall, struct AFSFid *Fid,
      * also returned
      */
     if ((errorCode =
-        GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
+        GetVolumePackage(acall, Fid, &volptr, &targetptr, DONTCHECK,
                          &parentwhentargetnotdir, &client, WRITE_LOCK,
                          &rights, &anyrights))) {
        goto Bad_StoreStatus;
@@ -3391,7 +3137,9 @@ SAFSS_StoreStatus(struct rx_call *acall, struct AFSFid *Fid,
     /* Update the status of the target's vnode */
     Update_TargetVnodeStatus(targetptr, TVS_SSTATUS, client, InStatus,
                             (parentwhentargetnotdir ? parentwhentargetnotdir
-                             : targetptr), volptr, 0);
+                             : targetptr), volptr, 0, 0);
+
+    rx_KeepAliveOn(acall);
 
     /* convert the write lock to a read lock before breaking callbacks */
     VVnodeWriteToRead(&errorCode, targetptr);
@@ -3406,7 +3154,7 @@ SAFSS_StoreStatus(struct rx_call *acall, struct AFSFid *Fid,
 
   Bad_StoreStatus:
     /* Update and store volume/vnode and parent vnodes back */
-    PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
+    PutVolumePackage(acall, parentwhentargetnotdir, targetptr, (Vnode *) 0,
                     volptr, &client);
     ViceLog(2, ("SAFS_StoreStatus returns %d\n", errorCode));
     return errorCode;
@@ -3424,21 +3172,9 @@ SRXAFS_StoreStatus(struct rx_call * acall, struct AFSFid * Fid,
     struct rx_connection *tcon;
     struct host *thost;
     struct client *t_client = NULL;    /* tmp ptr to client data */
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STORESTATUS]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_STORESTATUS);
 
     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
        goto Bad_StoreStatus;
@@ -3450,23 +3186,7 @@ SRXAFS_StoreStatus(struct rx_call * acall, struct AFSFid * Fid,
 
     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (code == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, code);
 
     osi_auditU(acall, StoreStatusEvent, code,
                AUD_ID, t_client ? t_client->ViceId : 0,
@@ -3513,7 +3233,7 @@ SAFSS_RemoveFile(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
      * also returned
      */
     if ((errorCode =
-        GetVolumePackage(tcon, DirFid, &volptr, &parentptr, MustBeDIR,
+        GetVolumePackage(acall, DirFid, &volptr, &parentptr, MustBeDIR,
                          &parentwhentargetnotdir, &client, WRITE_LOCK,
                          &rights, &anyrights))) {
        goto Bad_RemoveFile;
@@ -3534,14 +3254,11 @@ SAFSS_RemoveFile(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
     }
 
     /* Update the vnode status of the parent dir */
-#if FS_STATS_DETAILED
     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
                             parentptr->disk.linkCount,
                             client->InSameNetwork);
-#else
-    Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
-                            parentptr->disk.linkCount);
-#endif /* FS_STATS_DETAILED */
+
+    rx_KeepAliveOn(acall);
 
     /* Return the updated parent dir's status back to caller */
     GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
@@ -3569,7 +3286,7 @@ SAFSS_RemoveFile(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
 
   Bad_RemoveFile:
     /* Update and store volume/vnode and parent vnodes back */
-    PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr,
+    PutVolumePackage(acall, parentwhentargetnotdir, targetptr, parentptr,
                     volptr, &client);
     FidZap(&dir);
     ViceLog(2, ("SAFS_RemoveFile returns %d\n", errorCode));
@@ -3587,21 +3304,9 @@ SRXAFS_RemoveFile(struct rx_call * acall, struct AFSFid * DirFid, char *Name,
     struct rx_connection *tcon;
     struct host *thost;
     struct client *t_client = NULL;    /* tmp ptr to client data */
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEFILE]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_REMOVEFILE);
 
     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
        goto Bad_RemoveFile;
@@ -3613,23 +3318,7 @@ SRXAFS_RemoveFile(struct rx_call * acall, struct AFSFid * DirFid, char *Name,
 
     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (code == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, code);
 
     osi_auditU(acall, RemoveFileEvent, code,
                AUD_ID, t_client ? t_client->ViceId : 0,
@@ -3684,7 +3373,7 @@ SAFSS_CreateFile(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
      * also returned
      */
     if ((errorCode =
-        GetVolumePackage(tcon, DirFid, &volptr, &parentptr, MustBeDIR,
+        GetVolumePackage(acall, DirFid, &volptr, &parentptr, MustBeDIR,
                          &parentwhentargetnotdir, &client, WRITE_LOCK,
                          &rights, &anyrights))) {
        goto Bad_CreateFile;
@@ -3697,26 +3386,23 @@ SAFSS_CreateFile(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
        goto Bad_CreateFile;
     }
+
     /* get a new vnode for the file to be created and set it up */
     if ((errorCode =
         Alloc_NewVnode(parentptr, &dir, volptr, &targetptr, Name, OutFid,
-                       vFile, nBlocks(0)))) {
+                       vFile, nBlocks(0))))
        goto Bad_CreateFile;
-    }
 
     /* update the status of the parent vnode */
-#if FS_STATS_DETAILED
     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
                             parentptr->disk.linkCount,
                             client->InSameNetwork);
-#else
-    Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
-                            parentptr->disk.linkCount);
-#endif /* FS_STATS_DETAILED */
 
     /* update the status of the new file's vnode */
     Update_TargetVnodeStatus(targetptr, TVS_CFILE, client, InStatus,
-                            parentptr, volptr, 0);
+                            parentptr, volptr, 0, 0);
+
+    rx_KeepAliveOn(acall);
 
     /* set up the return status for the parent dir and the newly created file, and since the newly created file is owned by the creator, give it PRSFS_ADMINISTER to tell the client its the owner of the file */
     GetStatus(targetptr, OutFidStatus, rights | PRSFS_ADMINISTER, anyrights, parentptr);
@@ -3734,7 +3420,7 @@ SAFSS_CreateFile(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
 
   Bad_CreateFile:
     /* Update and store volume/vnode and parent vnodes back */
-    (void)PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr,
+    (void)PutVolumePackage(acall, parentwhentargetnotdir, targetptr, parentptr,
                           volptr, &client);
     FidZap(&dir);
     ViceLog(2, ("SAFS_CreateFile returns %d\n", errorCode));
@@ -3754,21 +3440,9 @@ SRXAFS_CreateFile(struct rx_call * acall, struct AFSFid * DirFid, char *Name,
     struct rx_connection *tcon;
     struct host *thost;
     struct client *t_client = NULL;    /* tmp ptr to client data */
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CREATEFILE]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_CREATEFILE);
 
     memset(OutFid, 0, sizeof(struct AFSFid));
 
@@ -3784,23 +3458,7 @@ SRXAFS_CreateFile(struct rx_call * acall, struct AFSFid * DirFid, char *Name,
 
     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (code == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, code);
 
     osi_auditU(acall, CreateFileEvent, code,
                AUD_ID, t_client ? t_client->ViceId : 0,
@@ -3884,7 +3542,7 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
 
     if (OldDirFid->Vnode <= NewDirFid->Vnode) {
        if ((errorCode =
-            GetVolumePackage(tcon, OldDirFid, &volptr, &oldvptr, MustBeDIR,
+            GetVolumePackage(acall, OldDirFid, &volptr, &oldvptr, MustBeDIR,
                              &parent, &client, WRITE_LOCK, &rights,
                              &anyrights))) {
            DFlush();
@@ -3895,7 +3553,7 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
            newrights = rights, newanyrights = anyrights;
        } else
            if ((errorCode =
-                GetVolumePackage(tcon, NewDirFid, &volptr, &newvptr,
+                GetVolumePackage(acall, NewDirFid, &volptr, &newvptr,
                                  MustBeDIR, &parent, &client, WRITE_LOCK,
                                  &newrights, &newanyrights))) {
            DFlush();
@@ -3903,14 +3561,14 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
        }
     } else {
        if ((errorCode =
-            GetVolumePackage(tcon, NewDirFid, &volptr, &newvptr, MustBeDIR,
+            GetVolumePackage(acall, NewDirFid, &volptr, &newvptr, MustBeDIR,
                              &parent, &client, WRITE_LOCK, &newrights,
                              &newanyrights))) {
            DFlush();
            goto Bad_Rename;
        }
        if ((errorCode =
-            GetVolumePackage(tcon, OldDirFid, &volptr, &oldvptr, MustBeDIR,
+            GetVolumePackage(acall, OldDirFid, &volptr, &oldvptr, MustBeDIR,
                              &parent, &client, WRITE_LOCK, &rights,
                              &anyrights))) {
            DFlush();
@@ -3928,6 +3586,13 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
        goto Bad_Rename;
     }
 
+    if (CheckLength(volptr, oldvptr, -1) ||
+        CheckLength(volptr, newvptr, -1)) {
+       VTakeOffline(volptr);
+       errorCode = VSALVAGE;
+       goto Bad_Rename;
+    }
+
     /* The CopyOnWrite might return ENOSPC ( disk full). Even if the second
      *  call to CopyOnWrite returns error, it is not necessary to revert back
      *  the effects of the first call because the contents of the volume is
@@ -3948,7 +3613,7 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
     SetDirHandle(&newdir, newvptr);
 
     /* Lookup the file to delete its vnode */
-    if (Lookup(&olddir, OldName, &fileFid)) {
+    if (afs_dir_Lookup(&olddir, OldName, &fileFid)) {
        errorCode = ENOENT;
        goto Bad_Rename;
     }
@@ -3988,7 +3653,7 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
     }
 
     /* Lookup the new file  */
-    if (!(Lookup(&newdir, NewName, &newFileFid))) {
+    if (!(afs_dir_Lookup(&newdir, NewName, &newFileFid))) {
        if (readonlyServer) {
            errorCode = VREADONLY;
            goto Bad_Rename;
@@ -4033,7 +3698,7 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
                errorCode = EISDIR;
                goto Bad_Rename;
            }
-           if ((IsEmpty(&newfiledir))) {
+           if ((afs_dir_IsEmpty(&newfiledir))) {
                errorCode = EEXIST;
                goto Bad_Rename;
            }
@@ -4096,7 +3761,7 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
        } else {
            struct AFSFid unused;
 
-           code = Lookup(&filedir, "..", &unused);
+           code = afs_dir_Lookup(&filedir, "..", &unused);
            if (code == ENOENT) {
                /* only update .. if it doesn't already exist */
                updatefile = 1;
@@ -4111,13 +3776,16 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
        ViceLog(25, ("Rename : calling CopyOnWrite on  target dir\n"));
        if ((errorCode = CopyOnWrite(fileptr, volptr, 0, MAXFSIZE)))
            goto Bad_Rename;
+       /* since copyonwrite would mean fileptr has a new handle, do it here */
+       FidZap(&filedir);
+       SetDirHandle(&filedir, fileptr);
     }
 
     /* If the new name exists already, delete it and the file it points to */
     doDelete = 0;
     if (newfileptr) {
        /* Delete NewName from its directory */
-       code = Delete(&newdir, NewName);
+       code = afs_dir_Delete(&newdir, NewName);
        osi_Assert(code == 0);
 
        /* Drop the link count */
@@ -4161,24 +3829,17 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
      * highly unlikely that it would work since it would involve issuing
      * another create.
      */
-    if ((errorCode = Create(&newdir, (char *)NewName, &fileFid)))
+    if ((errorCode = afs_dir_Create(&newdir, NewName, &fileFid)))
        goto Bad_Rename;
 
     /* Delete the old name */
-    osi_Assert(Delete(&olddir, (char *)OldName) == 0);
+    osi_Assert(afs_dir_Delete(&olddir, OldName) == 0);
 
     /* if the directory length changes, reflect it in the statistics */
-#if FS_STATS_DETAILED
     Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId,
                             oldvptr->disk.linkCount, client->InSameNetwork);
     Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId,
                             newvptr->disk.linkCount, client->InSameNetwork);
-#else
-    Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId,
-                            oldvptr->disk.linkCount);
-    Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId,
-                            newvptr->disk.linkCount);
-#endif /* FS_STATS_DETAILED */
 
     if (oldvptr == newvptr)
        oldvptr->disk.dataVersion--;    /* Since it was bumped by 2! */
@@ -4196,8 +3857,8 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
        fileptr->changed_newTime = 1;   /* status change of moved file */
 
        /* fix .. to point to the correct place */
-       Delete(&filedir, ".."); /* No assert--some directories may be bad */
-       osi_Assert(Create(&filedir, "..", NewDirFid) == 0);
+       afs_dir_Delete(&filedir, ".."); /* No assert--some directories may be bad */
+       osi_Assert(afs_dir_Create(&filedir, "..", NewDirFid) == 0);
        fileptr->disk.dataVersion++;
 
        /* if the parent directories are different the link counts have to be   */
@@ -4230,6 +3891,8 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
        osi_Assert(!errorCode || errorCode == VSALVAGE);
     }
 
+    rx_KeepAliveOn(acall);
+
     /* break call back on NewDirFid, OldDirFid, NewDirFid and newFileFid  */
     BreakCallBack(client->host, NewDirFid, 0);
     if (oldvptr != newvptr) {
@@ -4256,10 +3919,11 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
 
   Bad_Rename:
     if (newfileptr) {
+       rx_KeepAliveOff(acall);
        VPutVnode(&fileCode, newfileptr);
        osi_Assert(fileCode == 0);
     }
-    (void)PutVolumePackage(fileptr, (newvptr && newvptr != oldvptr ?
+    (void)PutVolumePackage(acall, fileptr, (newvptr && newvptr != oldvptr ?
                                     newvptr : 0), oldvptr, volptr, &client);
     FidZap(&olddir);
     FidZap(&newdir);
@@ -4282,21 +3946,9 @@ SRXAFS_Rename(struct rx_call * acall, struct AFSFid * OldDirFid,
     struct rx_connection *tcon;
     struct host *thost;
     struct client *t_client = NULL;    /* tmp ptr to client data */
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RENAME]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_RENAME);
 
     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
        goto Bad_Rename;
@@ -4310,23 +3962,7 @@ SRXAFS_Rename(struct rx_call * acall, struct AFSFid * OldDirFid,
 
     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (code == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, code);
 
     osi_auditU(acall, RenameFileEvent, code,
                AUD_ID, t_client ? t_client->ViceId : 0,
@@ -4384,19 +4020,17 @@ SAFSS_Symlink(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
      * rights to it
      */
     if ((errorCode =
-        GetVolumePackage(tcon, DirFid, &volptr, &parentptr, MustBeDIR,
+        GetVolumePackage(acall, DirFid, &volptr, &parentptr, MustBeDIR,
                          &parentwhentargetnotdir, &client, WRITE_LOCK,
-                         &rights, &anyrights))) {
+                         &rights, &anyrights)))
        goto Bad_SymLink;
-    }
 
     /* set volume synchronization information */
     SetVolumeSync(Sync, volptr);
 
     /* Does the caller has insert (and write) access to the parent directory? */
-    if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
+    if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)))
        goto Bad_SymLink;
-    }
 
     /*
      * If we're creating a mount point (any x bits clear), we must have
@@ -4427,24 +4061,19 @@ SAFSS_Symlink(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
     }
 
     /* update the status of the parent vnode */
-#if FS_STATS_DETAILED
     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
                             parentptr->disk.linkCount,
                             client->InSameNetwork);
-#else
-    Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
-                            parentptr->disk.linkCount);
-#endif /* FS_STATS_DETAILED */
 
     /* update the status of the new symbolic link file vnode */
     Update_TargetVnodeStatus(targetptr, TVS_SLINK, client, InStatus,
-                            parentptr, volptr, strlen((char *)LinkContents));
+                            parentptr, volptr, strlen((char *)LinkContents), 0);
 
     /* Write the contents of the symbolic link name into the target inode */
     fdP = IH_OPEN(targetptr->handle);
     if (fdP == NULL) {
-       (void)PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr,
-                              volptr, &client);
+       (void)PutVolumePackage(acall, parentwhentargetnotdir, targetptr,
+                              parentptr, volptr, &client);
        VTakeOffline(volptr);
        ViceLog(0, ("Volume %u now offline, must be salvaged.\n",
                    volptr->hashid));
@@ -4466,12 +4095,14 @@ SAFSS_Symlink(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
     VVnodeWriteToRead(&errorCode, parentptr);
     osi_Assert(!errorCode || errorCode == VSALVAGE);
 
+    rx_KeepAliveOn(acall);
+
     /* break call back on the parent dir */
     BreakCallBack(client->host, DirFid, 0);
 
   Bad_SymLink:
     /* Write the all modified vnodes (parent, new files) and volume back */
-    (void)PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr,
+    (void)PutVolumePackage(acall, parentwhentargetnotdir, targetptr, parentptr,
                           volptr, &client);
     FidZap(&dir);
     ViceLog(2, ("SAFS_Symlink returns %d\n", errorCode));
@@ -4495,21 +4126,9 @@ SRXAFS_Symlink(struct rx_call *acall,    /* Rx call */
     struct rx_connection *tcon;
     struct host *thost;
     struct client *t_client = NULL;    /* tmp ptr to client data */
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SYMLINK]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_SYMLINK);
 
     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
        goto Bad_Symlink;
@@ -4523,23 +4142,7 @@ SRXAFS_Symlink(struct rx_call *acall,    /* Rx call */
 
     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (code == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, code);
 
     osi_auditU(acall, SymlinkEvent, code,
                AUD_ID, t_client ? t_client->ViceId : 0,
@@ -4598,7 +4201,7 @@ SAFSS_Link(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
      * rights to it
      */
     if ((errorCode =
-        GetVolumePackage(tcon, DirFid, &volptr, &parentptr, MustBeDIR,
+        GetVolumePackage(acall, DirFid, &volptr, &parentptr, MustBeDIR,
                          &parentwhentargetnotdir, &client, WRITE_LOCK,
                          &rights, &anyrights))) {
        goto Bad_Link;
@@ -4618,11 +4221,18 @@ SAFSS_Link(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
        goto Bad_Link;
     }
 
+    if (CheckLength(volptr, parentptr, -1)) {
+       VTakeOffline(volptr);
+       errorCode = VSALVAGE;
+       goto Bad_Link;
+    }
+
     /* get the file vnode  */
     if ((errorCode =
         CheckVnode(ExistingFid, &volptr, &targetptr, WRITE_LOCK))) {
        goto Bad_Link;
     }
+
     if (targetptr->disk.type != vFile) {
        errorCode = EISDIR;
        goto Bad_Link;
@@ -4639,20 +4249,15 @@ SAFSS_Link(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
 
     /* add the name to the directory */
     SetDirHandle(&dir, parentptr);
-    if ((errorCode = Create(&dir, (char *)Name, ExistingFid)))
+    if ((errorCode = afs_dir_Create(&dir, Name, ExistingFid)))
        goto Bad_Link;
     DFlush();
 
     /* update the status in the parent vnode */
     /**WARNING** --> disk.author SHOULDN'T be modified???? */
-#if FS_STATS_DETAILED
     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
                             parentptr->disk.linkCount,
                             client->InSameNetwork);
-#else
-    Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
-                            parentptr->disk.linkCount);
-#endif /* FS_STATS_DETAILED */
 
     targetptr->disk.linkCount++;
     targetptr->disk.author = client->ViceId;
@@ -4668,6 +4273,8 @@ SAFSS_Link(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
     VVnodeWriteToRead(&errorCode, parentptr);
     osi_Assert(!errorCode || errorCode == VSALVAGE);
 
+    rx_KeepAliveOn(acall);
+
     /* break call back on DirFid */
     BreakCallBack(client->host, DirFid, 0);
     /*
@@ -4678,7 +4285,7 @@ SAFSS_Link(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
 
   Bad_Link:
     /* Write the all modified vnodes (parent, new files) and volume back */
-    (void)PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr,
+    (void)PutVolumePackage(acall, parentwhentargetnotdir, targetptr, parentptr,
                           volptr, &client);
     FidZap(&dir);
     ViceLog(2, ("SAFS_Link returns %d\n", errorCode));
@@ -4696,21 +4303,9 @@ SRXAFS_Link(struct rx_call * acall, struct AFSFid * DirFid, char *Name,
     struct rx_connection *tcon;
     struct host *thost;
     struct client *t_client = NULL;    /* tmp ptr to client data */
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_LINK]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_LINK);
 
     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
        goto Bad_Link;
@@ -4724,23 +4319,7 @@ SRXAFS_Link(struct rx_call * acall, struct AFSFid * DirFid, char *Name,
 
     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (code == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, code);
 
     osi_auditU(acall, LinkEvent, code,
                AUD_ID, t_client ? t_client->ViceId : 0,
@@ -4800,7 +4379,7 @@ SAFSS_MakeDir(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
      * rights to it.
      */
     if ((errorCode =
-        GetVolumePackage(tcon, DirFid, &volptr, &parentptr, MustBeDIR,
+        GetVolumePackage(acall, DirFid, &volptr, &parentptr, MustBeDIR,
                          &parentwhentargetnotdir, &client, WRITE_LOCK,
                          &rights, &anyrights))) {
        goto Bad_MakeDir;
@@ -4834,14 +4413,9 @@ SAFSS_MakeDir(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
     }
 
     /* Update the status for the parent dir */
-#if FS_STATS_DETAILED
     Update_ParentVnodeStatus(parentptr, volptr, &parentdir, client->ViceId,
                             parentptr->disk.linkCount + 1,
                             client->InSameNetwork);
-#else
-    Update_ParentVnodeStatus(parentptr, volptr, &parentdir, client->ViceId,
-                            parentptr->disk.linkCount + 1);
-#endif /* FS_STATS_DETAILED */
 
     /* Point to target's ACL buffer and copy the parent's ACL contents to it */
     osi_Assert((SetAccessList
@@ -4852,13 +4426,13 @@ SAFSS_MakeDir(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
 
     /* update the status for the target vnode */
     Update_TargetVnodeStatus(targetptr, TVS_MKDIR, client, InStatus,
-                            parentptr, volptr, 0);
+                            parentptr, volptr, 0, 0);
 
     /* Actually create the New directory in the directory package */
     SetDirHandle(&dir, targetptr);
-    osi_Assert(!(MakeDir(&dir, (afs_int32 *)OutFid, (afs_int32 *)DirFid)));
+    osi_Assert(!(afs_dir_MakeDir(&dir, (afs_int32 *)OutFid, (afs_int32 *)DirFid)));
     DFlush();
-    VN_SET_LEN(targetptr, (afs_fsize_t) Length(&dir));
+    VN_SET_LEN(targetptr, (afs_fsize_t) afs_dir_Length(&dir));
 
     /* set up return status */
     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
@@ -4868,6 +4442,8 @@ SAFSS_MakeDir(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
     VVnodeWriteToRead(&errorCode, parentptr);
     osi_Assert(!errorCode || errorCode == VSALVAGE);
 
+    rx_KeepAliveOn(acall);
+
     /* break call back on DirFid */
     BreakCallBack(client->host, DirFid, 0);
 
@@ -4876,7 +4452,7 @@ SAFSS_MakeDir(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
 
   Bad_MakeDir:
     /* Write the all modified vnodes (parent, new files) and volume back */
-    (void)PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr,
+    (void)PutVolumePackage(acall, parentwhentargetnotdir, targetptr, parentptr,
                           volptr, &client);
     FidZap(&dir);
     FidZap(&parentdir);
@@ -4897,21 +4473,10 @@ SRXAFS_MakeDir(struct rx_call * acall, struct AFSFid * DirFid, char *Name,
     struct rx_connection *tcon;
     struct host *thost;
     struct client *t_client = NULL;    /* tmp ptr to client data */
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
+
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_MAKEDIR);
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_MAKEDIR]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
        goto Bad_MakeDir;
 
@@ -4924,23 +4489,7 @@ SRXAFS_MakeDir(struct rx_call * acall, struct AFSFid * DirFid, char *Name,
 
     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (code == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, code);
 
     osi_auditU(acall, MakeDirEvent, code,
                AUD_ID, t_client ? t_client->ViceId : 0,
@@ -4989,7 +4538,7 @@ SAFSS_RemoveDir(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
      * rights to it
      */
     if ((errorCode =
-        GetVolumePackage(tcon, DirFid, &volptr, &parentptr, MustBeDIR,
+        GetVolumePackage(acall, DirFid, &volptr, &parentptr, MustBeDIR,
                          &parentwhentargetnotdir, &client, WRITE_LOCK,
                          &rights, &anyrights))) {
        goto Bad_RemoveDir;
@@ -5011,14 +4560,9 @@ SAFSS_RemoveDir(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
     }
 
     /* Update the status for the parent dir; link count is also adjusted */
-#if FS_STATS_DETAILED
     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
                             parentptr->disk.linkCount - 1,
                             client->InSameNetwork);
-#else
-    Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
-                            parentptr->disk.linkCount - 1);
-#endif /* FS_STATS_DETAILED */
 
     /* Return to the caller the updated parent dir status */
     GetStatus(parentptr, OutDirStatus, rights, anyrights, NULL);
@@ -5034,12 +4578,14 @@ SAFSS_RemoveDir(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
     VVnodeWriteToRead(&errorCode, parentptr);
     osi_Assert(!errorCode || errorCode == VSALVAGE);
 
+    rx_KeepAliveOn(acall);
+
     /* break call back on DirFid and fileFid */
     BreakCallBack(client->host, DirFid, 0);
 
   Bad_RemoveDir:
     /* Write the all modified vnodes (parent, new files) and volume back */
-    (void)PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr,
+    (void)PutVolumePackage(acall, parentwhentargetnotdir, targetptr, parentptr,
                           volptr, &client);
     FidZap(&dir);
     ViceLog(2, ("SAFS_RemoveDir        returns %d\n", errorCode));
@@ -5057,21 +4603,9 @@ SRXAFS_RemoveDir(struct rx_call * acall, struct AFSFid * DirFid, char *Name,
     struct rx_connection *tcon;
     struct host *thost;
     struct client *t_client = NULL;    /* tmp ptr to client data */
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEDIR]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_REMOVEDIR);
 
     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
        goto Bad_RemoveDir;
@@ -5083,23 +4617,7 @@ SRXAFS_RemoveDir(struct rx_call * acall, struct AFSFid * DirFid, char *Name,
 
     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (code == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, code);
 
     osi_auditU(acall, RemoveDirEvent, code,
                AUD_ID, t_client ? t_client->ViceId : 0,
@@ -5147,7 +4665,7 @@ SAFSS_SetLock(struct rx_call *acall, struct AFSFid *Fid, ViceLockType type,
      * rights to it
      */
     if ((errorCode =
-        GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
+        GetVolumePackage(acall, Fid, &volptr, &targetptr, DONTCHECK,
                          &parentwhentargetnotdir, &client, WRITE_LOCK,
                          &rights, &anyrights))) {
        goto Bad_SetLock;
@@ -5161,8 +4679,8 @@ SAFSS_SetLock(struct rx_call *acall, struct AFSFid *Fid, ViceLockType type,
 
   Bad_SetLock:
     /* Write the all modified vnodes (parent, new files) and volume back */
-    (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
-                          volptr, &client);
+    (void)PutVolumePackage(acall, parentwhentargetnotdir, targetptr,
+                          (Vnode *) 0, volptr, &client);
 
     if ((errorCode == VREADONLY) && (type == LockRead))
        errorCode = 0;          /* allow read locks on RO volumes without saving state */
@@ -5189,21 +4707,9 @@ SRXAFS_SetLock(struct rx_call * acall, struct AFSFid * Fid, ViceLockType type,
     struct rx_connection *tcon;
     struct host *thost;
     struct client *t_client = NULL;    /* tmp ptr to client data */
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SETLOCK]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_SETLOCK);
 
     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
        goto Bad_SetLock;
@@ -5215,23 +4721,7 @@ SRXAFS_SetLock(struct rx_call * acall, struct AFSFid * Fid, ViceLockType type,
 
     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (code == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, code);
 
     osi_auditU(acall, SetLockEvent, code,
                AUD_ID, t_client ? t_client->ViceId : 0,
@@ -5273,7 +4763,7 @@ SAFSS_ExtendLock(struct rx_call *acall, struct AFSFid *Fid,
      * rights to it
      */
     if ((errorCode =
-        GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
+        GetVolumePackage(acall, Fid, &volptr, &targetptr, DONTCHECK,
                          &parentwhentargetnotdir, &client, WRITE_LOCK,
                          &rights, &anyrights))) {
        goto Bad_ExtendLock;
@@ -5287,10 +4777,10 @@ SAFSS_ExtendLock(struct rx_call *acall, struct AFSFid *Fid,
 
   Bad_ExtendLock:
     /* Put back file's vnode and volume */
-    (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
-                          volptr, &client);
+    (void)PutVolumePackage(acall, parentwhentargetnotdir, targetptr,
+                          (Vnode *) 0, volptr, &client);
 
-    if ((errorCode == VREADONLY))      /* presumably, we already granted this lock */
+    if (errorCode == VREADONLY)        /* presumably, we already granted this lock */
        errorCode = 0;          /* under our generous policy re RO vols */
 
     ViceLog(2, ("SAFS_ExtendLock returns %d\n", errorCode));
@@ -5315,21 +4805,9 @@ SRXAFS_ExtendLock(struct rx_call * acall, struct AFSFid * Fid,
     struct rx_connection *tcon;
     struct host *thost;
     struct client *t_client = NULL;    /* tmp ptr to client data */
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_EXTENDLOCK]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_EXTENDLOCK);
 
     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
        goto Bad_ExtendLock;
@@ -5341,23 +4819,7 @@ SRXAFS_ExtendLock(struct rx_call * acall, struct AFSFid * Fid,
 
     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (code == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, code);
 
     osi_auditU(acall, ExtendLockEvent, code,
                AUD_ID, t_client ? t_client->ViceId : 0,
@@ -5400,7 +4862,7 @@ SAFSS_ReleaseLock(struct rx_call *acall, struct AFSFid *Fid,
      * rights to it
      */
     if ((errorCode =
-        GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
+        GetVolumePackage(acall, Fid, &volptr, &targetptr, DONTCHECK,
                          &parentwhentargetnotdir, &client, WRITE_LOCK,
                          &rights, &anyrights))) {
        goto Bad_ReleaseLock;
@@ -5415,6 +4877,7 @@ SAFSS_ReleaseLock(struct rx_call *acall, struct AFSFid *Fid,
 
     /* if no more locks left, a callback would be triggered here */
     if (targetptr->disk.lock.lockCount <= 0) {
+       rx_KeepAliveOn(acall);
        /* convert the write lock to a read lock before breaking callbacks */
        VVnodeWriteToRead(&errorCode, targetptr);
        osi_Assert(!errorCode || errorCode == VSALVAGE);
@@ -5423,10 +4886,10 @@ SAFSS_ReleaseLock(struct rx_call *acall, struct AFSFid *Fid,
 
   Bad_ReleaseLock:
     /* Put back file's vnode and volume */
-    (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
-                          volptr, &client);
+    (void)PutVolumePackage(acall, parentwhentargetnotdir, targetptr,
+                          (Vnode *) 0, volptr, &client);
 
-    if ((errorCode == VREADONLY))      /* presumably, we already granted this lock */
+    if (errorCode == VREADONLY)        /* presumably, we already granted this lock */
        errorCode = 0;          /* under our generous policy re RO vols */
 
     ViceLog(2, ("SAFS_ReleaseLock returns %d\n", errorCode));
@@ -5451,21 +4914,9 @@ SRXAFS_ReleaseLock(struct rx_call * acall, struct AFSFid * Fid,
     struct rx_connection *tcon;
     struct host *thost;
     struct client *t_client = NULL;    /* tmp ptr to client data */
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RELEASELOCK]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_RELEASELOCK);
 
     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
        goto Bad_ReleaseLock;
@@ -5477,23 +4928,7 @@ SRXAFS_ReleaseLock(struct rx_call * acall, struct AFSFid * Fid,
 
     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (code == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, code);
 
     osi_auditU(acall, ReleaseLockEvent, code,
                AUD_ID, t_client ? t_client->ViceId : 0,
@@ -5567,8 +5002,8 @@ SetVolumeStats(struct AFSStatistics *stats)
 
     for (part = DiskPartitionList; part && i < AFS_MSTATDISKS;
         part = part->next) {
-       stats->Disks[i].TotalBlocks = RoundInt64ToInt32(part->totalUsable);
-       stats->Disks[i].BlocksAvailable = RoundInt64ToInt32(part->free);
+       stats->Disks[i].TotalBlocks = RoundInt64ToInt31(part->totalUsable);
+       stats->Disks[i].BlocksAvailable = RoundInt64ToInt31(part->free);
        memset(stats->Disks[i].Name, 0, AFS_DISKNAMESIZE);
        strncpy(stats->Disks[i].Name, part->name, AFS_DISKNAMESIZE);
        i++;
@@ -5586,21 +5021,9 @@ SRXAFS_GetStatistics(struct rx_call *acall, struct ViceStatistics *Statistics)
     struct rx_connection *tcon = rx_ConnectionOf(acall);
     struct host *thost;
     struct client *t_client = NULL;    /* tmp ptr to client data */
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETSTATISTICS]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_GETSTATISTICS);
 
     if ((code = CallPreamble(acall, NOTACTIVECALL, &tcon, &thost)))
        goto Bad_GetStatistics;
@@ -5619,23 +5042,7 @@ SRXAFS_GetStatistics(struct rx_call *acall, struct ViceStatistics *Statistics)
 
     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (code == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, code);
 
     osi_auditU(acall, GetStatisticsEvent, code,
                AUD_ID, t_client ? t_client->ViceId : 0, AUD_END);
@@ -5653,21 +5060,9 @@ SRXAFS_GetStatistics64(struct rx_call *acall, afs_int32 statsVersion, ViceStatis
     struct host *thost;
     struct client *t_client = NULL;    /* tmp ptr to client data */
     struct timeval time;
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETSTATISTICS]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_GETSTATISTICS);
 
     if ((code = CallPreamble(acall, NOTACTIVECALL, &tcon, &thost)))
        goto Bad_GetStatistics64;
@@ -5730,23 +5125,7 @@ SRXAFS_GetStatistics64(struct rx_call *acall, afs_int32 statsVersion, ViceStatis
 
     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (code == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, code);
 
     osi_auditU(acall, GetStatisticsEvent, code,
                AUD_ID, t_client ? t_client->ViceId : 0, AUD_END);
@@ -5780,41 +5159,15 @@ SRXAFS_XStatsVersion(struct rx_call * a_call, afs_int32 * a_versionP)
 
     struct client *t_client = NULL;    /* tmp ptr to client data */
     struct rx_connection *tcon = rx_ConnectionOf(a_call);
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_XSTATSVERSION]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_XSTATSVERSION);
 
     *a_versionP = AFS_XSTAT_VERSION;
 
     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-    fs_stats_AddTo((opP->sumTime), elapsedTime);
-    fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-    if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-       fs_stats_TimeAssign((opP->minTime), elapsedTime);
-    }
-    if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-       fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-    }
-    FS_LOCK;
-    (opP->numSuccesses)++;
-    FS_UNLOCK;
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, 0);
 
     osi_auditU(a_call, XStatsVersionEvent, 0,
                AUD_ID, t_client ? t_client->ViceId : 0, AUD_END);
@@ -5845,7 +5198,6 @@ SRXAFS_XStatsVersion(struct rx_call * a_call, afs_int32 * a_versionP)
 static void
 FillPerfValues(struct afs_PerfStats *a_perfP)
 {                              /*FillPerfValues */
-    afs_uint32 hi, lo;
     int dir_Buffers;           /*# buffers in use by dir package */
     int dir_Calls;             /*# read calls in dir package */
     int dir_IOs;               /*# I/O ops in dir package */
@@ -5865,10 +5217,8 @@ FillPerfValues(struct afs_PerfStats *a_perfP)
     a_perfP->vcache_S_Reads = VnodeClassInfo[vSmall].reads;
     a_perfP->vcache_S_Writes = VnodeClassInfo[vSmall].writes;
     a_perfP->vcache_H_Entries = VStats.hdr_cache_size;
-    SplitInt64(VStats.hdr_gets, hi, lo);
-    a_perfP->vcache_H_Gets = lo;
-    SplitInt64(VStats.hdr_loads, hi, lo);
-    a_perfP->vcache_H_Replacements = lo;
+    a_perfP->vcache_H_Gets = (int)VStats.hdr_gets;
+    a_perfP->vcache_H_Replacements = (int)VStats.hdr_loads;
 
     /*
      * Directory section.
@@ -5988,21 +5338,9 @@ SRXAFS_GetXStats(struct rx_call *a_call, afs_int32 a_clientVersionNum,
     int code;          /*Return value */
     afs_int32 *dataBuffP;      /*Ptr to data to be returned */
     afs_int32 dataBytes;       /*Bytes in data buffer */
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETXSTATS]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_GETXSTATS);
 
     /*
      * Record the time of day and the server version number.
@@ -6088,7 +5426,6 @@ SRXAFS_GetXStats(struct rx_call *a_call, afs_int32 a_clientVersionNum,
         */
 
        afs_perfstats.numPerfCalls++;
-#if FS_STATS_DETAILED
        afs_FullPerfStats.overall.numPerfCalls = afs_perfstats.numPerfCalls;
        FillPerfValues(&afs_FullPerfStats.overall);
 
@@ -6101,7 +5438,6 @@ SRXAFS_GetXStats(struct rx_call *a_call, afs_int32 a_clientVersionNum,
        memcpy(dataBuffP, &afs_FullPerfStats, dataBytes);
        a_dataP->AFS_CollData_len = dataBytes >> 2;
        a_dataP->AFS_CollData_val = dataBuffP;
-#endif
        break;
 
     case AFS_XSTATSCOLL_CBSTATS:
@@ -6143,23 +5479,7 @@ SRXAFS_GetXStats(struct rx_call *a_call, afs_int32 a_clientVersionNum,
        code = 1;
     }                          /*Switch on collection number */
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (code == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, code);
 
     return (code);
 
@@ -6175,22 +5495,9 @@ common_GiveUpCallBacks(struct rx_call *acall, struct AFSCBFids *FidArray,
     struct client *client = 0;
     struct rx_connection *tcon;
     struct host *thost;
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP =
-       &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GIVEUPCALLBACKS]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_GIVEUPCALLBACKS);
 
     if (FidArray)
        ViceLog(1,
@@ -6206,7 +5513,7 @@ common_GiveUpCallBacks(struct rx_call *acall, struct AFSCBFids *FidArray,
     if (!FidArray && !CallBackArray) {
        ViceLog(1,
                ("SAFS_GiveUpAllCallBacks: host=%x\n",
-                (tcon->peer ? tcon->peer->host : 0)));
+                (rx_PeerOf(tcon) ? rx_HostOf(rx_PeerOf(tcon)) : 0)));
        errorCode = GetClient(tcon, &client);
        if (!errorCode) {
            H_LOCK;
@@ -6219,7 +5526,7 @@ common_GiveUpCallBacks(struct rx_call *acall, struct AFSCBFids *FidArray,
            ViceLog(0,
                    ("GiveUpCallBacks: #Fids %d < #CallBacks %d, host=%x\n",
                     FidArray->AFSCBFids_len, CallBackArray->AFSCBs_len,
-                    (tcon->peer ? tcon->peer->host : 0)));
+                    (rx_PeerOf(tcon) ? rx_HostOf(rx_PeerOf(tcon)) : 0)));
            errorCode = EINVAL;
            goto Bad_GiveUpCallBacks;
        }
@@ -6237,23 +5544,8 @@ common_GiveUpCallBacks(struct rx_call *acall, struct AFSCBFids *FidArray,
   Bad_GiveUpCallBacks:
     errorCode = CallPostamble(tcon, errorCode, thost);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (errorCode == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, errorCode);
+
     return errorCode;
 
 }                              /*common_GiveUpCallBacks */
@@ -6520,21 +5812,10 @@ SRXAFS_GetVolumeInfo(struct rx_call * acall, char *avolid,
     afs_int32 code;
     struct rx_connection *tcon;
     struct host *thost;
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
+
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_GETVOLUMEINFO);
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETVOLUMEINFO]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
        goto Bad_GetVolumeInfo;
 
@@ -6551,23 +5832,7 @@ SRXAFS_GetVolumeInfo(struct rx_call * acall, char *avolid,
   Bad_GetVolumeInfo:
     code = CallPostamble(tcon, code, thost);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (code == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, code);
 
     return code;
 
@@ -6589,22 +5854,9 @@ SRXAFS_GetVolumeStatus(struct rx_call * acall, afs_int32 avolid,
     struct rx_connection *tcon;
     struct host *thost;
     struct client *t_client = NULL;    /* tmp ptr to client data */
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP =
-       &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETVOLUMESTATUS]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_GETVOLUMESTATUS);
 
     ViceLog(1, ("SAFS_GetVolumeStatus for volume %u\n", avolid));
     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
@@ -6621,7 +5873,7 @@ SRXAFS_GetVolumeStatus(struct rx_call * acall, afs_int32 avolid,
        (afs_int32) ROOTVNODE, dummyFid.Unique = 1;
 
     if ((errorCode =
-        GetVolumePackage(tcon, &dummyFid, &volptr, &targetptr, MustBeDIR,
+        GetVolumePackage(acall, &dummyFid, &volptr, &targetptr, MustBeDIR,
                          &parentwhentargetnotdir, &client, READ_LOCK,
                          &rights, &anyrights)))
        goto Bad_GetVolumeStatus;
@@ -6633,8 +5885,8 @@ SRXAFS_GetVolumeStatus(struct rx_call * acall, afs_int32 avolid,
     (void)RXGetVolumeStatus(FetchVolStatus, Name, OfflineMsg, Motd, volptr);
 
   Bad_GetVolumeStatus:
-    (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
-                          volptr, &client);
+    (void)PutVolumePackage(acall, parentwhentargetnotdir, targetptr,
+                          (Vnode *) 0, volptr, &client);
     ViceLog(2, ("SAFS_GetVolumeStatus returns %d\n", errorCode));
     /* next is to guarantee out strings exist for stub */
     if (*Name == 0) {
@@ -6653,23 +5905,7 @@ SRXAFS_GetVolumeStatus(struct rx_call * acall, afs_int32 avolid,
 
     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (errorCode == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, errorCode);
 
     osi_auditU(acall, GetVolumeStatusEvent, errorCode,
                AUD_ID, t_client ? t_client->ViceId : 0,
@@ -6694,22 +5930,9 @@ SRXAFS_SetVolumeStatus(struct rx_call * acall, afs_int32 avolid,
     struct rx_connection *tcon = rx_ConnectionOf(acall);
     struct host *thost;
     struct client *t_client = NULL;    /* tmp ptr to client data */
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP =
-       &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SETVOLUMESTATUS]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_SETVOLUMESTATUS);
 
     ViceLog(1, ("SAFS_SetVolumeStatus for volume %u\n", avolid));
     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
@@ -6726,7 +5949,7 @@ SRXAFS_SetVolumeStatus(struct rx_call * acall, afs_int32 avolid,
        (afs_int32) ROOTVNODE, dummyFid.Unique = 1;
 
     if ((errorCode =
-        GetVolumePackage(tcon, &dummyFid, &volptr, &targetptr, MustBeDIR,
+        GetVolumePackage(acall, &dummyFid, &volptr, &targetptr, MustBeDIR,
                          &parentwhentargetnotdir, &client, READ_LOCK,
                          &rights, &anyrights)))
        goto Bad_SetVolumeStatus;
@@ -6744,30 +5967,14 @@ SRXAFS_SetVolumeStatus(struct rx_call * acall, afs_int32 avolid,
        RXUpdate_VolumeStatus(volptr, StoreVolStatus, Name, OfflineMsg, Motd);
 
   Bad_SetVolumeStatus:
-    PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
+    PutVolumePackage(acall, parentwhentargetnotdir, targetptr, (Vnode *) 0,
                     volptr, &client);
     ViceLog(2, ("SAFS_SetVolumeStatus returns %d\n", errorCode));
     errorCode = CallPostamble(tcon, errorCode, thost);
 
     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (errorCode == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, errorCode);
 
     osi_auditU(acall, SetVolumeStatusEvent, errorCode,
                AUD_ID, t_client ? t_client->ViceId : 0,
@@ -6788,24 +5995,9 @@ SRXAFS_GetRootVolume(struct rx_call * acall, char **VolumeName)
     struct host *thost;
     Error errorCode = 0;
 #endif
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime;        /* Start time for RPC op */
-#ifdef notdef
-    struct timeval opStopTime;
-    struct timeval elapsedTime;        /* Transfer time */
-#endif
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETROOTVOLUME]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_GETROOTVOLUME);
 
     return FSERR_EOPNOTSUPP;
 
@@ -6841,23 +6033,7 @@ SRXAFS_GetRootVolume(struct rx_call * acall, char **VolumeName)
   Bad_GetRootVolume:
     errorCode = CallPostamble(tcon, errorCode, thost);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (errorCode == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, errorCode);
 
     return (errorCode);
 #endif /* notdef */
@@ -6873,21 +6049,9 @@ SRXAFS_CheckToken(struct rx_call * acall, afs_int32 AfsId,
     afs_int32 code;
     struct rx_connection *tcon;
     struct host *thost;
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CHECKTOKEN]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_CHECKTOKEN);
 
     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
        goto Bad_CheckToken;
@@ -6897,23 +6061,7 @@ SRXAFS_CheckToken(struct rx_call * acall, afs_int32 AfsId,
   Bad_CheckToken:
     code = CallPostamble(tcon, code, thost);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    if (code == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, code);
 
     return code;
 
@@ -6927,21 +6075,9 @@ SRXAFS_GetTime(struct rx_call * acall, afs_uint32 * Seconds,
     struct rx_connection *tcon;
     struct host *thost;
     struct timeval tpl;
-#if FS_STATS_DETAILED
-    struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
-    struct timeval opStartTime, opStopTime;    /* Start/stop times for RPC op */
-    struct timeval elapsedTime;        /* Transfer time */
+    struct fsstats fsstats;
 
-    /*
-     * Set our stats pointer, remember when the RPC operation started, and
-     * tally the operation.
-     */
-    opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETTIME]);
-    FS_LOCK;
-    (opP->numOps)++;
-    FS_UNLOCK;
-    FT_GetTimeOfDay(&opStartTime, 0);
-#endif /* FS_STATS_DETAILED */
+    fsstats_StartOp(&fsstats, FS_STATS_RPCIDX_GETTIME);
 
     if ((code = CallPreamble(acall, NOTACTIVECALL, &tcon, &thost)))
        goto Bad_GetTime;
@@ -6958,23 +6094,7 @@ SRXAFS_GetTime(struct rx_call * acall, afs_uint32 * Seconds,
   Bad_GetTime:
     code = CallPostamble(tcon, code, thost);
 
-#if FS_STATS_DETAILED
-    FT_GetTimeOfDay(&opStopTime, 0);
-    fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
-    if (code == 0) {
-       FS_LOCK;
-       (opP->numSuccesses)++;
-       fs_stats_AddTo((opP->sumTime), elapsedTime);
-       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
-       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
-           fs_stats_TimeAssign((opP->minTime), elapsedTime);
-       }
-       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
-           fs_stats_TimeAssign((opP->maxTime), elapsedTime);
-       }
-       FS_UNLOCK;
-    }
-#endif /* FS_STATS_DETAILED */
+    fsstats_FinishOp(&fsstats, code);
 
     return code;
 
@@ -6993,23 +6113,18 @@ SRXAFS_GetTime(struct rx_call * acall, afs_uint32 * Seconds,
  *     Call            : Ptr to the Rx call involved.
  *     Pos             : Offset within the file.
  *     Len             : Length in bytes to read; this value is bogus!
- * if FS_STATS_DETAILED
  *     a_bytesToFetchP : Set to the number of bytes to be fetched from
  *                       the File Server.
  *     a_bytesFetchedP : Set to the actual number of bytes fetched from
  *                       the File Server.
- * endif
  */
 
-afs_int32
+static afs_int32
 FetchData_RXStyle(Volume * volptr, Vnode * targetptr,
                  struct rx_call * Call, afs_sfsize_t Pos,
                  afs_sfsize_t Len, afs_int32 Int64Mode,
-#if FS_STATS_DETAILED
                  afs_sfsize_t * a_bytesToFetchP,
-                 afs_sfsize_t * a_bytesFetchedP
-#endif                         /* FS_STATS_DETAILED */
-    )
+                 afs_sfsize_t * a_bytesFetchedP)
 {
     struct timeval StartTime, StopTime;        /* used to calculate file  transfer rates */
     IHandle_t *ihP;
@@ -7023,14 +6138,11 @@ FetchData_RXStyle(Volume * volptr, Vnode * targetptr,
     afs_sfsize_t tlen;
     afs_int32 optSize;
 
-#if FS_STATS_DETAILED
     /*
      * Initialize the byte count arguments.
      */
     (*a_bytesToFetchP) = 0;
     (*a_bytesFetchedP) = 0;
-#endif /* FS_STATS_DETAILED */
-
 
     ViceLog(25,
            ("FetchData_RXStyle: Pos %llu, Len %llu\n", (afs_uintmax_t) Pos,
@@ -7067,6 +6179,11 @@ FetchData_RXStyle(Volume * volptr, Vnode * targetptr,
                    volptr->hashid));
        return EIO;
     }
+    if (CheckLength(volptr, targetptr, tlen)) {
+       FDH_CLOSE(fdP);
+       VTakeOffline(volptr);
+       return VSALVAGE;
+    }
     if (Pos > tlen) {
        Len = 0;
     }
@@ -7085,9 +6202,7 @@ FetchData_RXStyle(Volume * volptr, Vnode * targetptr,
        low = htonl(low);
        rx_Write(Call, (char *)&low, sizeof(afs_int32));        /* send length on fetch */
     }
-#if FS_STATS_DETAILED
     (*a_bytesToFetchP) = Len;
-#endif /* FS_STATS_DETAILED */
 #ifndef HAVE_PIOV
     tbuffer = AllocSendBuffer();
 #endif /* HAVE_PIOV */
@@ -7127,18 +6242,21 @@ FetchData_RXStyle(Volume * volptr, Vnode * targetptr,
        nBytes = rx_Writev(Call, tiov, tnio, wlen);
 #endif /* HAVE_PIOV */
        Pos += wlen;
-#if FS_STATS_DETAILED
        /*
         * Bump the number of bytes actually sent by the number from this
         * latest iteration
         */
        (*a_bytesFetchedP) += nBytes;
-#endif /* FS_STATS_DETAILED */
        if (nBytes != wlen) {
+           afs_int32 err;
            FDH_CLOSE(fdP);
 #ifndef HAVE_PIOV
            FreeSendBuffer((struct afs_buffer *)tbuffer);
 #endif /* HAVE_PIOV */
+           err = VIsGoingOffline(volptr);
+           if (err) {
+               return err;
+           }
            return -31;
        }
        Len -= wlen;
@@ -7215,23 +6333,18 @@ GetLinkCountAndSize(Volume * vp, FdHandle_t * fdP, int *lc,
  *     Call            : Ptr to the Rx call involved.
  *     Pos             : Offset within the file.
  *     Len             : Length in bytes to store; this value is bogus!
- * if FS_STATS_DETAILED
  *     a_bytesToStoreP : Set to the number of bytes to be stored to
  *                       the File Server.
  *     a_bytesStoredP  : Set to the actual number of bytes stored to
  *                       the File Server.
- * endif
  */
 afs_int32
 StoreData_RXStyle(Volume * volptr, Vnode * targetptr, struct AFSFid * Fid,
                  struct client * client, struct rx_call * Call,
                  afs_fsize_t Pos, afs_fsize_t Length, afs_fsize_t FileLength,
                  int sync,
-#if FS_STATS_DETAILED
                  afs_sfsize_t * a_bytesToStoreP,
-                 afs_sfsize_t * a_bytesStoredP
-#endif                         /* FS_STATS_DETAILED */
-    )
+                 afs_sfsize_t * a_bytesStoredP)
 {
     afs_sfsize_t bytesTransfered;      /* number of bytes actually transfered */
     struct timeval StartTime, StopTime;        /* Used to measure how long the store takes */
@@ -7250,19 +6363,16 @@ StoreData_RXStyle(Volume * volptr, Vnode * targetptr, struct AFSFid * Fid,
     afs_fsize_t NewLength;     /* size after this store completes */
     afs_sfsize_t adjustSize;   /* bytes to call VAdjust... with */
     int linkCount = 0;         /* link count on inode */
-    afs_fsize_t CoW_off, CoW_len;
     ssize_t nBytes;
-    FdHandle_t *fdP, *origfdP = NULL;
+    FdHandle_t *fdP;
     struct in_addr logHostAddr;        /* host ip holder for inet_ntoa */
     afs_ino_str_t stmp;
 
-#if FS_STATS_DETAILED
     /*
      * Initialize the byte count arguments.
      */
     (*a_bytesToStoreP) = 0;
     (*a_bytesStoredP) = 0;
-#endif /* FS_STATS_DETAILED */
 
     /*
      * We break the callbacks here so that the following signal will not
@@ -7280,6 +6390,7 @@ StoreData_RXStyle(Volume * volptr, Vnode * targetptr, struct AFSFid * Fid,
                 inet_ntoa(logHostAddr), ntohs(rxr_PortOf(rx_ConnectionOf(Call)))));
        return ENOENT;          /* is this proper error code? */
     } else {
+       rx_KeepAliveOff(Call);
        /*
         * See if the file has several links (from other volumes).  If it
         * does, then we have to make a copy before changing it to avoid
@@ -7298,6 +6409,11 @@ StoreData_RXStyle(Volume * volptr, Vnode * targetptr, struct AFSFid * Fid,
                        volptr->hashid));
            return EIO;
        }
+       if (CheckLength(volptr, targetptr, DataLength)) {
+           FDH_CLOSE(fdP);
+           VTakeOffline(volptr);
+           return VSALVAGE;
+       }
 
        if (linkCount != 1) {
            afs_fsize_t size;
@@ -7312,32 +6428,20 @@ StoreData_RXStyle(Volume * volptr, Vnode * targetptr, struct AFSFid * Fid,
             * mechanisms (i.e. copy on write overhead.) Also the right size
             * of the disk will be recorded...
             */
-           origfdP = fdP;
+           FDH_CLOSE(fdP);
            VN_GET_LEN(size, targetptr);
            volptr->partition->flags &= ~PART_DONTUPDATE;
            VSetPartitionDiskUsage(volptr->partition);
            volptr->partition->flags |= PART_DONTUPDATE;
            if ((errorCode = VDiskUsage(volptr, nBlocks(size)))) {
                volptr->partition->flags &= ~PART_DONTUPDATE;
-               FDH_CLOSE(origfdP);
                return (errorCode);
            }
 
-           CoW_len = (FileLength >= (Length + Pos)) ? FileLength - Length : Pos;
-           CopyOnWrite_calls++;
-           if (CoW_len == 0) CopyOnWrite_size0++;
-           if (Pos == 0) CopyOnWrite_off0++;
-           if (CoW_len > CopyOnWrite_maxsize) CopyOnWrite_maxsize = CoW_len;
-
-           ViceLog(1, ("StoreData : calling CopyOnWrite on vnode %u.%u (%s) "
-                       "off 0x0 size 0x%llx\n",
-                       afs_printable_VolumeId_u(V_id(volptr)),
-                       afs_printable_VnodeId_u(targetptr->vnodeNumber),
-                       V_name(volptr), Pos));
-           if ((errorCode = CopyOnWrite(targetptr, volptr, 0, Pos))) {
+           ViceLog(25, ("StoreData : calling CopyOnWrite on  target dir\n"));
+           if ((errorCode = CopyOnWrite(targetptr, volptr, 0, MAXFSIZE))) {
                ViceLog(25, ("StoreData : CopyOnWrite failed\n"));
                volptr->partition->flags &= ~PART_DONTUPDATE;
-               FDH_CLOSE(origfdP);
                return (errorCode);
            }
            volptr->partition->flags &= ~PART_DONTUPDATE;
@@ -7346,7 +6450,6 @@ StoreData_RXStyle(Volume * volptr, Vnode * targetptr, struct AFSFid * Fid,
            if (fdP == NULL) {
                ViceLog(25,
                        ("StoreData : Reopen after CopyOnWrite failed\n"));
-               FDH_CLOSE(origfdP);
                return ENOENT;
            }
        }
@@ -7378,7 +6481,6 @@ StoreData_RXStyle(Volume * volptr, Vnode * targetptr, struct AFSFid * Fid,
         AdjustDiskUsage(volptr, adjustSize,
                         adjustSize - SpareComp(volptr)))) {
        FDH_CLOSE(fdP);
-       if (origfdP) FDH_CLOSE(origfdP);
        return (errorCode);
     }
 
@@ -7420,9 +6522,7 @@ StoreData_RXStyle(Volume * volptr, Vnode * targetptr, struct AFSFid * Fid,
        errorCode = FDH_TRUNC(fdP, Pos);
     } else {
        /* have some data to copy */
-#if FS_STATS_DETAILED
        (*a_bytesToStoreP) = Length;
-#endif /* FS_STATS_DETAILED */
        while (1) {
            int rlen;
            if (bytesTransfered >= Length) {
@@ -7443,9 +6543,7 @@ StoreData_RXStyle(Volume * volptr, Vnode * targetptr, struct AFSFid * Fid,
                errorCode = -32;
                break;
            }
-#if FS_STATS_DETAILED
            (*a_bytesStoredP) += errorCode;
-#endif /* FS_STATS_DETAILED */
            rlen = errorCode;
 #ifndef HAVE_PIOV
            nBytes = FDH_PWRITE(fdP, tbuffer, rlen, Pos);
@@ -7465,9 +6563,10 @@ StoreData_RXStyle(Volume * volptr, Vnode * targetptr, struct AFSFid * Fid,
     FreeSendBuffer((struct afs_buffer *)tbuffer);
 #endif /* HAVE_PIOV */
     if (sync) {
-       FDH_SYNC(fdP);
+       (void) FDH_SYNC(fdP);
     }
     if (errorCode) {
+       Error tmp_errorCode = 0;
        afs_sfsize_t nfSize = FDH_SIZE(fdP);
        osi_Assert(nfSize >= 0);
        /* something went wrong: adjust size and return */
@@ -7476,26 +6575,15 @@ StoreData_RXStyle(Volume * volptr, Vnode * targetptr, struct AFSFid * Fid,
         * need to update the target vnode.
         */
        targetptr->changed_newTime = 1;
-       if (origfdP && (bytesTransfered < Length))      /* Need to "finish" CopyOnWrite still */
-           CopyOnWrite2(origfdP, fdP, Pos + bytesTransfered, NewLength - Pos - bytesTransfered);
-       if (origfdP) FDH_CLOSE(origfdP);
        FDH_CLOSE(fdP);
        /* set disk usage to be correct */
-       VAdjustDiskUsage(&errorCode, volptr,
+       VAdjustDiskUsage(&tmp_errorCode, volptr,
                         (afs_sfsize_t) (nBlocks(nfSize) -
                                         nBlocks(NewLength)), 0);
-       return errorCode;
-    }
-    if (origfdP) {                                     /* finish CopyOnWrite */
-       if ( (CoW_off = Pos + Length) < NewLength) {
-           errorCode = CopyOnWrite2(origfdP, fdP, CoW_off, CoW_len = NewLength - CoW_off);
-           ViceLog(1, ("StoreData : CopyOnWrite2 on vnode %u.%u (%s) "
-                       "off 0x%llx size 0x%llx returns %d\n",
-                        afs_printable_VolumeId_u(V_id(volptr)),
-                       afs_printable_VnodeId_u(targetptr->vnodeNumber),
-                       V_name(volptr), CoW_off, CoW_len, errorCode));
+       if (tmp_errorCode) {
+           errorCode = tmp_errorCode;
        }
-       FDH_CLOSE(origfdP);
+       return errorCode;
     }
     FDH_CLOSE(fdP);