windows-btree-flush-race-20090522
authorJeffrey Altman <jaltman@secure-endpoints.com>
Fri, 22 May 2009 17:00:33 +0000 (17:00 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Fri, 22 May 2009 17:00:33 +0000 (17:00 +0000)
LICENSE MIT
FIXES 124787

A flush operation on a directory will result in the btree being destroyed.
This can race with on-going operations.  Make sure that the dirlock is held
if the btree is destroyed.  Otherwise, just invalidate the btree version
number.

====================
This delta was composed from multiple commits as part of the CVS->Git migration.
The checkin message with each commit was inconsistent.
The following are the additional commit messages.
====================
LICENSE MIT
FIXES 124787

correct sandbox leakage

src/WINNT/afsd/cm_ioctl.c
src/WINNT/afsd/cm_scache.c
src/WINNT/afsd/cm_scache.h

index 0167bc9..c2b1e2b 100644 (file)
@@ -102,10 +102,14 @@ cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
 
     code = buf_FlushCleanPages(scp, userp, reqp);
         
+    if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
+        lock_ObtainWrite(&scp->dirlock);
     lock_ObtainWrite(&scp->rw);
     cm_DiscardSCache(scp);
-    if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
-        cm_ResetSCacheDirectory(scp);
+    if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
+        cm_ResetSCacheDirectory(scp, 1);
+        lock_ReleaseWrite(&scp->dirlock);
+    }
     lock_ReleaseWrite(&scp->rw);
 
     osi_Log2(afsd_logp,"cm_FlushFile scp 0x%x returns error: [%x]",scp, code);
index 066781c..84eb866 100644 (file)
@@ -76,17 +76,36 @@ void cm_RemoveSCacheFromHashTable(cm_scache_t *scp)
 }
 
 /* called with cm_scacheLock and scp write-locked */
-void cm_ResetSCacheDirectory(cm_scache_t *scp)
+void cm_ResetSCacheDirectory(cm_scache_t *scp, afs_int32 dirlock)
 {
 #ifdef USE_BPLUS
     /* destroy directory Bplus Tree */
     if (scp->dirBplus) {
         LARGE_INTEGER start, end;
+
+        if (!dirlock && !lock_TryWrite(&scp->dirlock)) {
+            /* 
+             * We are not holding the dirlock and obtaining it
+             * requires that we drop the scp->rw.  As a result
+             * we will leave the dirBplus tree intact but 
+             * invalidate the version number so that whatever
+             * operation is currently active can safely complete
+             * but the contents will be ignored on the next 
+             * directory operation.
+             */
+            scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
+            return;
+        }
+
         QueryPerformanceCounter(&start);
         bplus_free_tree++;
         freeBtree(scp->dirBplus);
         scp->dirBplus = NULL;
+        scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
         QueryPerformanceCounter(&end);
+        
+        if (!dirlock) 
+            lock_ReleaseWrite(&scp->dirlock);
 
         bplus_free_time += (end.QuadPart - start.QuadPart);
     }
@@ -222,7 +241,7 @@ long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
      */
     cm_FreeAllACLEnts(scp);
 
-    cm_ResetSCacheDirectory(scp);
+    cm_ResetSCacheDirectory(scp, 0);
     return 0;
 }
 
index 49c8e8b..c7b1e0a 100644 (file)
@@ -419,5 +419,5 @@ extern void cm_AdjustScacheLRU(cm_scache_t *scp);
 
 extern int cm_DumpSCache(FILE *outputFile, char *cookie, int lock);
 
-extern void cm_ResetSCacheDirectory(cm_scache_t *scp);
+extern void cm_ResetSCacheDirectory(cm_scache_t *scp, afs_int32 locked);
 #endif /*  __CM_SCACHE_H_ENV__ */