windows-multi-fix-20061003
[openafs.git] / src / WINNT / afsd / cm_dcache.c
index 40f3cb4..9363f1b 100644 (file)
 #include <afs/param.h>
 #include <afs/stds.h>
 
-#ifndef DJGPP
 #include <windows.h>
 #include <winsock2.h>
 #include <nb30.h>
-#endif /* !DJGPP */
 #ifdef COMMENT
 #include <malloc.h>
 #endif
@@ -33,6 +31,16 @@ osi_mutex_t cm_bufGetMutex;
 extern osi_mutex_t cm_Freelance_Lock;
 #endif
 
+#ifdef AFS_LARGEFILES
+/* we can access connp->serverp without holding a lock because that
+   never changes since the connection is made. */
+#define SERVERHAS64BIT(connp) (!((connp)->serverp->flags & CM_SERVERFLAG_NO64BIT))
+#define SET_SERVERHASNO64BIT(connp) (cm_SetServerNo64Bit((connp)->serverp, TRUE))
+#else
+#define SERVERHAS64BIT(connp) (FALSE)
+#define SET_SERVERHASNO64BIT(connp) (FALSE)
+#endif
+
 /* functions called back from the buffer package when reading or writing data,
  * or when holding or releasing a vnode pointer.
  */
@@ -56,13 +64,15 @@ long cm_BufWrite(void *vfidp, osi_hyper_t *offsetp, long length, long flags,
     AFSVolSync volSync;
     AFSFid tfid;
     struct rx_call *callp;
+    struct rx_connection *rxconnp;
     osi_queueData_t *qdp;
     cm_buf_t *bufp;
     long wbytes;
     char *bufferp;
     cm_conn_t *connp;
-    long truncPos;
+    osi_hyper_t truncPos;
     cm_bulkIO_t biod;          /* bulk IO descriptor */
+    int require_64bit_ops = 0;
 
     osi_assert(userp != NULL);
 
@@ -71,13 +81,19 @@ long cm_BufWrite(void *vfidp, osi_hyper_t *offsetp, long length, long flags,
      * buffer, although more likely it will just return a new, empty, buffer.
      */
     scp = cm_FindSCache(fidp);
-    if (scp == NULL)
+    if (scp == NULL) {
         return CM_ERROR_NOSUCHFILE;    /* shouldn't happen */
+    }
 
     cm_AFSFidFromFid(&tfid, fidp);
 
     lock_ObtainMutex(&scp->mx);
-        
+    if (scp->flags & CM_SCACHEFLAG_DELETED) {
+       lock_ReleaseMutex(&scp->mx);
+        cm_ReleaseSCache(scp);
+       return CM_ERROR_NOSUCHFILE;
+    }
+
     code = cm_SetupStoreBIOD(scp, offsetp, length, &biod, userp, reqp);
     if (code) {
         osi_Log1(afsd_logp, "cm_SetupStoreBIOD code %x", code);
@@ -92,7 +108,7 @@ long cm_BufWrite(void *vfidp, osi_hyper_t *offsetp, long length, long flags,
         cm_ReleaseBIOD(&biod, 1);      /* should be a NOOP */
         cm_ReleaseSCache(scp);
         return 0;
-    }   
+    }
 
     /* Serialize StoreData RPC's; for rationale see cm_scache.c */
     (void) cm_SyncOp(scp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA_EXCL);
@@ -100,10 +116,10 @@ long cm_BufWrite(void *vfidp, osi_hyper_t *offsetp, long length, long flags,
     /* prepare the output status for the store */
     scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
     cm_StatusFromAttr(&inStatus, scp, NULL);
-    truncPos = scp->length.LowPart;
+    truncPos = scp->length;
     if ((scp->mask & CM_SCACHEMASK_TRUNCPOS)
-         && scp->truncPos.LowPart < (unsigned long) truncPos)
-        truncPos = scp->truncPos.LowPart;
+        && LargeIntegerLessThan(scp->truncPos, truncPos))
+        truncPos = scp->truncPos;
        scp->mask &= ~CM_SCACHEMASK_TRUNCPOS;
                 
     /* compute how many bytes to write from this buffer */
@@ -116,27 +132,66 @@ long cm_BufWrite(void *vfidp, osi_hyper_t *offsetp, long length, long flags,
         /* otherwise write out part of buffer before EOF, but not
          * more than bufferSize bytes.
          */
-        nbytes = thyper.LowPart;
-        if (nbytes > biod.length) 
+        if (LargeIntegerGreaterThan(thyper,
+                                    ConvertLongToLargeInteger(biod.length))) {
             nbytes = biod.length;
+        } else {
+            /* if thyper is less than or equal to biod.length, then we
+               can safely assume that the value fits in a long. */
+            nbytes = thyper.LowPart;
+        }
     }
 
-    lock_ReleaseMutex(&scp->mx);
+    if (LargeIntegerGreaterThan(LargeIntegerAdd(biod.offset,
+                                                 ConvertLongToLargeInteger(nbytes)),
+                                 ConvertLongToLargeInteger(LONG_MAX)) ||
+         LargeIntegerGreaterThan(truncPos,
+                                 ConvertLongToLargeInteger(LONG_MAX))) {
+        require_64bit_ops = 1;
+    }
         
+    lock_ReleaseMutex(&scp->mx);
+
     /* now we're ready to do the store operation */
     do {
         code = cm_Conn(&scp->fid, userp, reqp, &connp);
         if (code) 
             continue;
-               
-        callp = rx_NewCall(connp->callp);
 
-        osi_Log3(afsd_logp, "CALL StoreData vp %x, off 0x%x, size 0x%x",
-                 (long) scp, biod.offset.LowPart, nbytes);
+    retry:
+        rxconnp = cm_GetRxConn(connp);
+        callp = rx_NewCall(rxconnp);
+        rx_PutConnection(rxconnp);
+
+#ifdef AFS_LARGEFILES
+        if (SERVERHAS64BIT(connp)) {
+            osi_Log4(afsd_logp, "CALL StoreData64 scp 0x%p, offset 0x%x:%08x, length 0x%x",
+                     scp, biod.offset.HighPart, biod.offset.LowPart, nbytes);
+
+            code = StartRXAFS_StoreData64(callp, &tfid, &inStatus,
+                                          biod.offset.QuadPart,
+                                          nbytes,
+                                          truncPos.QuadPart);
+        } else {
+
+            if (require_64bit_ops) {
+                osi_Log0(afsd_logp, "Skipping StoreData.  The operation requires StoreData64");
+                code = CM_ERROR_TOOBIG;
+            } else {
+                osi_Log4(afsd_logp, "CALL StoreData scp 0x%p, offset 0x%x:%08x, length 0x%x",
+                         scp, biod.offset.HighPart, biod.offset.LowPart, nbytes);
+
+                code = StartRXAFS_StoreData(callp, &tfid, &inStatus,
+                                            biod.offset.LowPart, nbytes, truncPos.LowPart);
+            }
+        }
+#else
+        osi_Log4(afsd_logp, "CALL StoreData scp 0x%p, offset 0x%x:%08x, length 0x%x",
+                 scp, biod.offset.HighPart, biod.offset.LowPart, nbytes);
 
-        lock_ObtainMutex(&connp->mx);
         code = StartRXAFS_StoreData(callp, &tfid, &inStatus,
-                                    biod.offset.LowPart, nbytes, truncPos);
+                                    biod.offset.LowPart, nbytes, truncPos.LowPart);
+#endif
 
         if (code == 0) {
             /* write the data from the the list of buffers */
@@ -150,43 +205,62 @@ long cm_BufWrite(void *vfidp, osi_hyper_t *offsetp, long length, long flags,
                 bufp = osi_GetQData(qdp);
                 bufferp = bufp->datap;
                 wbytes = nbytes;
-                if (wbytes > buf_bufferSize) 
-                    wbytes = buf_bufferSize;
+                if (wbytes > cm_data.buf_blockSize) 
+                    wbytes = cm_data.buf_blockSize;
 
                 /* write out wbytes of data from bufferp */
                 temp = rx_Write(callp, bufferp, wbytes);
                 if (temp != wbytes) {
-                    osi_Log2(afsd_logp, "rx_Write failed %d != %d",temp,wbytes);
+                    osi_Log3(afsd_logp, "rx_Write failed bp 0x%p, %d != %d",bufp,temp,wbytes);
                     code = -1;
                     break;
                 } else {
-                    osi_Log1(afsd_logp, "rx_Write succeeded %d",temp);
+                    osi_Log2(afsd_logp, "rx_Write succeeded bp 0x%p, %d",bufp,temp);
                 }       
                 nbytes -= wbytes;
             }  /* while more bytes to write */
         }              /* if RPC started successfully */
         else {
-            osi_Log1(afsd_logp, "StartRXAFS_StoreData failed (%lX)",code);
+            osi_Log2(afsd_logp, "StartRXAFS_StoreData?? scp 0x%p failed (%lX)",scp,code);
         }
+
         if (code == 0) {
-            code = EndRXAFS_StoreData(callp, &outStatus, &volSync);
-            if (code)
-                osi_Log1(afsd_logp, "EndRXAFS_StoreData failed (%lX)",code);
+            if (SERVERHAS64BIT(connp)) {
+                code = EndRXAFS_StoreData64(callp, &outStatus, &volSync);
+                if (code)
+                    osi_Log2(afsd_logp, "EndRXAFS_StoreData64 scp 0x%p failed (%lX)", scp, code);
+            } else {
+                code = EndRXAFS_StoreData(callp, &outStatus, &volSync);
+                if (code)
+                    osi_Log2(afsd_logp, "EndRXAFS_StoreData scp 0x%p failed (%lX)",scp,code);
+            }
         }
+
         code = rx_EndCall(callp, code);
-        lock_ReleaseMutex(&connp->mx);
 
-        osi_Log0(afsd_logp, "CALL StoreData DONE");
+#ifdef AFS_LARGEFILES
+        if (code == RXGEN_OPCODE && SERVERHAS64BIT(connp)) {
+            SET_SERVERHASNO64BIT(connp);
+            goto retry;
+        }
+#endif
                 
     } while (cm_Analyze(connp, userp, reqp, &scp->fid, &volSync, NULL, NULL, code));
+
     code = cm_MapRPCError(code, reqp);
-        
+
+    if (code)
+        osi_Log2(afsd_logp, "CALL StoreData FAILURE scp 0x%p, code 0x%x", scp, code);
+    else
+        osi_Log1(afsd_logp, "CALL StoreData SUCCESS scp 0x%p", scp);
+
     /* now, clean up our state */
     lock_ObtainMutex(&scp->mx);
 
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STOREDATA_EXCL);
 
     if (code == 0) {
+        osi_hyper_t t;
         /* now, here's something a little tricky: in AFS 3, a dirty
          * length can't be directly stored, instead, a dirty chunk is
          * stored that sets the file's size (by writing and by using
@@ -205,8 +279,17 @@ long cm_BufWrite(void *vfidp, osi_hyper_t *offsetp, long length, long flags,
          * We have to turn off the length dirty bit as soon as we can,
          * so that we see updates made by other machines.
          */
-        if (outStatus.Length >= scp->length.LowPart)
+
+        if (SERVERHAS64BIT(connp)) {
+            t.LowPart = outStatus.Length;
+            t.HighPart = outStatus.Length_hi;
+        } else {
+            t = ConvertLongToLargeInteger(outStatus.Length);
+        }
+
+        if (LargeIntegerGreaterThanOrEqualTo(t, scp->length))
             scp->mask &= ~CM_SCACHEMASK_LENGTH;
+
         cm_MergeStatus(scp, &outStatus, &volSync, userp, 0);
     } else {
         if (code == CM_ERROR_SPACE)
@@ -233,9 +316,11 @@ long cm_StoreMini(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
     AFSVolSync volSync;
     AFSFid tfid;
     long code;
-    long truncPos;
+    osi_hyper_t truncPos;
     cm_conn_t *connp;
     struct rx_call *callp;
+    struct rx_connection *rxconnp;
+    int require_64bit_ops = 0;
 
     /* Serialize StoreData RPC's; for rationale see cm_scache.c */
     (void) cm_SyncOp(scp, NULL, userp, reqp, 0,
@@ -247,12 +332,18 @@ long cm_StoreMini(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
     scp->mask &= ~CM_SCACHEMASK_CLIENTMODTIME;
 
     /* calculate truncation position */
-    truncPos = scp->length.LowPart;
+    truncPos = scp->length;
     if ((scp->mask & CM_SCACHEMASK_TRUNCPOS)
-         && scp->truncPos.LowPart < (unsigned long) truncPos)
-        truncPos = scp->truncPos.LowPart;
+        && LargeIntegerLessThan(scp->truncPos, truncPos))
+        truncPos = scp->truncPos;
     scp->mask &= ~CM_SCACHEMASK_TRUNCPOS;
 
+    if (LargeIntegerGreaterThan(truncPos,
+                                ConvertLongToLargeInteger(LONG_MAX))) {
+
+        require_64bit_ops = 1;
+    }
+
     lock_ReleaseMutex(&scp->mx);
 
     cm_AFSFidFromFid(&tfid, &scp->fid);
@@ -262,18 +353,43 @@ long cm_StoreMini(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
         code = cm_Conn(&scp->fid, userp, reqp, &connp);
         if (code) 
             continue;
-               
-        callp = rx_NewCall(connp->callp);
 
-        lock_ObtainMutex(&connp->mx);
+    retry:     
+        rxconnp = cm_GetRxConn(connp);
+        callp = rx_NewCall(rxconnp);
+        rx_PutConnection(rxconnp);
+
+#ifdef AFS_LARGEFILES
+        if (SERVERHAS64BIT(connp)) {
+            code = StartRXAFS_StoreData64(callp, &tfid, &inStatus,
+                                          0, 0, truncPos.QuadPart);
+        } else {
+            if (require_64bit_ops) {
+                code = CM_ERROR_TOOBIG;
+            } else {
+                code = StartRXAFS_StoreData(callp, &tfid, &inStatus,
+                                            0, 0, truncPos.LowPart);
+            }
+        }
+#else
         code = StartRXAFS_StoreData(callp, &tfid, &inStatus,
-                                    0, 0, truncPos);
+                                    0, 0, truncPos.LowPart);
+#endif
 
-        if (code == 0)
-            code = EndRXAFS_StoreData(callp, &outStatus, &volSync);
+        if (code == 0) {
+            if (SERVERHAS64BIT(connp))
+                code = EndRXAFS_StoreData64(callp, &outStatus, &volSync);
+            else
+                code = EndRXAFS_StoreData(callp, &outStatus, &volSync);
+        }
         code = rx_EndCall(callp, code);
 
-        lock_ReleaseMutex(&connp->mx);
+#ifdef AFS_LARGEFILES
+        if (code == RXGEN_OPCODE && SERVERHAS64BIT(connp)) {
+            SET_SERVERHASNO64BIT(connp);
+            goto retry;
+        }
+#endif
 
     } while (cm_Analyze(connp, userp, reqp, &scp->fid, &volSync, NULL, NULL, code));
     code = cm_MapRPCError(code, reqp);
@@ -284,11 +400,19 @@ long cm_StoreMini(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STOREDATA_EXCL);
 
     if (code == 0) {
+        osi_hyper_t t;
         /*
          * For explanation of handling of CM_SCACHEMASK_LENGTH,
          * see cm_BufWrite().
          */
-        if (outStatus.Length >= scp->length.LowPart)
+        if (SERVERHAS64BIT(connp)) {
+            t.HighPart = outStatus.Length_hi;
+            t.LowPart = outStatus.Length;
+        } else {
+            t = ConvertLongToLargeInteger(outStatus.Length);
+        }
+
+        if (LargeIntegerGreaterThanOrEqualTo(t, scp->length))
             scp->mask &= ~CM_SCACHEMASK_LENGTH;
         cm_MergeStatus(scp, &outStatus, &volSync, userp, 0);
     }
@@ -298,7 +422,7 @@ long cm_StoreMini(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
 
 long cm_BufRead(cm_buf_t *bufp, long nbytes, long *bytesReadp, cm_user_t *userp)
 {
-    *bytesReadp = buf_bufferSize;
+    *bytesReadp = cm_data.buf_blockSize;
 
     /* now return a code that means that I/O is done */
     return 0;
@@ -332,6 +456,8 @@ long cm_BufUnstabilize(void *parmp, cm_user_t *userp)
         
     scp = parmp;
         
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_SETSIZE);
+
     lock_ReleaseMutex(&scp->mx);
         
     /* always succeeds */
@@ -345,12 +471,20 @@ cm_buf_ops_t cm_bufOps = {
     cm_BufUnstabilize
 };
 
-int cm_InitDCache(long chunkSize, long nbuffers)
+long cm_ValidateDCache(void)
+{
+    return buf_ValidateBuffers();
+}
+
+long cm_ShutdownDCache(void)
+{
+    return 0;
+}
+
+int cm_InitDCache(int newFile, long chunkSize, afs_uint64 nbuffers)
 {
     lock_InitializeMutex(&cm_bufGetMutex, "buf_Get mutex");
-    if (nbuffers) 
-        buf_nbuffers = nbuffers;
-    return buf_Init(&cm_bufOps);
+    return buf_Init(newFile, &cm_bufOps, nbuffers);
 }
 
 /* check to see if we have an up-to-date buffer.  The buffer must have
@@ -367,9 +501,7 @@ int cm_HaveBuffer(cm_scache_t *scp, cm_buf_t *bufp, int isBufLocked)
     int code;
     if (!cm_HaveCallback(scp))
         return 0;
-    if ((bufp->cmFlags
-          & (CM_BUF_CMFETCHING | CM_BUF_CMFULLYFETCHED))
-         == (CM_BUF_CMFETCHING | CM_BUF_CMFULLYFETCHED))
+    if ((bufp->cmFlags & (CM_BUF_CMFETCHING | CM_BUF_CMFULLYFETCHED)) == (CM_BUF_CMFETCHING | CM_BUF_CMFULLYFETCHED))
         return 1;
     if (bufp->dataVersion == scp->dataVersion)
         return 1;
@@ -431,11 +563,11 @@ long cm_CheckFetchRange(cm_scache_t *scp, osi_hyper_t *startBasep, long length,
         bp = buf_Find(scp, &tbase);
         /* We cheat slightly by not locking the bp mutex. */
         if (bp) {
-            if ((bp->cmFlags
-                  & (CM_BUF_CMFETCHING | CM_BUF_CMSTORING)) == 0
+            if ((bp->cmFlags & (CM_BUF_CMFETCHING | CM_BUF_CMSTORING)) == 0
                  && bp->dataVersion != scp->dataVersion)
                 stop = 1;
             buf_Release(bp);
+           bp = NULL;
         }
         else 
             stop = 1;
@@ -446,10 +578,10 @@ long cm_CheckFetchRange(cm_scache_t *scp, osi_hyper_t *startBasep, long length,
         if (stop) 
             break;
                 
-        toffset.LowPart = buf_bufferSize;
+        toffset.LowPart = cm_data.buf_blockSize;
         toffset.HighPart = 0;
         tbase = LargeIntegerAdd(toffset, tbase);
-        length -= buf_bufferSize;
+        length -= cm_data.buf_blockSize;
     }
         
     /* if we get here, either everything is fine or stop stopped us at a
@@ -469,29 +601,37 @@ long cm_CheckFetchRange(cm_scache_t *scp, osi_hyper_t *startBasep, long length,
     return code;
 }
 
-void cm_BkgStore(cm_scache_t *scp, long p1, long p2, long p3, long p4,
+void cm_BkgStore(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4,
                  cm_user_t *userp)
 {
     osi_hyper_t toffset;
     long length;
     cm_req_t req;
+    long code;
 
-    cm_InitReq(&req);
-    req.flags |= CM_REQ_NORETRY;
+    if (scp->flags & CM_SCACHEFLAG_DELETED) {
+       osi_Log4(afsd_logp, "Skipping BKG store - Deleted scp 0x%p, offset 0x%x:%08x, length 0x%x", scp, p2, p1, p3);
+    } else {
+       cm_InitReq(&req);
+#ifdef NO_BKG_RETRIES
+       req.flags |= CM_REQ_NORETRY;
+#endif
 
-    toffset.LowPart = p1;
-    toffset.HighPart = p2;
-    length = p3;
+       toffset.LowPart = p1;
+       toffset.HighPart = p2;
+       length = p3;
 
-    osi_Log2(afsd_logp, "Starting BKG store vp 0x%x, base 0x%x", scp, p1);
+       osi_Log4(afsd_logp, "Starting BKG store scp 0x%p, offset 0x%x:%08x, length 0x%x", scp, p2, p1, p3);
 
-    cm_BufWrite(&scp->fid, &toffset, length, /* flags */ 0, userp, &req);
+       code = cm_BufWrite(&scp->fid, &toffset, length, /* flags */ 0, userp, &req);
+    }
 
     lock_ObtainMutex(&scp->mx);
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_ASYNCSTORE);
     lock_ReleaseMutex(&scp->mx);
 }
 
+/* Called with scp locked */
 void cm_ClearPrefetchFlag(long code, cm_scache_t *scp, osi_hyper_t *base)
 {
     osi_hyper_t thyper;
@@ -527,7 +667,7 @@ void cm_BkgPrefetch(cm_scache_t *scp, long p1, long p2, long p3, long p4,
     base.HighPart = p2;
     length = p3;
         
-    osi_Log2(afsd_logp, "Starting BKG prefetch vp 0x%x, base 0x%x", scp, p1);
+    osi_Log2(afsd_logp, "Starting BKG prefetch scp 0x%p, base 0x%x", scp, p1);
 
     code = buf_Get(scp, &base, &bp);
 
@@ -583,7 +723,7 @@ void cm_ConsiderPrefetch(cm_scache_t *scp, osi_hyper_t *offsetp,
     if (code) 
         return;        /* can't find something to prefetch */
 
-    osi_Log2(afsd_logp, "BKG Prefetch request vp 0x%x, base 0x%x",
+    osi_Log2(afsd_logp, "BKG Prefetch request scp 0x%p, base 0x%x",
              scp, realBase.LowPart);
 
     cm_QueueBKGRequest(scp, cm_BkgPrefetch, realBase.LowPart,
@@ -625,11 +765,11 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
 
     /* reserve a chunk's worth of buffers */
     lock_ReleaseMutex(&scp->mx);
-    buf_ReserveBuffers(cm_chunkSize / buf_bufferSize);
+    buf_ReserveBuffers(cm_chunkSize / cm_data.buf_blockSize);
     lock_ObtainMutex(&scp->mx);
 
     bufp = NULL;
-    for (temp = 0; temp < inSize; temp += buf_bufferSize, bufp = NULL) {
+    for (temp = 0; temp < inSize; temp += cm_data.buf_blockSize) {
         thyper.HighPart = 0;
         thyper.LowPart = temp;
         tbase = LargeIntegerAdd(*inOffsetp, thyper);
@@ -649,7 +789,7 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
             if (code) {
                 lock_ReleaseMutex(&bufp->mx);
                 buf_Release(bufp);
-                buf_UnreserveBuffers(cm_chunkSize / buf_bufferSize);
+                buf_UnreserveBuffers(cm_chunkSize / cm_data.buf_blockSize);
                 return code;
             }   
                         
@@ -665,6 +805,7 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
             cm_SyncOpDone(scp, bufp, flags);
             lock_ReleaseMutex(&bufp->mx);
             buf_Release(bufp);
+           bufp = NULL;
         }       
     }
 
@@ -687,9 +828,10 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
     osi_QAddH((osi_queue_t **) &biop->bufListp,
               (osi_queue_t **) &biop->bufListEndp,
               &qdp->q);
-    biop->length = buf_bufferSize;
+    biop->length = cm_data.buf_blockSize;
     firstModOffset = bufp->offset;
     biop->offset = firstModOffset;
+    bufp = NULL;       /* this buffer and reference added to the queue */
 
     /* compute the window surrounding *inOffsetp of size cm_chunkSize */
     scanStart = *inOffsetp;
@@ -705,8 +847,8 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
         | CM_SCACHESYNC_NOWAIT;
 
     /* start by looking backwards until scanStart */
-    thyper.HighPart = 0;               /* hyper version of buf_bufferSize */
-    thyper.LowPart = buf_bufferSize;
+    thyper.HighPart = 0;               /* hyper version of cm_data.buf_blockSize */
+    thyper.LowPart = cm_data.buf_blockSize;
     tbase = LargeIntegerSubtract(firstModOffset, thyper);
     while(LargeIntegerGreaterThanOrEqualTo(tbase, scanStart)) {
         /* see if we can find the buffer */
@@ -715,9 +857,12 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
             break;
 
         /* try to lock it, and quit if we can't (simplifies locking) */
+        lock_ReleaseMutex(&scp->mx);
         code = lock_TryMutex(&bufp->mx);
+        lock_ObtainMutex(&scp->mx);
         if (code == 0) {
             buf_Release(bufp);
+           bufp = NULL;
             break;
         }
                 
@@ -725,6 +870,7 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
         if (code) {
             lock_ReleaseMutex(&bufp->mx);
             buf_Release(bufp);
+           bufp = NULL;
             break;
         }
                 
@@ -733,6 +879,7 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
             cm_SyncOpDone(scp, bufp, flags);
             lock_ReleaseMutex(&bufp->mx);
             buf_Release(bufp);
+           bufp = NULL;
             break;
         }
 
@@ -749,18 +896,19 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
         osi_QAddT((osi_queue_t **) &biop->bufListp,
                   (osi_queue_t **) &biop->bufListEndp,
                   &qdp->q);
+       bufp = NULL;            /* added to the queue */
 
         /* update biod info describing the transfer */
         biop->offset = LargeIntegerSubtract(biop->offset, thyper);
-        biop->length += buf_bufferSize;
+        biop->length += cm_data.buf_blockSize;
 
         /* update loop pointer */
         tbase = LargeIntegerSubtract(tbase, thyper);
     }  /* while loop looking for pages preceding the one we found */
 
     /* now, find later dirty, contiguous pages, and add them to the list */
-    thyper.HighPart = 0;               /* hyper version of buf_bufferSize */
-    thyper.LowPart = buf_bufferSize;
+    thyper.HighPart = 0;               /* hyper version of cm_data.buf_blockSize */
+    thyper.LowPart = cm_data.buf_blockSize;
     tbase = LargeIntegerAdd(firstModOffset, thyper);
     while(LargeIntegerLessThan(tbase, scanEnd)) {
         /* see if we can find the buffer */
@@ -769,9 +917,12 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
             break;
 
         /* try to lock it, and quit if we can't (simplifies locking) */
+        lock_ReleaseMutex(&scp->mx);
         code = lock_TryMutex(&bufp->mx);
+        lock_ObtainMutex(&scp->mx);
         if (code == 0) {
             buf_Release(bufp);
+           bufp = NULL;
             break;
         }
 
@@ -779,6 +930,7 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
         if (code) {
             lock_ReleaseMutex(&bufp->mx);
             buf_Release(bufp);
+           bufp = NULL;
             break;
         }
                 
@@ -787,6 +939,7 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
             cm_SyncOpDone(scp, bufp, flags);
             lock_ReleaseMutex(&bufp->mx);
             buf_Release(bufp);
+           bufp = NULL;
             break;
         }
 
@@ -803,9 +956,10 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
         osi_QAddH((osi_queue_t **) &biop->bufListp,
                   (osi_queue_t **) &biop->bufListEndp,
                   &qdp->q);
+       bufp = NULL;
 
         /* update biod info describing the transfer */
-        biop->length += buf_bufferSize;
+        biop->length += cm_data.buf_blockSize;
                 
         /* update loop pointer */
         tbase = LargeIntegerAdd(tbase, thyper);
@@ -878,35 +1032,37 @@ long cm_SetupFetchBIOD(cm_scache_t *scp, osi_hyper_t *offsetp,
      * sequence at a time.
      */
 
+    // lock_ObtainMutex(&cm_bufGetMutex);
     /* first hold all buffers, since we can't hold any locks in buf_Get */
     while (1) {
         /* stop at chunk boundary */
-        if (collected >= cm_chunkSize) break;
+        if (collected >= cm_chunkSize) 
+            break;
                 
         /* see if the next page would be past EOF */
-        if (LargeIntegerGreaterThanOrEqualTo(pageBase, fileSize)) break;
-
-        lock_ObtainMutex(&cm_bufGetMutex);
+        if (LargeIntegerGreaterThanOrEqualTo(pageBase, fileSize)) 
+            break;
 
         code = buf_Get(scp, &pageBase, &tbp);
         if (code) {
-            lock_ReleaseMutex(&cm_bufGetMutex);
+            //lock_ReleaseMutex(&cm_bufGetMutex);
             lock_ObtainMutex(&scp->mx);
+            cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
             return code;
         }
                 
         buf_Release(tbp);
 
-        lock_ReleaseMutex(&cm_bufGetMutex);
-
         toffset.HighPart = 0;
-        toffset.LowPart = buf_bufferSize;
+        toffset.LowPart = cm_data.buf_blockSize;
         pageBase = LargeIntegerAdd(toffset, pageBase);
-        collected += buf_bufferSize;
+        collected += cm_data.buf_blockSize;
     }
 
     /* reserve a chunk's worth of buffers if possible */
-    reserving = buf_TryReserveBuffers(cm_chunkSize / buf_bufferSize);
+    reserving = buf_TryReserveBuffers(cm_chunkSize / cm_data.buf_blockSize);
+
+    // lock_ReleaseMutex(&cm_bufGetMutex);
 
     pageBase = *offsetp;
     collected = pageBase.LowPart & (cm_chunkSize - 1);
@@ -928,16 +1084,17 @@ long cm_SetupFetchBIOD(cm_scache_t *scp, osi_hyper_t *offsetp,
         /* add the buffer to the list */
         qdp = osi_QDAlloc();
         osi_SetQData(qdp, tbp);
-        osi_QAdd((osi_queue_t **)&heldBufListp, &qdp->q);
-        if (!heldBufListEndp) heldBufListEndp = qdp;
+        osi_QAddH((osi_queue_t **)&heldBufListp, 
+                 (osi_queue_t **)&heldBufListEndp, 
+                 &qdp->q);
         /* leave tbp held (from buf_Get) */
 
         if (!reserving) 
             break;
 
-        collected += buf_bufferSize;
+        collected += cm_data.buf_blockSize;
         toffset.HighPart = 0;
-        toffset.LowPart = buf_bufferSize;
+        toffset.LowPart = cm_data.buf_blockSize;
         pageBase = LargeIntegerAdd(toffset, pageBase);
     }
 
@@ -997,16 +1154,16 @@ long cm_SetupFetchBIOD(cm_scache_t *scp, osi_hyper_t *offsetp,
         /* add the buffer to the list */
         qdp = osi_QDAlloc();
         osi_SetQData(qdp, tbp);
-        osi_QAdd((osi_queue_t **)&biop->bufListp, &qdp->q);
-        if (!biop->bufListEndp) 
-            biop->bufListEndp = qdp;
+        osi_QAddH((osi_queue_t **)&biop->bufListp, 
+                 (osi_queue_t **)&biop->bufListEndp, 
+                 &qdp->q);
         buf_Hold(tbp);
 
         /* from now on, a failure just stops our collection process, but
          * we still do the I/O to whatever we've already managed to collect.
          */
         isFirst = 0;
-        collected += buf_bufferSize;
+        collected += cm_data.buf_blockSize;
     }
         
     /* now, we've held in biop->bufListp all the buffer's we're really
@@ -1016,6 +1173,9 @@ long cm_SetupFetchBIOD(cm_scache_t *scp, osi_hyper_t *offsetp,
     for (qdp = heldBufListp; qdp; qdp = tqdp) {
         tqdp = (osi_queueData_t *) osi_QNext(&qdp->q);
         tbp = osi_GetQData(qdp);
+       osi_QRemoveHT((osi_queue_t **) &heldBufListp,
+                     (osi_queue_t **) &heldBufListEndp,
+                     &qdp->q);
         osi_QDFree(qdp);
         buf_Release(tbp);
     }
@@ -1028,7 +1188,7 @@ long cm_SetupFetchBIOD(cm_scache_t *scp, osi_hyper_t *offsetp,
      * caller requires to make any progress.  Give up now.
      */
     if (code && isFirst) {
-        buf_UnreserveBuffers(cm_chunkSize / buf_bufferSize);
+        buf_UnreserveBuffers(cm_chunkSize / cm_data.buf_blockSize);
         return code;
     }
         
@@ -1053,7 +1213,7 @@ void cm_ReleaseBIOD(cm_bulkIO_t *biop, int isStore)
 
     /* Give back reserved buffers */
     if (biop->reserved)
-        buf_UnreserveBuffers(cm_chunkSize / buf_bufferSize);
+        buf_UnreserveBuffers(cm_chunkSize / cm_data.buf_blockSize);
         
     flags = CM_SCACHESYNC_NEEDCALLBACK;
     if (isStore)
@@ -1068,24 +1228,29 @@ void cm_ReleaseBIOD(cm_bulkIO_t *biop, int isStore)
                 
         /* extract buffer and free queue data */
         bufp = osi_GetQData(qdp);
+       osi_QRemoveHT((osi_queue_t **) &biop->bufListp,
+                     (osi_queue_t **) &biop->bufListEndp,
+                     &qdp->q);
         osi_QDFree(qdp);
 
         /* now, mark I/O as done, unlock the buffer and release it */
         lock_ObtainMutex(&bufp->mx);
         lock_ObtainMutex(&scp->mx);
         cm_SyncOpDone(scp, bufp, flags);
-        lock_ReleaseMutex(&scp->mx);
                 
         /* turn off writing and wakeup users */
         if (isStore) {
             if (bufp->flags & CM_BUF_WAITING) {
-                osi_Wakeup((long) bufp);
+                osi_Log2(afsd_logp, "cm_ReleaseBIOD Waking [scp 0x%p] bp 0x%p", scp, bufp);
+                osi_Wakeup((LONG_PTR) bufp);
             }
-            bufp->flags &= ~(CM_BUF_WAITING | CM_BUF_WRITING | CM_BUF_DIRTY);
+            bufp->flags &= ~(CM_BUF_WRITING | CM_BUF_DIRTY);
         }
 
+        lock_ReleaseMutex(&scp->mx);
         lock_ReleaseMutex(&bufp->mx);
         buf_Release(bufp);
+       bufp = NULL;
     }
 
     /* clean things out */
@@ -1100,21 +1265,25 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up,
                   cm_req_t *reqp)
 {
     long code;
-    long nbytes;                       /* bytes in transfer */
+    afs_int32 nbytes;                  /* bytes in transfer */
+    afs_int32 nbytes_hi = 0;            /* high-order 32 bits of bytes in transfer */
+    afs_int64 length_found = 0;
     long rbytes;                       /* bytes in rx_Read call */
     long temp;
     AFSFetchStatus afsStatus;
     AFSCallBack callback;
     AFSVolSync volSync;
     char *bufferp;
-    cm_buf_t *tbufp;           /* buf we're filling */
+    cm_buf_t *tbufp;                   /* buf we're filling */
     osi_queueData_t *qdp;              /* q element we're scanning */
     AFSFid tfid;
     struct rx_call *callp;
+    struct rx_connection *rxconnp;
     cm_bulkIO_t biod;          /* bulk IO descriptor */
     cm_conn_t *connp;
     int getroot;
     long t1, t2;
+    int require_64bit_ops = 0;
 
     /* now, the buffer may or may not be filled with good data (buf_GetNew
      * drops lots of locks, and may indeed return a properly initialized
@@ -1127,9 +1296,9 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up,
     // handle it differently, since it's local rather than on any
     // server
 
-    getroot = (scp==cm_rootSCachep);
+    getroot = (scp==cm_data.rootSCachep);
     if (getroot)
-        osi_Log1(afsd_logp,"GetBuffer returns cm_rootSCachep=%x",cm_rootSCachep);
+        osi_Log1(afsd_logp,"GetBuffer returns cm_data.rootSCachep=%x",cm_data.rootSCachep);
 #endif
 
     cm_AFSFidFromFid(&tfid, &scp->fid);
@@ -1156,7 +1325,7 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up,
              && LargeIntegerGreaterThanOrEqualTo(bufp->offset,
                                                  scp->serverLength)) {
             if (bufp->dataVersion == -1)
-                memset(bufp->datap, 0, buf_bufferSize);
+                memset(bufp->datap, 0, cm_data.buf_blockSize);
             bufp->dataVersion = scp->dataVersion;
         }
         lock_ReleaseMutex(&scp->mx);
@@ -1164,9 +1333,15 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up,
         lock_ObtainMutex(&scp->mx);
         return 0;
     }
-        
+
     lock_ReleaseMutex(&scp->mx);
 
+    if (LargeIntegerGreaterThan(LargeIntegerAdd(biod.offset,
+                                                ConvertLongToLargeInteger(biod.length)),
+                                ConvertLongToLargeInteger(LONG_MAX))) {
+        require_64bit_ops = 1;
+    }
+
 #ifdef DISKCACHE95
     DPRINTF("cm_GetBuffer: fetching data scpDV=%d bufDV=%d scp=%x bp=%x dcp=%x\n",
             scp->dataVersion, bufp->dataVersion, scp, bufp, bufp->dcp);
@@ -1184,7 +1359,7 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up,
         afsStatus.FileType = 0x2;
         afsStatus.LinkCount = scp->linkCount;
         afsStatus.Length = cm_fakeDirSize;
-        afsStatus.DataVersion = cm_fakeDirVersion;
+        afsStatus.DataVersion = cm_data.fakeDirVersion;
         afsStatus.Author = 0x1;
         afsStatus.Owner = 0x0;
         afsStatus.CallerAccess = 0x9;
@@ -1193,11 +1368,14 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up,
         afsStatus.ParentVnode = 0x1;
         afsStatus.ParentUnique = 0x1;
         afsStatus.ResidencyMask = 0;
-        afsStatus.ClientModTime = FakeFreelanceModTime;
-        afsStatus.ServerModTime = FakeFreelanceModTime;
+        afsStatus.ClientModTime = (afs_uint32)FakeFreelanceModTime;
+        afsStatus.ServerModTime = (afs_uint32)FakeFreelanceModTime;
         afsStatus.Group = 0;
         afsStatus.SyncCounter = 0;
         afsStatus.dataVersionHigh = 0;
+        afsStatus.lockCount = 0;
+        afsStatus.Length_hi = 0;
+        afsStatus.errorCode = 0;
        
         // once we're done setting up the status info,
         // we just fill the buffer pages with fakedata
@@ -1210,9 +1388,9 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up,
         while (qdp) {
             tbufp = osi_GetQData(qdp);
             bufferp=tbufp->datap;
-            memset(bufferp, 0, buf_bufferSize);
+            memset(bufferp, 0, cm_data.buf_blockSize);
             t2 = cm_fakeDirSize - t1;
-            if (t2>buf_bufferSize) t2=buf_bufferSize;
+            if (t2>cm_data.buf_blockSize) t2=cm_data.buf_blockSize;
             if (t2 > 0) {
                 memcpy(bufferp, cm_FakeRootDir+t1, t2);
             } else {
@@ -1238,25 +1416,86 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up,
         code = cm_Conn(&scp->fid, up, reqp, &connp);
         if (code) 
             continue;
-               
-        lock_ObtainMutex(&connp->mx);
-        callp = rx_NewCall(connp->callp);
 
-        osi_Log3(afsd_logp, "CALL FetchData vp %x, off 0x%x, size 0x%x",
-                  (long) scp, biod.offset.LowPart, biod.length);
+        rxconnp = cm_GetRxConn(connp);
+        callp = rx_NewCall(rxconnp);
+        rx_PutConnection(rxconnp);
+
+#ifdef AFS_LARGEFILES
+        nbytes = nbytes_hi = 0;
+
+        if (SERVERHAS64BIT(connp)) {
+            osi_Log4(afsd_logp, "CALL FetchData64 scp 0x%p, off 0x%x:%08x, size 0x%x",
+                     scp, biod.offset.HighPart, biod.offset.LowPart, biod.length);
+
+            code = StartRXAFS_FetchData64(callp, &tfid, biod.offset.QuadPart, biod.length);
+
+            if (code == 0) {
+                temp = rx_Read(callp, (char *) &nbytes_hi, sizeof(afs_int32));
+                if (temp == sizeof(afs_int32)) {
+                    nbytes_hi = ntohl(nbytes_hi);
+                } else {
+                    nbytes_hi = 0;
+                   code = callp->error;
+                    rx_EndCall(callp, code);
+                    callp = NULL;
+                }
+            }
+        }
+
+        if (code == RXGEN_OPCODE || !SERVERHAS64BIT(connp)) {
+            if (require_64bit_ops) {
+                osi_Log0(afsd_logp, "Skipping FetchData.  Operation requires FetchData64");
+                code = CM_ERROR_TOOBIG;
+            } else {
+                if (!callp) {
+                    rxconnp = cm_GetRxConn(connp);
+                    callp = rx_NewCall(rxconnp);
+                    rx_PutConnection(rxconnp);
+                }
+
+                osi_Log3(afsd_logp, "CALL FetchData scp 0x%p, off 0x%x, size 0x%x",
+                         scp, biod.offset.LowPart, biod.length);
+
+                code = StartRXAFS_FetchData(callp, &tfid, biod.offset.LowPart,
+                                            biod.length);
+
+                SET_SERVERHASNO64BIT(connp);
+            }
+        }
+
+        if (code == 0) {
+            temp  = rx_Read(callp, (char *)&nbytes, sizeof(afs_int32));
+            if (temp == sizeof(afs_int32)) {
+                nbytes = ntohl(nbytes);
+                FillInt64(length_found, nbytes_hi, nbytes);
+                if (length_found > biod.length) 
+                    code = (callp->error < 0) ? callp->error : -1;
+            } else {
+                code = (callp->error < 0) ? callp->error : -1;
+            }
+        }
+        /* for the moment, nbytes_hi will always be 0 if code == 0
+           because biod.length is a 32-bit quantity. */
+#else
+        osi_Log3(afsd_logp, "CALL FetchData scp 0x%p, off 0x%x, size 0x%x",
+                 scp, biod.offset.LowPart, biod.length);
 
         code = StartRXAFS_FetchData(callp, &tfid, biod.offset.LowPart,
                                     biod.length);
 
         /* now copy the data out of the pipe and put it in the buffer */
-        temp  = rx_Read(callp, (char *)&nbytes, 4);
-        if (temp == 4) {
-            nbytes = ntohl(nbytes);
-            if (nbytes > biod.length) 
+        if (code == 0) {
+            temp  = rx_Read(callp, (char *)&nbytes, sizeof(afs_int32));
+            if (temp == sizeof(afs_int32)) {
+                nbytes = ntohl(nbytes);
+                if (nbytes > biod.length) 
+                    code = (callp->error < 0) ? callp->error : -1;
+            }
+            else 
                 code = (callp->error < 0) ? callp->error : -1;
         }
-        else 
-            code = (callp->error < 0) ? callp->error : -1;
+#endif
 
         if (code == 0) {
             qdp = biod.bufListEndp;
@@ -1281,7 +1520,7 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up,
                 osi_assert(bufferp != NULL);
 
                 /* read rbytes of data */
-                rbytes = (nbytes > buf_bufferSize? buf_bufferSize : nbytes);
+                rbytes = (nbytes > cm_data.buf_blockSize? cm_data.buf_blockSize : nbytes);
                 temp = rx_Read(callp, bufferp, rbytes);
                 if (temp < rbytes) {
                     code = (callp->error < 0) ? callp->error : -1;
@@ -1296,8 +1535,8 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up,
                 tbufp->cmFlags |= CM_BUF_CMFULLYFETCHED;
                 lock_ObtainMutex(&scp->mx);
                 if (scp->flags & CM_SCACHEFLAG_WAITING) {
-                    scp->flags &= ~CM_SCACHEFLAG_WAITING;
-                    osi_Wakeup((long) &scp->flags);
+                    osi_Log1(afsd_logp, "CM GetBuffer Waking scp 0x%p", scp);
+                    osi_Wakeup((LONG_PTR) &scp->flags);
                 }
                 if (cpffp && !*cpffp && !osi_QPrev(&qdp->q)) {
                     *cpffp = 1;
@@ -1328,9 +1567,11 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up,
              * all of the rest of the pages.
              */
             /* bytes fetched */
-            rbytes = bufferp - tbufp->datap;
+           osi_assert((bufferp - tbufp->datap) < LONG_MAX);
+            rbytes = (long) (bufferp - tbufp->datap);
+
             /* bytes left to zero */
-            rbytes = buf_bufferSize - rbytes;
+            rbytes = cm_data.buf_blockSize - rbytes;
             while(qdp) {
                 if (rbytes != 0)
                     memset(bufferp, 0, rbytes);
@@ -1340,20 +1581,29 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up,
                 tbufp = osi_GetQData(qdp);
                 bufferp = tbufp->datap;
                 /* bytes to clear in this page */
-                rbytes = buf_bufferSize;
+                rbytes = cm_data.buf_blockSize;
             }   
         }
 
-        if (code == 0)
-            code = EndRXAFS_FetchData(callp, &afsStatus, &callback, &volSync);
-        else
-            osi_Log0(afsd_logp, "CALL EndRXAFS_FetchData skipped due to error");
-        code = rx_EndCall(callp, code);
+        if (code == 0) {
+            if (SERVERHAS64BIT(connp))
+                code = EndRXAFS_FetchData64(callp, &afsStatus, &callback, &volSync);
+            else
+                code = EndRXAFS_FetchData(callp, &afsStatus, &callback, &volSync);
+        } else {
+            if (SERVERHAS64BIT(connp))
+                osi_Log1(afsd_logp, "CALL EndRXAFS_FetchData64 skipped due to error %d", code);
+            else
+                osi_Log1(afsd_logp, "CALL EndRXAFS_FetchData skipped due to error %d", code);
+        }
+
+        if (callp)
+            code = rx_EndCall(callp, code);
+
         if (code == RXKADUNKNOWNKEY)
             osi_Log0(afsd_logp, "CALL EndCall returns RXKADUNKNOWNKEY");
-        osi_Log0(afsd_logp, "CALL FetchData DONE");
 
-        lock_ReleaseMutex(&connp->mx);
+        osi_Log0(afsd_logp, "CALL FetchData DONE");
 
     } while (cm_Analyze(connp, up, reqp, &scp->fid, &volSync, NULL, NULL, code));
 
@@ -1361,6 +1611,9 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up,
     code = cm_MapRPCError(code, reqp);
 
     lock_ObtainMutex(&scp->mx);
+    
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_FETCHSTATUS);
+
     /* we know that no one else has changed the buffer, since we still have
      * the fetching flag on the buffers, and we have the scp locked again.
      * Copy in the version # into the buffer if we got code 0 back from the
@@ -1375,7 +1628,7 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up,
 
 #ifdef DISKCACHE95
             /* write buffer out to disk cache */
-            diskcache_Update(tbufp->dcp, tbufp->datap, buf_bufferSize,
+            diskcache_Update(tbufp->dcp, tbufp->datap, cm_data.buf_blockSize,
                               tbufp->dataVersion);
 #endif /* DISKCACHE95 */
         }
@@ -1388,5 +1641,6 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up,
 
     if (code == 0) 
         cm_MergeStatus(scp, &afsStatus, &volSync, up, 0);
+    
     return code;
 }