windows-misc-fix-20061004
[openafs.git] / src / WINNT / afsd / cm_buf.c
index 98b63f8..a279116 100644 (file)
 #include <afs/param.h>
 #include <afs/stds.h>
 
-#ifndef DJGPP
 #include <windows.h>
-#endif
 #include <osi.h>
 #include <stdio.h>
 #include <assert.h>
 #include <strsafe.h>
+#include <math.h>
 
 #include "afsd.h"
 #include "cm_memmap.h"
@@ -88,12 +87,48 @@ extern int cm_diskCacheEnabled;
 /* set this to 1 when we are terminating to prevent access attempts */
 static int buf_ShutdownFlag = 0;
 
+void buf_HoldLocked(cm_buf_t *bp)
+{
+    osi_assert(bp->magic == CM_BUF_MAGIC);
+    bp->refCount++;
+}
+
 /* hold a reference to an already held buffer */
 void buf_Hold(cm_buf_t *bp)
 {
+    lock_ObtainWrite(&buf_globalLock);
+    buf_HoldLocked(bp);
+    lock_ReleaseWrite(&buf_globalLock);
+}
+
+/* code to drop reference count while holding buf_globalLock */
+void buf_ReleaseLocked(cm_buf_t *bp)
+{
+    /* ensure that we're in the LRU queue if our ref count is 0 */
     osi_assert(bp->magic == CM_BUF_MAGIC);
+#ifdef DEBUG
+    if (bp->refCount == 0)
+       DebugBreak();
+#else
+    osi_assert(bp->refCount > 0);
+#endif
+    if (--bp->refCount == 0) {
+        if (!(bp->flags & CM_BUF_INLRU)) {
+            osi_QAdd((osi_queue_t **) &cm_data.buf_freeListp, &bp->q);
+
+            /* watch for transition from empty to one element */
+            if (!cm_data.buf_freeListEndp)
+                cm_data.buf_freeListEndp = cm_data.buf_freeListp;
+            bp->flags |= CM_BUF_INLRU;
+        }
+    }
+}       
+
+/* release a buffer.  Buffer must be referenced, but unlocked. */
+void buf_Release(cm_buf_t *bp)
+{
     lock_ObtainWrite(&buf_globalLock);
-    bp->refCount++;
+    buf_ReleaseLocked(bp);
     lock_ReleaseWrite(&buf_globalLock);
 }
 
@@ -102,27 +137,28 @@ void buf_IncrSyncer(long parm)
 {
     cm_buf_t *bp;                      /* buffer we're hacking on; held */
     long i;                            /* counter */
-    long nAtOnce;                      /* how many to do at once */
+    long wasDirty;
     cm_req_t req;
 
     lock_ObtainWrite(&buf_globalLock);
     bp = cm_data.buf_allp;
-    bp->refCount++;
+    buf_HoldLocked(bp);
     lock_ReleaseWrite(&buf_globalLock);
-    nAtOnce = cm_data.buf_nbuffers / 10;
+    wasDirty = 0;
+
     while (buf_ShutdownFlag == 0) {
-#ifndef DJGPP
-        i = SleepEx(5000, 1);
-        if (i != 0) continue;
-#else
-        thrd_Sleep(5000);
-#endif /* DJGPP */
-            
+        if (!wasDirty) {
+            i = SleepEx(5000, 1);
+            if (i != 0) continue;
+       }
+
         if (buf_ShutdownFlag == 1)
             return;
 
+       wasDirty = 0;
+
         /* now go through our percentage of the buffers */
-        for (i=0; i<nAtOnce; i++) {
+        for (i=0; i<cm_data.buf_nbuffers; i++) {
             /* don't want its identity changing while we're
              * messing with it, so must do all of this with
              * bp held.
@@ -133,18 +169,20 @@ void buf_IncrSyncer(long parm)
              * a log page at any given instant.
              */
             cm_InitReq(&req);
+#ifdef NO_BKG_RETRIES
             req.flags |= CM_REQ_NORETRY;
-            buf_CleanAsync(bp, &req);
+#endif
+           wasDirty |= buf_CleanAsync(bp, &req);
 
             /* now advance to the next buffer; the allp chain never changes,
              * and so can be followed even when holding no locks.
              */
             lock_ObtainWrite(&buf_globalLock);
-            buf_LockedRelease(bp);
+            buf_ReleaseLocked(bp);
             bp = bp->allp;
             if (!bp) 
                 bp = cm_data.buf_allp;
-            bp->refCount++;
+           buf_HoldLocked(bp);
             lock_ReleaseWrite(&buf_globalLock);
         }      /* for loop over a bunch of buffers */
     }          /* whole daemon's while loop */
@@ -154,7 +192,14 @@ long
 buf_ValidateBuffers(void)
 {
     cm_buf_t * bp, *bpf, *bpa, *bpb;
-    afs_uint32 countb = 0, countf = 0, counta = 0;
+    afs_uint64 countb = 0, countf = 0, counta = 0;
+
+    if (cm_data.buf_freeListp == NULL && cm_data.buf_freeListEndp != NULL ||
+         cm_data.buf_freeListp != NULL && cm_data.buf_freeListEndp == NULL) {
+        afsi_log("cm_ValidateBuffers failure: inconsistent free list pointers");
+        fprintf(stderr, "cm_ValidateBuffers failure: inconsistent free list pointers\n");
+        return -9;                  
+    }
 
     for (bp = cm_data.buf_freeListEndp; bp; bp=(cm_buf_t *) osi_QPrev(&bp->q)) { 
         if (bp->magic != CM_BUF_MAGIC) {
@@ -227,7 +272,7 @@ void buf_Shutdown(void)
 /* initialize the buffer package; called with no locks
  * held during the initialization phase.
  */
-long buf_Init(int newFile, cm_buf_ops_t *opsp, long nbuffers)
+long buf_Init(int newFile, cm_buf_ops_t *opsp, afs_uint64 nbuffers)
 {
     static osi_once_t once;
     cm_buf_t *bp;
@@ -334,9 +379,7 @@ long buf_Init(int newFile, cm_buf_ops_t *opsp, long nbuffers)
                                "buf_IncrSyncer");
 
         osi_assertx(phandle != NULL, "buf: can't create incremental sync proc");
-#ifndef DJGPP
         CloseHandle(phandle);
-#endif /* !DJGPP */
     }
 
 #ifdef TESTING
@@ -348,9 +391,8 @@ long buf_Init(int newFile, cm_buf_ops_t *opsp, long nbuffers)
 /* add nbuffers to the buffer pool, if possible.
  * Called with no locks held.
  */
-long buf_AddBuffers(long nbuffers)
+long buf_AddBuffers(afs_uint64 nbuffers)
 {
-#ifndef DJGPP
     /* The size of a virtual cache cannot be changed after it has
      * been created.  Subsequent calls to MapViewofFile() with
      * an existing mapping object name would not allow the 
@@ -364,49 +406,12 @@ long buf_AddBuffers(long nbuffers)
               nbuffers, cm_data.buf_nbuffers);
 
     return CM_ERROR_INVAL;
-#else
-    cm_buf_t *bp;
-    int i;
-    char *data;
-
-    data = malloc(buf_nbuffers * cm_data.buf_blockSize);
-
-    /* Create buffer headers and put in free list */
-    bp = malloc(nbuffers * sizeof(*bp));
-
-    for (i=0; i<nbuffers; i++) {
-        memset(bp, 0, sizeof(*bp));
-        
-        lock_InitializeMutex(&bp->mx, "cm_buf_t");
-
-        /* grab appropriate number of bytes from aligned zone */
-        bp->datap = data;
-
-        bp->flags |= CM_BUF_INLRU;
-
-        lock_ObtainWrite(&buf_globalLock);
-        /* note that buf_allp chain is covered by buf_globalLock now */
-        bp->allp = cm_data.buf_allp;
-        cm_data.buf_allp = bp;
-        osi_QAdd((osi_queue_t **) &cm_data.buf_freeListp, &bp->q);
-        if (!cm_data.buf_freeListEndp) 
-            cm_data.buf_freeListEndp = bp;
-        cm_data.buf_nbuffers++;
-        lock_ReleaseWrite(&buf_globalLock);
-
-        bp++;
-        data += cm_data.buf_blockSize;
-       
-    }   /* for loop over all buffers */
-
-    return 0;
-#endif /* DJGPP */
 }       
 
 /* interface to set the number of buffers to an exact figure.
  * Called with no locks held.
  */
-long buf_SetNBuffers(long nbuffers)
+long buf_SetNBuffers(afs_uint64 nbuffers)
 {
     if (nbuffers < 10) 
         return CM_ERROR_INVAL;
@@ -418,16 +423,8 @@ long buf_SetNBuffers(long nbuffers)
         return CM_ERROR_INVAL;
 }
 
-/* release a buffer.  Buffer must be referenced, but unlocked. */
-void buf_Release(cm_buf_t *bp)
-{
-    lock_ObtainWrite(&buf_globalLock);
-    buf_LockedRelease(bp);
-    lock_ReleaseWrite(&buf_globalLock);
-}
-
 /* wait for reading or writing to clear; called with write-locked
- * buffer, and returns with locked buffer.
+ * buffer and unlocked scp and returns with locked buffer.
  */
 void buf_WaitIO(cm_scache_t * scp, cm_buf_t *bp)
 {
@@ -447,18 +444,21 @@ void buf_WaitIO(cm_scache_t * scp, cm_buf_t *bp)
         if ( bp->flags & CM_BUF_WAITING ) {
             bp->waitCount++;
             bp->waitRequests++;
-            osi_Log1(buf_logp, "buf_WaitIO CM_BUF_WAITING already set for 0x%x", bp);
+            osi_Log1(buf_logp, "buf_WaitIO CM_BUF_WAITING already set for 0x%p", bp);
         } else {
-            osi_Log1(buf_logp, "buf_WaitIO CM_BUF_WAITING set for 0x%x", bp);
+            osi_Log1(buf_logp, "buf_WaitIO CM_BUF_WAITING set for 0x%p", bp);
             bp->flags |= CM_BUF_WAITING;
             bp->waitCount = bp->waitRequests = 1;
         }
-        osi_SleepM((long) bp, &bp->mx);
+        osi_SleepM((LONG_PTR)bp, &bp->mx);
+
+       smb_UpdateServerPriority();
+
         lock_ObtainMutex(&bp->mx);
-        osi_Log1(buf_logp, "buf_WaitIO conflict wait done for 0x%x", bp);
+        osi_Log1(buf_logp, "buf_WaitIO conflict wait done for 0x%p", bp);
         bp->waitCount--;
         if (bp->waitCount == 0) {
-            osi_Log1(afsd_logp, "buf_WaitIO CM_BUF_WAITING reset for 0x%x", bp);
+            osi_Log1(buf_logp, "buf_WaitIO CM_BUF_WAITING reset for 0x%p", bp);
             bp->flags &= ~CM_BUF_WAITING;
             bp->waitRequests = 0;
         }
@@ -469,10 +469,10 @@ void buf_WaitIO(cm_scache_t * scp, cm_buf_t *bp)
         if ( scp ) {
             lock_ObtainMutex(&scp->mx);
             if (scp->flags & CM_SCACHEFLAG_WAITING) {
-                osi_Log1(buf_logp, "buf_WaitIO waking scp 0x%x", scp);
-                osi_Wakeup(&scp->flags);
-                lock_ReleaseMutex(&scp->mx);
+                osi_Log1(buf_logp, "buf_WaitIO waking scp 0x%p", scp);
+                osi_Wakeup((LONG_PTR)&scp->flags);
             }
+           lock_ReleaseMutex(&scp->mx);
         }
     }
         
@@ -480,33 +480,16 @@ void buf_WaitIO(cm_scache_t * scp, cm_buf_t *bp)
      * the I/O to complete.  Do so.
      */
     if (bp->flags & CM_BUF_WAITING) {
-        osi_Log1(buf_logp, "buf_WaitIO Waking bp 0x%x", bp);
-        osi_Wakeup((long) bp);
+        osi_Log1(buf_logp, "buf_WaitIO Waking bp 0x%p", bp);
+        osi_Wakeup((LONG_PTR) bp);
     }
-    osi_Log1(buf_logp, "WaitIO finished wait for bp 0x%x", (long) bp);
+    osi_Log1(buf_logp, "WaitIO finished wait for bp 0x%p", bp);
 }
 
-/* code to drop reference count while holding buf_globalLock */
-void buf_LockedRelease(cm_buf_t *bp)
-{
-    /* ensure that we're in the LRU queue if our ref count is 0 */
-    osi_assert(bp->refCount > 0);
-    if (--bp->refCount == 0) {
-        if (!(bp->flags & CM_BUF_INLRU)) {
-            osi_QAdd((osi_queue_t **) &cm_data.buf_freeListp, &bp->q);
-
-            /* watch for transition from empty to one element */
-            if (!cm_data.buf_freeListEndp)
-                cm_data.buf_freeListEndp = cm_data.buf_freeListp;
-            bp->flags |= CM_BUF_INLRU;
-        }
-    }
-}       
-
 /* find a buffer, if any, for a particular file ID and offset.  Assumes
  * that buf_globalLock is write locked when called.
  */
-cm_buf_t *buf_LockedFind(struct cm_scache *scp, osi_hyper_t *offsetp)
+cm_buf_t *buf_FindLocked(struct cm_scache *scp, osi_hyper_t *offsetp)
 {
     long i;
     cm_buf_t *bp;
@@ -516,7 +499,7 @@ cm_buf_t *buf_LockedFind(struct cm_scache *scp, osi_hyper_t *offsetp)
         if (cm_FidCmp(&scp->fid, &bp->fid) == 0
              && offsetp->LowPart == bp->offset.LowPart
              && offsetp->HighPart == bp->offset.HighPart) {
-            bp->refCount++;
+            buf_HoldLocked(bp);
             break;
         }
     }
@@ -533,7 +516,7 @@ cm_buf_t *buf_Find(struct cm_scache *scp, osi_hyper_t *offsetp)
     cm_buf_t *bp;
 
     lock_ObtainWrite(&buf_globalLock);
-    bp = buf_LockedFind(scp, offsetp);
+    bp = buf_FindLocked(scp, offsetp);
     lock_ReleaseWrite(&buf_globalLock);
 
     return bp;
@@ -545,23 +528,43 @@ cm_buf_t *buf_Find(struct cm_scache *scp, osi_hyper_t *offsetp)
  * Makes sure that there's only one person writing this block
  * at any given time, and also ensures that the log is forced sufficiently far,
  * if this buffer contains logged data.
+ *
+ * Returns one if the buffer was dirty.
  */
-void buf_LockedCleanAsync(cm_buf_t *bp, cm_req_t *reqp)
+long buf_CleanAsyncLocked(cm_buf_t *bp, cm_req_t *reqp)
 {
     long code = 0;
+    long isdirty = 0;
+       cm_scache_t * scp = NULL;
 
     osi_assert(bp->magic == CM_BUF_MAGIC);
 
     while ((bp->flags & CM_BUF_DIRTY) == CM_BUF_DIRTY) {
+       isdirty = 1;
         lock_ReleaseMutex(&bp->mx);
 
-        code = (*cm_buf_opsp->Writep)(&bp->fid, &bp->offset,
+       scp = cm_FindSCache(&bp->fid);
+       osi_Log2(buf_logp, "buf_CleanAsyncLocked starts I/O on scp 0x%p buf 0x%p", scp, bp);
+        code = (*cm_buf_opsp->Writep)(scp, &bp->offset,
                                        cm_data.buf_blockSize, 0, bp->userp,
                                        reqp);
+       osi_Log3(buf_logp, "buf_CleanAsyncLocked I/O on scp 0x%p buf 0x%p, done=%d", scp, bp, code);
+
+       if (scp) {
+           cm_ReleaseSCache(scp);
+           scp = NULL;
+       }
                 
         lock_ObtainMutex(&bp->mx);
-        if (code) 
-            break;
+       /* if the Write routine returns No Such File, clear the dirty flag 
+        * because we aren't going to be able to write this data to the file
+        * server.
+        */
+       if (code == CM_ERROR_NOSUCHFILE){
+           bp->flags &= ~CM_BUF_DIRTY;
+           bp->flags |= CM_BUF_ERROR;
+           bp->error = CM_ERROR_NOSUCHFILE;
+       }
 
 #ifdef DISKCACHE95
         /* Disk cache support */
@@ -571,16 +574,16 @@ void buf_LockedCleanAsync(cm_buf_t *bp, cm_req_t *reqp)
     };
 
     /* do logging after call to GetLastError, or else */
-    osi_Log2(buf_logp, "buf_CleanAsync starts I/O on 0x%x, done=%d", bp, code);
         
     /* if someone was waiting for the I/O that just completed or failed,
      * wake them up.
      */
     if (bp->flags & CM_BUF_WAITING) {
         /* turn off flags and wakeup users */
-        osi_Log1(buf_logp, "buf_WaitIO Waking bp 0x%x", bp);
-        osi_Wakeup((long) bp);
+        osi_Log1(buf_logp, "buf_WaitIO Waking bp 0x%p", bp);
+        osi_Wakeup((LONG_PTR) bp);
     }
+    return isdirty;
 }
 
 /* Called with a zero-ref count buffer and with the buf_globalLock write locked.
@@ -603,7 +606,7 @@ void buf_Recycle(cm_buf_t *bp)
      * have any lock conflicts, so we can grab the buffer lock out of
      * order in the locking hierarchy.
      */
-    osi_Log2( buf_logp, "buf_Recycle recycles 0x%x, off 0x%x",
+    osi_Log2( buf_logp, "buf_Recycle recycles 0x%p, off 0x%x",
               bp, bp->offset.LowPart);
 
     osi_assert(bp->refCount == 0);
@@ -678,13 +681,25 @@ long buf_GetNewLocked(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bu
         lock_ObtainWrite(&buf_globalLock);
         /* check to see if we lost the race */
         if (scp) {
-            if (bp = buf_LockedFind(scp, offsetp)) {
+            if (bp = buf_FindLocked(scp, offsetp)) {
+               /* Do not call buf_ReleaseLocked() because we 
+                * do not want to allow the buffer to be added
+                * to the free list.
+                */
                 bp->refCount--;
                 lock_ReleaseWrite(&buf_globalLock);
                 return CM_BUF_EXISTS;
             }
         }
 
+       /* does this fix the problem below?  it's a simple solution. */
+       if (!cm_data.buf_freeListEndp)
+           {
+           lock_ReleaseWrite(&buf_globalLock);
+           Sleep(200);
+           goto retry;
+           }
+
         /* for debugging, assert free list isn't empty, although we
          * really should try waiting for a running tranasction to finish
          * instead of this; or better, we should have a transaction
@@ -734,7 +749,7 @@ long buf_GetNewLocked(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bu
                  * just the lock required to minimize contention
                  * on the big lock.
                  */
-                bp->refCount++;
+                buf_HoldLocked(bp);
                 lock_ReleaseWrite(&buf_globalLock);
 
                 /* grab required lock and clean; this only
@@ -769,6 +784,9 @@ long buf_GetNewLocked(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bu
             if (scp) {
                 bp->flags |= CM_BUF_INHASH;
                 bp->fid = scp->fid;
+#ifdef DEBUG
+               bp->scp = scp;
+#endif
                 bp->offset = *offsetp;
                 i = BUF_HASH(&scp->fid, offsetp);
                 bp->hashp = cm_data.buf_hashTablepp[i];
@@ -868,8 +886,8 @@ long buf_GetNew(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bufpp)
      */
     lock_ReleaseMutex(&bp->mx);
     *bufpp = bp;
-    osi_Log3(buf_logp, "buf_GetNew returning bp 0x%x for file 0x%x, offset 0x%x",
-              bp, (long) scp, offsetp->LowPart);
+    osi_Log3(buf_logp, "buf_GetNew returning bp 0x%p for scp 0x%p, offset 0x%x",
+              bp, scp, offsetp->LowPart);
     return 0;
 }
 
@@ -900,16 +918,17 @@ long buf_Get(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bufpp)
         if (bp) {
             /* lock it and break out */
             lock_ObtainMutex(&bp->mx);
-            break;
 
 #ifdef DISKCACHE95
             /* touch disk chunk to update LRU info */
             diskcache_Touch(bp->dcp);
 #endif /* DISKCACHE95 */
+            break;
         }
 
         /* otherwise, we have to create a page */
         code = buf_GetNewLocked(scp, &pageOffset, &bp);
+       /* bp->mx is now held */
 
         /* check if the buffer was created in a race condition branch.
          * If so, go around so we can hold a reference to it. 
@@ -938,10 +957,8 @@ long buf_Get(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bufpp)
         osi_assert(!(bp->flags & (CM_BUF_READING | CM_BUF_WRITING)));
 
         /* setup offset, event */
-#ifndef DJGPP  /* doesn't seem to be used */
         bp->over.Offset = bp->offset.LowPart;
         bp->over.OffsetHigh = bp->offset.HighPart;
-#endif /* !DJGPP */
 
         /* start the I/O; may drop lock */
         bp->flags |= CM_BUF_READING;
@@ -954,15 +971,13 @@ long buf_Get(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bufpp)
 
         if (code != 0) {
             /* failure or queued */
-#ifndef DJGPP   /* cm_bufRead always returns 0 */
             if (code != ERROR_IO_PENDING) {
-#endif
                 bp->error = code;
                 bp->flags |= CM_BUF_ERROR;
                 bp->flags &= ~CM_BUF_READING;
                 if (bp->flags & CM_BUF_WAITING) {
-                    osi_Log1(buf_logp, "buf_Get Waking bp 0x%x", bp);
-                    osi_Wakeup((long) bp);
+                    osi_Log1(buf_logp, "buf_Get Waking bp 0x%p", bp);
+                    osi_Wakeup((LONG_PTR) bp);
                 }
                 lock_ReleaseMutex(&bp->mx);
                 buf_Release(bp);
@@ -970,9 +985,7 @@ long buf_Get(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bufpp)
                 buf_ValidateBufQueues();
 #endif /* TESTING */
                 return code;
-#ifndef DJGPP
             }
-#endif
         } else {
             /* otherwise, I/O completed instantly and we're done, except
              * for padding the xfr out with 0s and checking for EOF
@@ -984,8 +997,8 @@ long buf_Get(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bufpp)
             }
             bp->flags &= ~CM_BUF_READING;
             if (bp->flags & CM_BUF_WAITING) {
-                osi_Log1(buf_logp, "buf_Get Waking bp 0x%x", bp);
-                osi_Wakeup((long) bp);
+                osi_Log1(buf_logp, "buf_Get Waking bp 0x%p", bp);
+                osi_Wakeup((LONG_PTR) bp);
             }
         }
 
@@ -1015,8 +1028,8 @@ long buf_Get(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bufpp)
     }
     lock_ReleaseWrite(&buf_globalLock);
 
-    osi_Log3(buf_logp, "buf_Get returning bp 0x%x for file 0x%x, offset 0x%x",
-              bp, (long) scp, offsetp->LowPart);
+    osi_Log3(buf_logp, "buf_Get returning bp 0x%p for scp 0x%p, offset 0x%x",
+              bp, scp, offsetp->LowPart);
 #ifdef TESTING
     buf_ValidateBufQueues();
 #endif /* TESTING */
@@ -1048,13 +1061,16 @@ long buf_CountFreeList(void)
 }
 
 /* clean a buffer synchronously */
-void buf_CleanAsync(cm_buf_t *bp, cm_req_t *reqp)
+long buf_CleanAsync(cm_buf_t *bp, cm_req_t *reqp)
 {
+    long code;
     osi_assert(bp->magic == CM_BUF_MAGIC);
 
     lock_ObtainMutex(&bp->mx);
-    buf_LockedCleanAsync(bp, reqp);
+    code = buf_CleanAsyncLocked(bp, reqp);
     lock_ReleaseMutex(&bp->mx);
+
+    return code;
 }       
 
 /* wait for a buffer's cleaning to finish */
@@ -1079,7 +1095,7 @@ void buf_SetDirty(cm_buf_t *bp)
     osi_assert(bp->magic == CM_BUF_MAGIC);
     osi_assert(bp->refCount > 0);
        
-    osi_Log1(buf_logp, "buf_SetDirty 0x%x", bp);
+    osi_Log1(buf_logp, "buf_SetDirty 0x%p", bp);
 
     /* set dirty bit */
     bp->flags |= CM_BUF_DIRTY;
@@ -1118,17 +1134,17 @@ long buf_CleanAndReset(void)
     for(i=0; i<cm_data.buf_hashSize; i++) {
         for(bp = cm_data.buf_hashTablepp[i]; bp; bp = bp->hashp) {
             if ((bp->flags & CM_BUF_DIRTY) == CM_BUF_DIRTY) {
-                bp->refCount++;
+                buf_HoldLocked(bp);
                 lock_ReleaseWrite(&buf_globalLock);
 
                 /* now no locks are held; clean buffer and go on */
                 cm_InitReq(&req);
-                buf_CleanAsync(bp, &req);
-                buf_CleanWait(NULL, bp);
+               buf_CleanAsync(bp, &req);
+               buf_CleanWait(NULL, bp);
 
                 /* relock and release buffer */
                 lock_ObtainWrite(&buf_globalLock);
-                buf_LockedRelease(bp);
+                buf_ReleaseLocked(bp);
             } /* dirty */
         } /* over one bucket */
     }  /* for loop over all hash buckets */
@@ -1147,14 +1163,14 @@ long buf_CleanAndReset(void)
 /* called without global lock being held, reserves buffers for callers
  * that need more than one held (not locked) at once.
  */
-void buf_ReserveBuffers(long nbuffers)
+void buf_ReserveBuffers(afs_uint64 nbuffers)
 {
     lock_ObtainWrite(&buf_globalLock);
     while (1) {
         if (cm_data.buf_reservedBufs + nbuffers > cm_data.buf_maxReservedBufs) {
             cm_data.buf_reserveWaiting = 1;
             osi_Log1(buf_logp, "buf_ReserveBuffers waiting for %d bufs", nbuffers);
-            osi_SleepW((long) &cm_data.buf_reservedBufs, &buf_globalLock);
+            osi_SleepW((LONG_PTR) &cm_data.buf_reservedBufs, &buf_globalLock);
             lock_ObtainWrite(&buf_globalLock);
         }
         else {
@@ -1165,7 +1181,7 @@ void buf_ReserveBuffers(long nbuffers)
     lock_ReleaseWrite(&buf_globalLock);
 }
 
-int buf_TryReserveBuffers(long nbuffers)
+int buf_TryReserveBuffers(afs_uint64 nbuffers)
 {
     int code;
 
@@ -1184,13 +1200,13 @@ int buf_TryReserveBuffers(long nbuffers)
 /* called without global lock held, releases reservation held by
  * buf_ReserveBuffers.
  */
-void buf_UnreserveBuffers(long nbuffers)
+void buf_UnreserveBuffers(afs_uint64 nbuffers)
 {
     lock_ObtainWrite(&buf_globalLock);
     cm_data.buf_reservedBufs -= nbuffers;
     if (cm_data.buf_reserveWaiting) {
         cm_data.buf_reserveWaiting = 0;
-        osi_Wakeup((long) &cm_data.buf_reservedBufs);
+        osi_Wakeup((LONG_PTR) &cm_data.buf_reservedBufs);
     }
     lock_ReleaseWrite(&buf_globalLock);
 }       
@@ -1208,7 +1224,6 @@ long buf_Truncate(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
     osi_hyper_t bufEnd;
     long code;
     long bufferPos;
-    int didRelease;
     long i;
 
     /* assert that cm_bufCreateLock is held in write mode */
@@ -1223,10 +1238,9 @@ long buf_Truncate(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
         return 0;
     }
 
-    bufp->refCount++;
+    buf_HoldLocked(bufp);
     lock_ReleaseWrite(&buf_globalLock);
     for(; bufp; bufp = nbufp) {
-        didRelease = 0;
         lock_ObtainMutex(&bufp->mx);
 
         bufEnd.HighPart = 0;
@@ -1247,14 +1261,16 @@ long buf_Truncate(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
                           | CM_SCACHESYNC_GETSTATUS
                           | CM_SCACHESYNC_SETSIZE
                           | CM_SCACHESYNC_BUFLOCKED);
-        /* if we succeeded in our locking, and this applies to the right
+
+       
+       lock_ObtainWrite(&buf_globalLock);
+       /* if we succeeded in our locking, and this applies to the right
          * file, and the truncate request overlaps the buffer either
          * totally or partially, then do something.
          */
         if (code == 0 && cm_FidCmp(&bufp->fid, &scp->fid) == 0
              && LargeIntegerLessThan(*sizep, bufEnd)) {
 
-            lock_ObtainWrite(&buf_globalLock);
 
             /* destroy the buffer, turning off its dirty bit, if
              * we're truncating the whole buffer.  Otherwise, set
@@ -1281,42 +1297,34 @@ long buf_Truncate(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
                 memset(bufp->datap + bufferPos, 0,
                         cm_data.buf_blockSize - bufferPos);
             }
-
-            lock_ReleaseWrite(&buf_globalLock);
         }
                
+       cm_SyncOpDone( scp, bufp, 
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS
+                      | CM_SCACHESYNC_SETSIZE | CM_SCACHESYNC_BUFLOCKED);
+
         lock_ReleaseMutex(&scp->mx);
         lock_ReleaseMutex(&bufp->mx);
-        if (!didRelease) {
-            lock_ObtainWrite(&buf_globalLock);
-            nbufp = bufp->fileHashp;
-            if (nbufp) nbufp->refCount++;
-            buf_LockedRelease(bufp);
-            lock_ReleaseWrite(&buf_globalLock);
-        }
-
-        /* bail out early if we fail */
-        if (code) {
-            /* at this point, nbufp is held; bufp has already been
-             * released.
-             */
-            if (nbufp) 
-                buf_Release(nbufp);
-
-#ifdef TESTING
-            buf_ValidateBufQueues();
-#endif /* TESTING */
-
-            return code;
-        }
+    
+       if (!code) {
+           nbufp = bufp->fileHashp;
+           if (nbufp) 
+               buf_HoldLocked(nbufp);
+       } else {
+           /* This forces the loop to end and the error code
+            * to be returned. */
+           nbufp = NULL;
+       }
+       buf_ReleaseLocked(bufp);
+       lock_ReleaseWrite(&buf_globalLock);
     }
 
 #ifdef TESTING
     buf_ValidateBufQueues();
 #endif /* TESTING */
 
-    /* success */
-    return 0;
+    /* done */
+    return code;
 }
 
 long buf_FlushCleanPages(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
@@ -1333,8 +1341,9 @@ long buf_FlushCleanPages(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
     lock_ObtainWrite(&buf_globalLock);
     bp = cm_data.buf_fileHashTablepp[i];
     if (bp) 
-        bp->refCount++;
+        buf_HoldLocked(bp);
     lock_ReleaseWrite(&buf_globalLock);
+    
     for (; bp; bp = nbp) {
         didRelease = 0;        /* haven't released this buffer yet */
 
@@ -1343,7 +1352,7 @@ long buf_FlushCleanPages(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
             lock_ObtainMutex(&bp->mx);
 
             /* start cleaning the buffer, and wait for it to finish */
-            buf_LockedCleanAsync(bp, reqp);
+            buf_CleanAsyncLocked(bp, reqp);
             buf_WaitIO(scp, bp);
             lock_ReleaseMutex(&bp->mx);
 
@@ -1357,10 +1366,10 @@ long buf_FlushCleanPages(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
              */
             if (!(bp->flags & CM_BUF_DIRTY)) {
                 if (bp->refCount == 1) {       /* bp is held above */
-                    buf_LockedRelease(bp);
                     nbp = bp->fileHashp;
                     if (nbp) 
-                        nbp->refCount++;
+                        buf_HoldLocked(nbp);
+                    buf_ReleaseLocked(bp);
                     didRelease = 1;
                     buf_Recycle(bp);
                 }
@@ -1373,15 +1382,16 @@ long buf_FlushCleanPages(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
       skip:
         if (!didRelease) {
             lock_ObtainWrite(&buf_globalLock);
-            if (nbp = bp->fileHashp) 
-                nbp->refCount++;
-            buf_LockedRelease(bp);
+            nbp = bp->fileHashp;
+           if (nbp)
+                buf_HoldLocked(nbp);
+            buf_ReleaseLocked(bp);
             lock_ReleaseWrite(&buf_globalLock);
         }
     }  /* for loop over a bunch of buffers */
 
 #ifdef TESTING
-            buf_ValidateBufQueues();
+    buf_ValidateBufQueues();
 #endif /* TESTING */
 
     /* done */
@@ -1401,7 +1411,7 @@ long buf_CleanVnode(struct cm_scache *scp, cm_user_t *userp, cm_req_t *reqp)
     lock_ObtainWrite(&buf_globalLock);
     bp = cm_data.buf_fileHashTablepp[i];
     if (bp) 
-        bp->refCount++;
+        buf_HoldLocked(bp);
     lock_ReleaseWrite(&buf_globalLock);
     for (; bp; bp = nbp) {
         /* clean buffer synchronously */
@@ -1414,8 +1424,8 @@ long buf_CleanVnode(struct cm_scache *scp, cm_user_t *userp, cm_req_t *reqp)
                 bp->userp = userp;
                 lock_ReleaseMutex(&bp->mx);
             }   
-            buf_CleanAsync(bp, reqp);
-            buf_CleanWait(scp, bp);
+            code = buf_CleanAsync(bp, reqp);
+           buf_CleanWait(scp, bp);
             lock_ObtainMutex(&bp->mx);
             if (bp->flags & CM_BUF_ERROR) {
                 if (code == 0 || code == -1) 
@@ -1427,10 +1437,10 @@ long buf_CleanVnode(struct cm_scache *scp, cm_user_t *userp, cm_req_t *reqp)
         }
 
         lock_ObtainWrite(&buf_globalLock);
-        buf_LockedRelease(bp);
         nbp = bp->fileHashp;
         if (nbp) 
-            nbp->refCount++;
+            buf_HoldLocked(nbp);
+        buf_ReleaseLocked(bp);
         lock_ReleaseWrite(&buf_globalLock);
     }  /* for loop over a bunch of buffers */
 
@@ -1496,7 +1506,7 @@ int cm_DumpBufHashTable(FILE *outputFile, char *cookie, int lock)
   
     StringCbPrintfA(output, sizeof(output), "%s - dumping buf_HashTable - buf_hashSize=%d\n", 
                     cookie, cm_data.buf_hashSize);
-    WriteFile(outputFile, output, strlen(output), &zilch, NULL);
+    WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
   
     for (i = 0; i < cm_data.buf_hashSize; i++)
     {
@@ -1507,13 +1517,13 @@ int cm_DumpBufHashTable(FILE *outputFile, char *cookie, int lock)
                 StringCbPrintfA(output, sizeof(output), "vnode=%d, unique=%d), size=%d refCount=%d\n", 
                         cookie, (void *)bp, i, bp->fid.cell, bp->fid.volume, 
                         bp->fid.vnode, bp->fid.unique, bp->size, bp->refCount);
-                WriteFile(outputFile, output, strlen(output), &zilch, NULL);
+                WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
             }
         }
     }
   
     StringCbPrintfA(output, sizeof(output), "%s - Done dumping buf_HashTable.\n", cookie);
-    WriteFile(outputFile, output, strlen(output), &zilch, NULL);
+    WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
 
     if (lock)
         lock_ReleaseRead(&buf_globalLock);
@@ -1541,3 +1551,44 @@ void buf_ForceTrace(BOOL flush)
         FlushFileBuffers(handle);
     CloseHandle(handle);
 }
+
+long buf_DirtyBuffersExist(cm_fid_t *fidp)
+{
+    cm_buf_t *bp;
+    afs_uint32 bcount = 0;
+
+    for (bp = cm_data.buf_allp; bp; bp=bp->allp, bcount++) {
+       if (!cm_FidCmp(fidp, &bp->fid) && (bp->flags & CM_BUF_DIRTY))
+           return 1;
+    }
+    return 0;
+}
+
+#if 0
+long buf_CleanDirtyBuffers(cm_scache_t *scp)
+{
+    cm_buf_t *bp;
+    afs_uint32 bcount = 0;
+    cm_fid_t * fidp = &scp->fid;
+
+    for (bp = cm_data.buf_allp; bp; bp=bp->allp, bcount++) {
+       if (!cm_FidCmp(fidp, &bp->fid) && (bp->flags & CM_BUF_DIRTY)) {
+               buf_Hold(bp);
+           lock_ObtainMutex(&bp->mx);
+           bp->cmFlags &= ~CM_BUF_CMSTORING;
+           bp->flags &= ~CM_BUF_DIRTY;
+           bp->flags |= CM_BUF_ERROR;
+           bp->error = VNOVNODE;
+           bp->dataVersion = -1; /* bad */
+           bp->dirtyCounter++;
+           if (bp->flags & CM_BUF_WAITING) {
+               osi_Log2(buf_logp, "BUF CleanDirtyBuffers Waking [scp 0x%x] bp 0x%x", scp, bp);
+               osi_Wakeup((long) &bp);
+           }
+           lock_ReleaseMutex(&bp->mx);
+           buf_Release(bp);
+       }
+    }
+    return 0;
+}
+#endif