windows-misc-fix-20061004
[openafs.git] / src / WINNT / afsd / cm_buf.c
index cdfe139..a279116 100644 (file)
@@ -12,9 +12,7 @@
 #include <afs/param.h>
 #include <afs/stds.h>
 
-#ifndef DJGPP
 #include <windows.h>
-#endif
 #include <osi.h>
 #include <stdio.h>
 #include <assert.h>
@@ -89,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);
 }
 
@@ -103,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 = (long)sqrt((double)cm_data.buf_nbuffers);
+    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.
@@ -134,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 */
@@ -342,9 +379,7 @@ long buf_Init(int newFile, cm_buf_ops_t *opsp, afs_uint64 nbuffers)
                                "buf_IncrSyncer");
 
         osi_assertx(phandle != NULL, "buf: can't create incremental sync proc");
-#ifndef DJGPP
         CloseHandle(phandle);
-#endif /* !DJGPP */
     }
 
 #ifdef TESTING
@@ -358,7 +393,6 @@ long buf_Init(int newFile, cm_buf_ops_t *opsp, afs_uint64 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 
@@ -372,43 +406,6 @@ long buf_AddBuffers(afs_uint64 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.
@@ -426,14 +423,6 @@ long buf_SetNBuffers(afs_uint64 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 unlocked scp and returns with locked buffer.
  */
@@ -455,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(afsd_logp, "buf_WaitIO CM_BUF_WAITING already set for 0x%p", bp);
+            osi_Log1(buf_logp, "buf_WaitIO CM_BUF_WAITING already set for 0x%p", bp);
         } else {
-            osi_Log1(afsd_logp, "buf_WaitIO CM_BUF_WAITING set for 0x%p", 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_PTR)bp, &bp->mx);
+
+       smb_UpdateServerPriority();
+
         lock_ObtainMutex(&bp->mx);
-        osi_Log1(afsd_logp, "buf_WaitIO conflict wait done for 0x%p", 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%p", bp);
+            osi_Log1(buf_logp, "buf_WaitIO CM_BUF_WAITING reset for 0x%p", bp);
             bp->flags &= ~CM_BUF_WAITING;
             bp->waitRequests = 0;
         }
@@ -477,7 +469,7 @@ 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(afsd_logp, "buf_WaitIO waking scp 0x%p", scp);
+                osi_Log1(buf_logp, "buf_WaitIO waking scp 0x%p", scp);
                 osi_Wakeup((LONG_PTR)&scp->flags);
             }
            lock_ReleaseMutex(&scp->mx);
@@ -488,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(afsd_logp, "buf_WaitIO Waking bp 0x%p", bp);
+        osi_Log1(buf_logp, "buf_WaitIO Waking bp 0x%p", bp);
         osi_Wakeup((LONG_PTR) bp);
     }
-    osi_Log1(afsd_logp, "WaitIO finished wait for bp 0x%p", 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;
@@ -524,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;
         }
     }
@@ -541,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;
@@ -553,25 +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);
 
-       osi_Log1(afsd_logp, "buf_LockedCleanAsync starts I/O on 0x%p", bp);
-        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_Log2(afsd_logp, "buf_LockedCleanAsync I/O on 0x%p, done=%d", bp, code);
+       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 */
@@ -590,6 +583,7 @@ void buf_LockedCleanAsync(cm_buf_t *bp, cm_req_t *reqp)
         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.
@@ -687,7 +681,11 @@ 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;
@@ -751,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
@@ -786,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];
@@ -917,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. 
@@ -955,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;
@@ -971,9 +971,7 @@ 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;
@@ -987,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
@@ -1065,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 */
@@ -1135,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 */
@@ -1225,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 */
@@ -1240,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;
@@ -1264,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
@@ -1298,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)
@@ -1350,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 */
 
@@ -1360,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);
 
@@ -1374,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);
                 }
@@ -1390,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 */
@@ -1418,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 */
@@ -1431,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) 
@@ -1444,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 */
 
@@ -1558,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