Windows: Add buf_FindAll() and buf_FindAllLocked()
[openafs.git] / src / WINNT / afsd / cm_buf.c
index 11e0d64..5b37eed 100644 (file)
@@ -234,15 +234,25 @@ buf_Sync(int quitOnShutdown)
 
         if (bp->flags & CM_BUF_DIRTY && !(bp->flags & CM_BUF_REDIR)) {
             /* start cleaning the buffer; don't touch log pages since
-            * the log code counts on knowing exactly who is writing
-            * a log page at any given instant.
-            */
+             * the log code counts on knowing exactly who is writing
+             * a log page at any given instant.
+             *
+             * only attempt to write the buffer if the volume might
+             * be online.
+             */
             afs_uint32 dirty;
+            cm_volume_t * volp;
 
-            cm_InitReq(&req);
-            req.flags |= CM_REQ_NORETRY;
-            buf_CleanAsyncLocked(bp, &req, &dirty);
-            wasDirty |= dirty;
+            volp = cm_GetVolumeByFID(&bp->fid);
+            switch (cm_GetVolumeStatus(volp, bp->fid.volume)) {
+            case vl_online:
+            case vl_unknown:
+                cm_InitReq(&req);
+                req.flags |= CM_REQ_NORETRY;
+                buf_CleanAsyncLocked(bp, &req, &dirty);
+                wasDirty |= dirty;
+            }
+            cm_PutVolume(volp);
         }
 
         /* the buffer may or may not have been dirty
@@ -268,6 +278,34 @@ buf_Sync(int quitOnShutdown)
             buf_ReleaseLocked(bp, TRUE);
             lock_ConvertWToR(&buf_globalLock);
         } else {
+            if (buf_ShutdownFlag) {
+                cm_cell_t *cellp;
+                cm_volume_t *volp;
+                char volstr[VL_MAXNAMELEN+12]="";
+                char *ext = "";
+
+                volp = cm_GetVolumeByFID(&bp->fid);
+                if (volp) {
+                    cellp = volp->cellp;
+                    if (bp->fid.volume == volp->vol[RWVOL].ID)
+                        ext = "";
+                    else if (bp->fid.volume == volp->vol[ROVOL].ID)
+                        ext = ".readonly";
+                    else if (bp->fid.volume == volp->vol[BACKVOL].ID)
+                        ext = ".backup";
+                    else
+                        ext = ".nomatch";
+                    snprintf(volstr, sizeof(volstr), "%s%s", volp->namep, ext);
+                } else {
+                    cellp = cm_FindCellByID(bp->fid.cell, CM_FLAG_NOPROBE);
+                    snprintf(volstr, sizeof(volstr), "%u", bp->fid.volume);
+                }
+
+                LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_DIRTY_BUFFER_AT_SHUTDOWN, 
+                         cellp->name, volstr, bp->fid.vnode, bp->fid.unique, 
+                         bp->offset.QuadPart+bp->dirty_offset, bp->dirty_length);
+            }
+
             /* advance the pointer so we don't loop forever */
             lock_ObtainRead(&buf_globalLock);
             bpp = &bp->dirtyp;
@@ -292,7 +330,9 @@ void buf_IncrSyncer(long parm)
            i = SleepEx(5000, 1);
            if (i != 0) 
                 continue;
-       }
+       } else {
+            Sleep(50);
+        }
 
         wasDirty = buf_Sync(1);
     } /* whole daemon's while loop */
@@ -644,6 +684,54 @@ cm_buf_t *buf_Find(struct cm_scache *scp, osi_hyper_t *offsetp)
     return bp;
 }       
 
+/* find a buffer, if any, for a particular file ID and offset.  Assumes
+ * that buf_globalLock is write locked when called.  Uses the all buffer
+ * list.
+ */
+cm_buf_t *buf_FindAllLocked(struct cm_scache *scp, osi_hyper_t *offsetp, afs_uint32 flags)
+{
+    cm_buf_t *bp;
+
+    if (flags == 0) {
+        for(bp = cm_data.buf_allp; bp; bp=bp->allp) {
+            if (cm_FidCmp(&scp->fid, &bp->fid) == 0
+                 && offsetp->LowPart == bp->offset.LowPart
+                 && offsetp->HighPart == bp->offset.HighPart) {
+                buf_HoldLocked(bp);
+                break;
+            }
+        }
+    } else {
+        for(bp = cm_data.buf_allp; bp; bp=bp->allp) {
+            if (cm_FidCmp(&scp->fid, &bp->fid) == 0) {
+                char * fileOffset;
+                
+                fileOffset = offsetp->QuadPart + cm_data.baseAddress;
+                if (fileOffset == bp->datap) {
+                    buf_HoldLocked(bp);
+                    break;
+                }
+            }
+        }
+    }
+    /* return whatever we found, if anything */
+    return bp;
+}
+
+/* find a buffer with offset *offsetp for vnode *scp.  Called
+ * with no locks held.  Use the all buffer list.
+ */
+cm_buf_t *buf_FindAll(struct cm_scache *scp, osi_hyper_t *offsetp, afs_uint32 flags)
+{
+    cm_buf_t *bp;
+
+    lock_ObtainRead(&buf_globalLock);
+    bp = buf_FindAllLocked(scp, offsetp, flags);
+    lock_ReleaseRead(&buf_globalLock);
+
+    return bp;
+}       
+
 /* start cleaning I/O on this buffer.  Buffer must be write locked, and is returned
  * write-locked.
  *
@@ -721,7 +809,14 @@ afs_uint32 buf_CleanAsyncLocked(cm_buf_t *bp, cm_req_t *reqp, afs_uint32 *pisdir
         */
        if (reqp->flags & CM_REQ_NORETRY)
            break;
-    };
+
+        /* Ditto if the hardDeadTimeout or idleTimeout was reached */
+        if (code == CM_ERROR_TIMEDOUT || code == CM_ERROR_ALLDOWN ||
+            code == CM_ERROR_ALLBUSY || code == CM_ERROR_ALLOFFLINE ||
+            code == CM_ERROR_CLOCKSKEW) {
+            break;
+        }
+    }
 
     /* if someone was waiting for the I/O that just completed or failed,
      * wake them up.
@@ -814,14 +909,11 @@ void buf_Recycle(cm_buf_t *bp)
  * space from the buffer pool.  In that case, the buffer will be returned
  * without being hashed into the hash table.
  */
-long buf_GetNewLocked(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bufpp)
+long buf_GetNewLocked(struct cm_scache *scp, osi_hyper_t *offsetp, cm_req_t *reqp, cm_buf_t **bufpp)
 {
     cm_buf_t *bp;      /* buffer we're dealing with */
     cm_buf_t *nextBp;  /* next buffer in file hash chain */
     afs_uint32 i;      /* temp */
-    cm_req_t req;
-
-    cm_InitReq(&req);  /* just in case */
 
 #ifdef TESTING
     buf_ValidateBufQueues();
@@ -922,7 +1014,7 @@ long buf_GetNewLocked(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bu
                  * have the WRITING flag set, so we won't get
                  * back here.
                  */
-                buf_CleanAsync(bp, &req, NULL);
+                buf_CleanAsync(bp, reqp, NULL);
 
                 /* now put it back and go around again */
                 buf_Release(bp);
@@ -1014,7 +1106,7 @@ long buf_GetNewLocked(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bu
 /* get a page, returning it held but unlocked.  Doesn't fill in the page
  * with I/O, since we're going to write the whole thing new.
  */
-long buf_GetNew(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bufpp)
+long buf_GetNew(struct cm_scache *scp, osi_hyper_t *offsetp, cm_req_t *reqp, cm_buf_t **bufpp)
 {
     cm_buf_t *bp;
     long code;
@@ -1033,7 +1125,7 @@ long buf_GetNew(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bufpp)
         }
 
         /* otherwise, we have to create a page */
-        code = buf_GetNewLocked(scp, &pageOffset, &bp);
+        code = buf_GetNewLocked(scp, &pageOffset, reqp, &bp);
 
         /* check if the buffer was created in a race condition branch.
          * If so, go around so we can hold a reference to it. 
@@ -1066,7 +1158,7 @@ long buf_GetNew(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bufpp)
 
 /* get a page, returning it held but unlocked.  Make sure it is complete */
 /* The scp must be unlocked when passed to this function */
-long buf_Get(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bufpp)
+long buf_Get(struct cm_scache *scp, osi_hyper_t *offsetp, cm_req_t *reqp, cm_buf_t **bufpp)
 {
     cm_buf_t *bp;
     long code;
@@ -1100,7 +1192,7 @@ long buf_Get(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bufpp)
         }
 
         /* otherwise, we have to create a page */
-        code = buf_GetNewLocked(scp, &pageOffset, &bp);
+        code = buf_GetNewLocked(scp, &pageOffset, reqp, &bp);
        /* bp->mx is now held */
 
         /* check if the buffer was created in a race condition branch.
@@ -1230,7 +1322,7 @@ long buf_CountFreeList(void)
 }
 
 /* clean a buffer synchronously */
-long buf_CleanAsync(cm_buf_t *bp, cm_req_t *reqp, afs_uint32 *pisdirty)
+afs_uint32 buf_CleanAsync(cm_buf_t *bp, cm_req_t *reqp, afs_uint32 *pisdirty)
 {
     long code;
     osi_assertx(bp->magic == CM_BUF_MAGIC, "invalid cm_buf_t magic");
@@ -1728,6 +1820,15 @@ long buf_CleanVnode(struct cm_scache *scp, cm_user_t *userp, cm_req_t *reqp)
                     bp->dataVersion = CM_BUF_VERSION_BAD;
                     bp->dirtyCounter++;
                     break;
+                case CM_ERROR_TIMEDOUT:
+                case CM_ERROR_ALLDOWN:
+                case CM_ERROR_ALLBUSY:
+                case CM_ERROR_ALLOFFLINE:
+                case CM_ERROR_CLOCKSKEW:
+                    /* do not mark the buffer in error state but do
+                     * not attempt to complete the rest either.
+                     */
+                    break;
                 default:
                     code = buf_CleanAsyncLocked(bp, reqp, &wasDirty);
                     if (bp->flags & CM_BUF_ERROR) {
@@ -1820,11 +1921,11 @@ int cm_DumpBufHashTable(FILE *outputFile, char *cookie, int lock)
            StringCbPrintfA(output, sizeof(output), 
                            "%s bp=0x%08X, hash=%d, fid (cell=%d, volume=%d, "
                            "vnode=%d, unique=%d), offset=%x:%08x, dv=%I64d, "
-                           "flags=0x%x, cmFlags=0x%x, refCount=%d\r\n",
+                           "flags=0x%x, cmFlags=0x%x, error=0x%x, refCount=%d\r\n",
                             cookie, (void *)bp, i, bp->fid.cell, bp->fid.volume, 
                             bp->fid.vnode, bp->fid.unique, bp->offset.HighPart, 
                             bp->offset.LowPart, bp->dataVersion, bp->flags, 
-                            bp->cmFlags, bp->refCount);
+                            bp->cmFlags, bp->error, bp->refCount);
            WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
         }
     }
@@ -1838,11 +1939,11 @@ int cm_DumpBufHashTable(FILE *outputFile, char *cookie, int lock)
        StringCbPrintfA(output, sizeof(output), 
                         "%s bp=0x%08X, fid (cell=%d, volume=%d, "
                         "vnode=%d, unique=%d), offset=%x:%08x, dv=%I64d, "
-                        "flags=0x%x, cmFlags=0x%x, refCount=%d\r\n",
+                        "flags=0x%x, cmFlags=0x%x, error=0x%x, refCount=%d\r\n",
                         cookie, (void *)bp, bp->fid.cell, bp->fid.volume, 
                         bp->fid.vnode, bp->fid.unique, bp->offset.HighPart, 
                         bp->offset.LowPart, bp->dataVersion, bp->flags, 
-                        bp->cmFlags, bp->refCount);
+                        bp->cmFlags, bp->error, bp->refCount);
        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
     }
     StringCbPrintfA(output, sizeof(output), "%s - Done dumping buf_FreeListEndp.\r\n", cookie);
@@ -1854,11 +1955,11 @@ int cm_DumpBufHashTable(FILE *outputFile, char *cookie, int lock)
        StringCbPrintfA(output, sizeof(output), 
                         "%s bp=0x%08X, fid (cell=%d, volume=%d, "
                         "vnode=%d, unique=%d), offset=%x:%08x, dv=%I64d, "
-                        "flags=0x%x, cmFlags=0x%x, refCount=%d\r\n",
+                        "flags=0x%x, cmFlags=0x%x, error=0x%x, refCount=%d\r\n",
                         cookie, (void *)bp, bp->fid.cell, bp->fid.volume, 
                         bp->fid.vnode, bp->fid.unique, bp->offset.HighPart, 
                         bp->offset.LowPart, bp->dataVersion, bp->flags, 
-                        bp->cmFlags, bp->refCount);
+                        bp->cmFlags, bp->error, bp->refCount);
        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
     }
     StringCbPrintfA(output, sizeof(output), "%s - Done dumping buf_dirtyListp.\r\n", cookie);