Windows: do not leak scp->dirlock if cm_BPlusDirBuildTree fails
[openafs.git] / src / WINNT / afsd / cm_dir.c
index ceb92ff..c80f8f0 100644 (file)
@@ -854,9 +854,9 @@ int
 cm_DirHash(char *string)
 {
     /* Hash a string to a number between 0 and NHASHENT. */
-    register unsigned char tc;
-    register int hval;
-    register int tval;
+    unsigned char tc;
+    int hval;
+    int tval;
     hval = 0;
     while ((tc = (*string++))) {
        hval *= 173;
@@ -982,8 +982,8 @@ cm_BeginDirOp(cm_scache_t * scp, cm_user_t * userp, cm_req_t * reqp,
     long code;
     int i, mxheld = 0, haveWrite = 0;
 
-    osi_Log3(afsd_logp, "Beginning dirOp[0x%p] for scp[0x%p], userp[0x%p]",
-             op, scp, userp);
+    osi_Log4(afsd_logp, "Beginning dirOp[0x%p] for scp[0x%p], userp[0x%p] lockType[0x%x]",
+             op, scp, userp, lockType);
 
     memset(op, 0, sizeof(*op));
 
@@ -1036,6 +1036,7 @@ cm_BeginDirOp(cm_scache_t * scp, cm_user_t * userp, cm_req_t * reqp,
             default:
                 osi_assert(haveWrite);
             }
+            op->lockType = lockType;
         } else {
             if (!(scp->dirBplus && 
                   scp->dirDataVersion == scp->dataVersion)) 
@@ -1060,7 +1061,7 @@ cm_BeginDirOp(cm_scache_t * scp, cm_user_t * userp, cm_req_t * reqp,
                     bplus_free_tree++;
                     freeBtree(scp->dirBplus);
                     scp->dirBplus = NULL;
-                    scp->dirDataVersion = -1;
+                    scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
                 }
 
                 if (!scp->dirBplus) {
@@ -1068,39 +1069,49 @@ cm_BeginDirOp(cm_scache_t * scp, cm_user_t * userp, cm_req_t * reqp,
                         lock_ReleaseWrite(&scp->rw);
                         mxheld = 0;
                     }
-                    cm_BPlusDirBuildTree(scp, userp, reqp);
+                    code = cm_BPlusDirBuildTree(scp, userp, reqp);
+                    osi_Log1(afsd_logp, "cm_BeginDirOp cm_BPlusDirBuildTree code 0x%x", code);
                     if (!mxheld) {
                         lock_ObtainWrite(&scp->rw);
                         mxheld = 1;
                     }
-                    if (op->dataVersion != scp->dataVersion) {
-                        /* We lost the race, therefore we must update the
-                         * dirop state and retry to build the tree.
-                         */
-                        op->length = scp->length;
-                        op->newLength = op->length;
-                        op->dataVersion = scp->dataVersion;
-                        op->newDataVersion = op->dataVersion;
-                        goto repeat;
+                    if (code) {
+                        bplus_free_tree++;
+                        freeBtree(scp->dirBplus);
+                        scp->dirBplus = NULL;
+                        scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
+                    } else {
+                        if (op->dataVersion != scp->dataVersion) {
+                            /* We lost the race, therefore we must update the
+                             * dirop state and retry to build the tree.
+                            */
+                            op->length = scp->length;
+                            op->newLength = op->length;
+                            op->dataVersion = scp->dataVersion;
+                            op->newDataVersion = op->dataVersion;
+                            goto repeat;
+                        }
+
+                         if (scp->dirBplus)
+                            scp->dirDataVersion = scp->dataVersion;
                     }
-
-                    if (scp->dirBplus)
-                        scp->dirDataVersion = scp->dataVersion;
                 }
             }
 
-            switch (lockType) {
-            case CM_DIRLOCK_NONE:
-                lock_ReleaseWrite(&scp->dirlock);
-                break;
-            case CM_DIRLOCK_READ:
-                lock_ConvertWToR(&scp->dirlock);
-                break;
-            case CM_DIRLOCK_WRITE:
-            default:
-                /* got it already */;
+            if (code == 0) {
+                switch (lockType) {
+                case CM_DIRLOCK_NONE:
+                    lock_ReleaseWrite(&scp->dirlock);
+                    break;
+                case CM_DIRLOCK_READ:
+                    lock_ConvertWToR(&scp->dirlock);
+                    break;
+                case CM_DIRLOCK_WRITE:
+                default:
+                    /* got it already */;
+                }
+                op->lockType = lockType;
             }
-            haveWrite = 0;
         }
 #else
         /* we know that haveWrite matches lockType at this point */
@@ -1118,18 +1129,21 @@ cm_BeginDirOp(cm_scache_t * scp, cm_user_t * userp, cm_req_t * reqp,
         default:
             osi_assert(haveWrite);
         }
-#endif
         op->lockType = lockType;
-        if (mxheld)
-            lock_ReleaseWrite(&scp->rw);
-    } else {
+#endif
+    }
+
+    if (mxheld)
+        lock_ReleaseWrite(&scp->rw);
+
+    if (code) {
         if (haveWrite)
             lock_ReleaseWrite(&scp->dirlock);
         else
             lock_ReleaseRead(&scp->dirlock);
-        if (mxheld)
-            lock_ReleaseWrite(&scp->rw);
         cm_EndDirOp(op);
+
+        osi_Log1(afsd_logp, "cm_BeginDirOp return code 0x%x", code);
     }
 
     return code;
@@ -1177,12 +1191,12 @@ cm_EndDirOp(cm_dirOp_t * op)
 {
     long code = 0;
 
+    osi_Log4(afsd_logp, "Ending dirOp[0x%p] scp[0x%p] lockType[0x%x] with %d dirty buffer releases",
+             op, op->scp, op->lockType, op->dirtyBufCount);
+
     if (op->scp == NULL)
         return 0;
 
-    osi_Log2(afsd_logp, "Ending dirOp 0x%p with %d dirty buffer releases",
-             op, op->dirtyBufCount);
-
     if (op->dirtyBufCount > 0) {
 #ifdef USE_BPLUS
         /* update the data version on the B+ tree */
@@ -1234,6 +1248,9 @@ cm_EndDirOp(cm_dirOp_t * op)
 
     osi_assertx(op->nBuffers == 0, "Buffer leak after dirOp termination");
 
+    if (code)
+        osi_Log1(afsd_logp, "cm_EndDirOp return code 0x%x", code);
+
     return code;
 }
 
@@ -1509,7 +1526,7 @@ cm_DirPrefetchBuffers(cm_dirOp_t * op)
                  offset.HighPart, offset.LowPart);
         lock_ReleaseWrite(&op->scp->rw);
 
-        code = buf_Get(op->scp, &offset, &bufferp);
+        code = buf_Get(op->scp, &offset, &op->req, &bufferp);
 
         lock_ObtainWrite(&op->scp->rw);
 
@@ -1547,7 +1564,6 @@ cm_DirPrefetchBuffers(cm_dirOp_t * op)
         offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(cm_data.buf_blockSize));
     }
 
- done:
     lock_ReleaseWrite(&op->scp->rw);
 
     osi_Log1(afsd_logp, "cm_DirPrefetchBuffers returning code 0x%x", code);
@@ -1657,7 +1673,7 @@ cm_DirGetPage(cm_dirOp_t * op,
             goto _has_buffer;
         }
 
-        code = buf_Get(op->scp, &bufferOffset, &bufferp);
+        code = buf_Get(op->scp, &bufferOffset, &op->req, &bufferp);
         if (code) {
             osi_Log1(afsd_logp, "    buf_Get returned code 0x%x", code);
             bufferp = NULL;