viced: Check vnode length on Rename and Link
[openafs.git] / src / viced / afsfileprocs.c
index 6b01518..b2dac04 100644 (file)
 
 #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/assert.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"
@@ -118,17 +106,6 @@ extern void FidZero(DirHandle * file);
 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 */
 
 #define        DONTCHECK       0
@@ -287,6 +264,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.
@@ -346,7 +382,7 @@ CallPreamble(struct rx_call *acall, int activecall,
        code = hpr_Initialize(&uclient);
 
        if (!code)
-           assert(pthread_setspecific(viced_uclient_key, (void *)uclient) == 0);
+           osi_Assert(pthread_setspecific(viced_uclient_key, (void *)uclient) == 0);
        H_LOCK;
 #else
        code = pr_Initialize(2, AFSDIR_SERVER_ETC_DIRPATH, 0);
@@ -470,7 +506,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,11 +526,18 @@ CheckVnode(AFSFid * fid, Volume ** volptr, Vnode ** vptr, int lock)
                VRESTARTING
 #endif
                ;
+#ifdef AFS_PTHREAD_ENV
+           static const struct timespec timeout_ts = { 0, 0 };
+           static const struct timespec * const ts = &timeout_ts;
+#else
+           static const struct timespec * const ts = NULL;
+#endif
 
            errorCode = 0;
-           *volptr = VGetVolumeNoWait(&local_errorCode, &errorCode, (afs_int32) fid->Volume);
+           *volptr = VGetVolumeWithCall(&local_errorCode, &errorCode,
+                                              fid->Volume, ts, cbv);
            if (!errorCode) {
-               assert(*volptr);
+               osi_Assert(*volptr);
                break;
            }
            if ((errorCode == VOFFLINE) && (VInit < 2)) {
@@ -586,7 +630,7 @@ CheckVnode(AFSFid * fid, Volume ** volptr, Vnode ** vptr, int lock)
                return (errorCode);
        }
     }
-    assert(*volptr);
+    osi_Assert(*volptr);
 
     /* get the vnode  */
     *vptr = VGetVnode(&errorCode, *volptr, fid->Vnode, lock);
@@ -594,13 +638,19 @@ CheckVnode(AFSFid * fid, Volume ** volptr, Vnode ** vptr, int lock)
        return (errorCode);
     if ((*vptr)->disk.uniquifier != fid->Unique) {
        VPutVnode(&fileCode, *vptr);
-       assert(fileCode == 0);
+       osi_Assert(fileCode == 0);
        *vptr = 0;
        return (VNOVNODE);      /* return the right error code, at least */
     }
     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
@@ -618,7 +668,7 @@ SetAccessList(Vnode ** targetptr, Volume ** volume,
        *ACLSize = VAclSize(*targetptr);
        return (0);
     } else {
-       assert(Fid != 0);
+       osi_Assert(Fid != 0);
        while (1) {
            VnodeId parentvnode;
            Error errorCode = 0;
@@ -702,7 +752,7 @@ GetRights(struct client *client, struct acl_accessList *ACL,
     while (client->host->hostFlags & HCPS_INPROGRESS) {
        client->host->hostFlags |= HCPS_WAITING;        /* I am waiting */
 #ifdef AFS_PTHREAD_ENV
-       pthread_cond_wait(&client->host->cond, &host_glock_mutex);
+       CV_WAIT(&client->host->cond, &host_glock_mutex);
 #else /* AFS_PTHREAD_ENV */
        if ((code =
             LWP_WaitProcess(&(client->host->hostFlags))) != LWP_SUCCESS)
@@ -751,16 +801,16 @@ VanillaUser(struct client *client)
  * interface calls.
  */
 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_connection *tcon, struct VCallByVol *cbv,
+                         AFSFid * Fid, Volume ** volptr, Vnode ** targetptr,
+                         int chkforDir, Vnode ** parent, struct client **client,
+                         int locktype, afs_int32 * rights, afs_int32 * anyrights)
 {
     struct acl_accessList *aCL;        /* Internal access List */
     int aCLSize;               /* size of the access list */
     Error errorCode = 0;               /* return code to caller */
 
-    if ((errorCode = CheckVnode(Fid, volptr, targetptr, locktype)))
+    if ((errorCode = CheckVnodeWithCall(Fid, volptr, cbv, targetptr, locktype)))
        return (errorCode);
     if (chkforDir) {
        if (chkforDir == MustNOTBeDIR
@@ -776,7 +826,7 @@ GetVolumePackage(struct rx_connection *tcon, AFSFid * Fid, Volume ** volptr,
                       (chkforDir == MustBeDIR ? 0 : locktype))) != 0)
        return (errorCode);
     if (chkforDir == MustBeDIR)
-       assert((*parent) == 0);
+       osi_Assert((*parent) == 0);
     if (!(*client)) {
        if ((errorCode = GetClient(tcon, client)) != 0)
            return (errorCode);
@@ -801,37 +851,57 @@ GetVolumePackage(struct rx_connection *tcon, AFSFid * Fid, Volume ** volptr,
 
 }                              /*GetVolumePackage */
 
+static_inline 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)
+{
+    return GetVolumePackageWithCall(tcon, NULL, Fid, volptr, targetptr,
+                                    chkforDir, parent, client, locktype,
+                                    rights, anyrights);
+}
+
 
 /*
  * 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!
  */
 static void
-PutVolumePackage(Vnode * parentwhentargetnotdir, Vnode * targetptr,
-                Vnode * parentptr, Volume * volptr, struct client **client)
+PutVolumePackageWithCall(Vnode * parentwhentargetnotdir, Vnode * targetptr,
+                         Vnode * parentptr, Volume * volptr,
+                         struct client **client, struct VCallByVol *cbv)
 {
     Error fileCode = 0;                /* Error code returned by the volume package */
 
     if (parentwhentargetnotdir) {
        VPutVnode(&fileCode, parentwhentargetnotdir);
-       assert(!fileCode || (fileCode == VSALVAGE));
+       osi_Assert(!fileCode || (fileCode == VSALVAGE));
     }
     if (targetptr) {
        VPutVnode(&fileCode, targetptr);
-       assert(!fileCode || (fileCode == VSALVAGE));
+       osi_Assert(!fileCode || (fileCode == VSALVAGE));
     }
     if (parentptr) {
        VPutVnode(&fileCode, parentptr);
-       assert(!fileCode || (fileCode == VSALVAGE));
+       osi_Assert(!fileCode || (fileCode == VSALVAGE));
     }
     if (volptr) {
-       VPutVolume(volptr);
+       VPutVolumeWithCall(volptr, cbv);
     }
     if (*client) {
        PutClient(client);
     }
 }                              /*PutVolumePackage */
 
+static_inline void
+PutVolumePackage(Vnode * parentwhentargetnotdir, Vnode * targetptr,
+                Vnode * parentptr, Volume * volptr, struct client **client)
+{
+    PutVolumePackageWithCall(parentwhentargetnotdir, targetptr, parentptr,
+                             volptr, client, NULL);
+}
+
 static int
 VolumeOwner(struct client *client, Vnode * targetptr)
 {
@@ -891,7 +961,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
@@ -1174,7 +1245,7 @@ CopyOnWrite(Vnode * targetptr, Volume * volptr, afs_foff_t off, afs_fsize_t len)
     }
     IH_INIT(newH, V_device(volptr), V_id(volptr), ino);
     newFdP = IH_OPEN(newH);
-    assert(newFdP != NULL);
+    osi_Assert(newFdP != NULL);
 
     done = off;
     while (size > 0) {
@@ -1249,11 +1320,11 @@ CopyOnWrite(Vnode * targetptr, Volume * volptr, afs_foff_t off, afs_fsize_t len)
     FDH_REALLYCLOSE(targFdP);
     rc = IH_DEC(V_linkHandle(volptr), VN_GET_INO(targetptr),
                V_parentId(volptr));
-    assert(!rc);
+    osi_Assert(!rc);
     IH_RELEASE(targetptr->handle);
 
     rc = FDH_SYNC(newFdP);
-    assert(rc == 0);
+    osi_Assert(rc == 0);
     FDH_CLOSE(newFdP);
     targetptr->handle = newH;
     VN_SET_INO(targetptr, ino);
@@ -1324,6 +1395,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_r(volptr);
+       return VSALVAGE;
+    }
+
     if (parentptr->disk.cloned) {
        ViceLog(25, ("DeleteTarget : CopyOnWrite called\n"));
        if ((errorCode = CopyOnWrite(parentptr, volptr, 0, MAXFSIZE))) {
@@ -1354,7 +1431,7 @@ DeleteTarget(Vnode * parentptr, Volume * volptr, Vnode ** targetptr,
     } else if ((*targetptr)->disk.type == vDirectory)
        return (EISDIR);
 
-    /*assert((*targetptr)->disk.uniquifier == fileFid->Unique); */
+    /*osi_Assert((*targetptr)->disk.uniquifier == fileFid->Unique); */
     /**
       * If the uniquifiers dont match then instead of asserting
       * take the volume offline and return VSALVAGE
@@ -1730,11 +1807,17 @@ Alloc_NewVnode(Vnode * parentptr, DirHandle * dir, Volume * volptr,
         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);
     }
 
+    if (CheckLength(volptr, parentptr, -1)) {
+       VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
+       VTakeOffline_r(volptr);
+       return VSALVAGE;
+    }
+
     *targetptr = VAllocVnode(&errorCode, volptr, FileType);
     if (errorCode != 0) {
        VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
@@ -1945,30 +2028,26 @@ RXGetVolumeStatus(AFSFetchVolumeStatus * status, char **name, char **offMsg,
     temp = strlen(V_name(volptr)) + 1;
     *name = malloc(temp);
     if (!*name) {
-       ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
-       assert(0);
+       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"));
-       assert(0);
+       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"));
-       assert(0);
+       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"));
-       assert(0);
+       ViceLogThenPanic(0, ("Failed malloc in RXGetVolumeStatus\n"));
     }
     strcpy(*motd, V_motd(volptr));
 #endif /* FS_STATS_DETAILED */
@@ -2057,8 +2136,7 @@ AllocSendBuffer(void)
        FS_UNLOCK;
        tmp = malloc(sendBufSize);
        if (!tmp) {
-           ViceLog(0, ("Failed malloc in AllocSendBuffer\n"));
-           assert(0);
+           ViceLogThenPanic(0, ("Failed malloc in AllocSendBuffer\n"));
        }
        return tmp;
     }
@@ -2139,6 +2217,7 @@ 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 */
+    struct VCallByVol tcbv, *cbv = NULL;
 #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 */
@@ -2178,12 +2257,17 @@ 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(tcon, cbv, Fid, &volptr, &targetptr, DONTCHECK,
                          &parentwhentargetnotdir, &client, READ_LOCK,
                          &rights, &anyrights)))
        goto Bad_FetchData;
@@ -2217,7 +2301,7 @@ common_FetchData64(struct rx_call *acall, struct AFSFid *Fid,
     if (parentwhentargetnotdir != NULL) {
        tparentwhentargetnotdir = *parentwhentargetnotdir;
        VPutVnode(&fileCode, parentwhentargetnotdir);
-       assert(!fileCode || (fileCode == VSALVAGE));
+       osi_Assert(!fileCode || (fileCode == VSALVAGE));
        parentwhentargetnotdir = NULL;
     }
 #if FS_STATS_DETAILED
@@ -2321,8 +2405,8 @@ 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(parentwhentargetnotdir, targetptr,
+                                   (Vnode *) 0, volptr, &client, cbv);
     ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode));
     errorCode = CallPostamble(tcon, errorCode, thost);
 
@@ -2428,8 +2512,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"));
-       assert(0);
+       ViceLogThenPanic(0, ("Failed malloc in SRXAFS_FetchACL\n"));
     }
 
     /*
@@ -2618,15 +2701,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"));
-       assert(0);
+       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"));
-       assert(0);
+       ViceLogThenPanic(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
     }
     CallBacks->AFSCBs_len = nfiles;
 
@@ -2769,15 +2850,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"));
-       assert(0);
+       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"));
-       assert(0);
+       ViceLogThenPanic(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
     }
     CallBacks->AFSCBs_len = nfiles;
 
@@ -3048,7 +3127,7 @@ common_StoreData64(struct rx_call *acall, struct AFSFid *Fid,
     if (parentwhentargetnotdir != NULL) {
        tparentwhentargetnotdir = *parentwhentargetnotdir;
        VPutVnode(&fileCode, parentwhentargetnotdir);
-       assert(!fileCode || (fileCode == VSALVAGE));
+       osi_Assert(!fileCode || (fileCode == VSALVAGE));
        parentwhentargetnotdir = NULL;
     }
 #if FS_STATS_DETAILED
@@ -3289,7 +3368,7 @@ SRXAFS_StoreACL(struct rx_call * acall, struct AFSFid * Fid,
 
     /* convert the write lock to a read lock before breaking callbacks */
     VVnodeWriteToRead(&errorCode, targetptr);
-    assert(!errorCode || errorCode == VSALVAGE);
+    osi_Assert(!errorCode || errorCode == VSALVAGE);
 
     /* break call backs on the directory  */
     BreakCallBack(client->host, Fid, 0);
@@ -3395,7 +3474,7 @@ SAFSS_StoreStatus(struct rx_call *acall, struct AFSFid *Fid,
 
     /* convert the write lock to a read lock before breaking callbacks */
     VVnodeWriteToRead(&errorCode, targetptr);
-    assert(!errorCode || errorCode == VSALVAGE);
+    osi_Assert(!errorCode || errorCode == VSALVAGE);
 
     /* Break call backs on Fid */
     BreakCallBack(client->host, Fid, 0);
@@ -3552,14 +3631,14 @@ SAFSS_RemoveFile(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
        DeleteFileCallBacks(&fileFid);
        /* convert the parent lock to a read lock before breaking callbacks */
        VVnodeWriteToRead(&errorCode, parentptr);
-       assert(!errorCode || errorCode == VSALVAGE);
+       osi_Assert(!errorCode || errorCode == VSALVAGE);
     } else {
        /* convert the parent lock to a read lock before breaking callbacks */
        VVnodeWriteToRead(&errorCode, parentptr);
-       assert(!errorCode || errorCode == VSALVAGE);
+       osi_Assert(!errorCode || errorCode == VSALVAGE);
        /* convert the target lock to a read lock before breaking callbacks */
        VVnodeWriteToRead(&errorCode, targetptr);
-       assert(!errorCode || errorCode == VSALVAGE);
+       osi_Assert(!errorCode || errorCode == VSALVAGE);
        /* tell all the file has changed */
        BreakCallBack(client->host, &fileFid, 1);
     }
@@ -3724,7 +3803,7 @@ SAFSS_CreateFile(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
 
     /* convert the write lock to a read lock before breaking callbacks */
     VVnodeWriteToRead(&errorCode, parentptr);
-    assert(!errorCode || errorCode == VSALVAGE);
+    osi_Assert(!errorCode || errorCode == VSALVAGE);
 
     /* break call back on parent dir */
     BreakCallBack(client->host, DirFid, 0);
@@ -3928,6 +4007,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
@@ -4072,7 +4158,7 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
            }
            if (testnode == 1) top = 1;
            testvptr = VGetVnode(&errorCode, volptr, testnode, READ_LOCK);
-           assert(errorCode == 0);
+           osi_Assert(errorCode == 0);
            testnode = testvptr->disk.parent;
            VPutVnode(&errorCode, testvptr);
            if ((top == 1) && (testnode != 0)) {
@@ -4083,7 +4169,7 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
                errorCode = EIO;
                goto Bad_Rename;
            }
-           assert(errorCode == 0);
+           osi_Assert(errorCode == 0);
        }
     }
 
@@ -4118,7 +4204,7 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
     if (newfileptr) {
        /* Delete NewName from its directory */
        code = Delete(&newdir, NewName);
-       assert(code == 0);
+       osi_Assert(code == 0);
 
        /* Drop the link count */
        newfileptr->disk.linkCount--;
@@ -4165,7 +4251,7 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
        goto Bad_Rename;
 
     /* Delete the old name */
-    assert(Delete(&olddir, (char *)OldName) == 0);
+    osi_Assert(Delete(&olddir, (char *)OldName) == 0);
 
     /* if the directory length changes, reflect it in the statistics */
 #if FS_STATS_DETAILED
@@ -4191,13 +4277,13 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
     /* if we are dealing with a rename of a directory, and we need to
      * update the .. entry of that directory */
     if (updatefile) {
-       assert(!fileptr->disk.cloned);
+       osi_Assert(!fileptr->disk.cloned);
 
        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 */
-       assert(Create(&filedir, "..", NewDirFid) == 0);
+       osi_Assert(Create(&filedir, "..", NewDirFid) == 0);
        fileptr->disk.dataVersion++;
 
        /* if the parent directories are different the link counts have to be   */
@@ -4219,15 +4305,15 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
 
     /* convert the write locks to a read locks before breaking callbacks */
     VVnodeWriteToRead(&errorCode, newvptr);
-    assert(!errorCode || errorCode == VSALVAGE);
+    osi_Assert(!errorCode || errorCode == VSALVAGE);
     if (oldvptr != newvptr) {
        VVnodeWriteToRead(&errorCode, oldvptr);
-       assert(!errorCode || errorCode == VSALVAGE);
+       osi_Assert(!errorCode || errorCode == VSALVAGE);
     }
     if (newfileptr && !doDelete) {
        /* convert the write lock to a read lock before breaking callbacks */
        VVnodeWriteToRead(&errorCode, newfileptr);
-       assert(!errorCode || errorCode == VSALVAGE);
+       osi_Assert(!errorCode || errorCode == VSALVAGE);
     }
 
     /* break call back on NewDirFid, OldDirFid, NewDirFid and newFileFid  */
@@ -4257,7 +4343,7 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
   Bad_Rename:
     if (newfileptr) {
        VPutVnode(&fileCode, newfileptr);
-       assert(fileCode == 0);
+       osi_Assert(fileCode == 0);
     }
     (void)PutVolumePackage(fileptr, (newvptr && newvptr != oldvptr ?
                                     newvptr : 0), oldvptr, volptr, &client);
@@ -4464,7 +4550,7 @@ SAFSS_Symlink(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
 
     /* convert the write lock to a read lock before breaking callbacks */
     VVnodeWriteToRead(&errorCode, parentptr);
-    assert(!errorCode || errorCode == VSALVAGE);
+    osi_Assert(!errorCode || errorCode == VSALVAGE);
 
     /* break call back on the parent dir */
     BreakCallBack(client->host, DirFid, 0);
@@ -4618,6 +4704,12 @@ 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))) {
@@ -4664,9 +4756,9 @@ SAFSS_Link(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
 
     /* convert the write locks to read locks before breaking callbacks */
     VVnodeWriteToRead(&errorCode, targetptr);
-    assert(!errorCode || errorCode == VSALVAGE);
+    osi_Assert(!errorCode || errorCode == VSALVAGE);
     VVnodeWriteToRead(&errorCode, parentptr);
-    assert(!errorCode || errorCode == VSALVAGE);
+    osi_Assert(!errorCode || errorCode == VSALVAGE);
 
     /* break call back on DirFid */
     BreakCallBack(client->host, DirFid, 0);
@@ -4844,10 +4936,10 @@ SAFSS_MakeDir(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
 #endif /* FS_STATS_DETAILED */
 
     /* Point to target's ACL buffer and copy the parent's ACL contents to it */
-    assert((SetAccessList
+    osi_Assert((SetAccessList
            (&targetptr, &volptr, &newACL, &newACLSize,
             &parentwhentargetnotdir, (AFSFid *) 0, 0)) == 0);
-    assert(parentwhentargetnotdir == 0);
+    osi_Assert(parentwhentargetnotdir == 0);
     memcpy((char *)newACL, (char *)VVnodeACL(parentptr), VAclSize(parentptr));
 
     /* update the status for the target vnode */
@@ -4856,7 +4948,7 @@ SAFSS_MakeDir(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
 
     /* Actually create the New directory in the directory package */
     SetDirHandle(&dir, targetptr);
-    assert(!(MakeDir(&dir, (afs_int32 *)OutFid, (afs_int32 *)DirFid)));
+    osi_Assert(!(MakeDir(&dir, (afs_int32 *)OutFid, (afs_int32 *)DirFid)));
     DFlush();
     VN_SET_LEN(targetptr, (afs_fsize_t) Length(&dir));
 
@@ -4866,7 +4958,7 @@ SAFSS_MakeDir(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
 
     /* convert the write lock to a read lock before breaking callbacks */
     VVnodeWriteToRead(&errorCode, parentptr);
-    assert(!errorCode || errorCode == VSALVAGE);
+    osi_Assert(!errorCode || errorCode == VSALVAGE);
 
     /* break call back on DirFid */
     BreakCallBack(client->host, DirFid, 0);
@@ -5032,7 +5124,7 @@ SAFSS_RemoveDir(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
 
     /* convert the write lock to a read lock before breaking callbacks */
     VVnodeWriteToRead(&errorCode, parentptr);
-    assert(!errorCode || errorCode == VSALVAGE);
+    osi_Assert(!errorCode || errorCode == VSALVAGE);
 
     /* break call back on DirFid and fileFid */
     BreakCallBack(client->host, DirFid, 0);
@@ -5417,7 +5509,7 @@ SAFSS_ReleaseLock(struct rx_call *acall, struct AFSFid *Fid,
     if (targetptr->disk.lock.lockCount <= 0) {
        /* convert the write lock to a read lock before breaking callbacks */
        VVnodeWriteToRead(&errorCode, targetptr);
-       assert(!errorCode || errorCode == VSALVAGE);
+       osi_Assert(!errorCode || errorCode == VSALVAGE);
        BreakCallBack(client->host, Fid, 0);
     }
 
@@ -7067,6 +7159,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;
     }
@@ -7077,7 +7174,7 @@ FetchData_RXStyle(Volume * volptr, Vnode * targetptr,
     {
        afs_int32 high, low;
        SplitOffsetOrSize(Len, high, low);
-       assert(Int64Mode || (Len >= 0 && high == 0) || Len < 0);
+       osi_Assert(Int64Mode || (Len >= 0 && high == 0) || Len < 0);
        if (Int64Mode) {
            high = htonl(high);
            rx_Write(Call, (char *)&high, sizeof(afs_int32));   /* High order bits */
@@ -7135,10 +7232,15 @@ FetchData_RXStyle(Volume * volptr, Vnode * targetptr,
        (*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;
@@ -7184,11 +7286,7 @@ GetLinkCountAndSize(Volume * vp, FdHandle_t * fdP, int *lc,
     lhp = IH_OPEN(V_linkHandle(vp));
     if (!lhp)
        return EIO;
-#ifdef AFS_NT40_ENV
-    *lc = nt_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0);
-#else
-    *lc = namei_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0);
-#endif
+    *lc = namei_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0, 0, 1);
     FDH_CLOSE(lhp);
     if (*lc < 0)
        return -1;
@@ -7302,6 +7400,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;
@@ -7350,7 +7453,7 @@ StoreData_RXStyle(Volume * volptr, Vnode * targetptr, struct AFSFid * Fid,
            if (fdP == NULL) {
                ViceLog(25,
                        ("StoreData : Reopen after CopyOnWrite failed\n"));
-               FDH_CLOSE(origfdP);
+               FDH_REALLYCLOSE(origfdP);
                return ENOENT;
            }
        }
@@ -7382,7 +7485,7 @@ StoreData_RXStyle(Volume * volptr, Vnode * targetptr, struct AFSFid * Fid,
         AdjustDiskUsage(volptr, adjustSize,
                         adjustSize - SpareComp(volptr)))) {
        FDH_CLOSE(fdP);
-       if (origfdP) FDH_CLOSE(origfdP);
+       if (origfdP) FDH_REALLYCLOSE(origfdP);
        return (errorCode);
     }
 
@@ -7473,7 +7576,7 @@ StoreData_RXStyle(Volume * volptr, Vnode * targetptr, struct AFSFid * Fid,
     }
     if (errorCode) {
        afs_sfsize_t nfSize = FDH_SIZE(fdP);
-       assert(nfSize >= 0);
+       osi_Assert(nfSize >= 0);
        /* something went wrong: adjust size and return */
        VN_SET_LEN(targetptr, nfSize);  /* set new file size. */
        /* changed_newTime is tested in StoreData to detemine if we
@@ -7482,7 +7585,7 @@ StoreData_RXStyle(Volume * volptr, Vnode * targetptr, struct AFSFid * Fid,
        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);
+       if (origfdP) FDH_REALLYCLOSE(origfdP);
        FDH_CLOSE(fdP);
        /* set disk usage to be correct */
        VAdjustDiskUsage(&errorCode, volptr,
@@ -7499,7 +7602,7 @@ StoreData_RXStyle(Volume * volptr, Vnode * targetptr, struct AFSFid * Fid,
                        afs_printable_VnodeId_u(targetptr->vnodeNumber),
                        V_name(volptr), CoW_off, CoW_len, errorCode));
        }
-       FDH_CLOSE(origfdP);
+       FDH_REALLYCLOSE(origfdP);
     }
     FDH_CLOSE(fdP);