From a31fd7f70f0049a180e5b02202941d3b1266c1f8 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Fri, 22 May 2009 17:00:33 +0000 Subject: [PATCH] windows-btree-flush-race-20090522 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 | 8 ++++++-- src/WINNT/afsd/cm_scache.c | 23 +++++++++++++++++++++-- src/WINNT/afsd/cm_scache.h | 2 +- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/WINNT/afsd/cm_ioctl.c b/src/WINNT/afsd/cm_ioctl.c index 0167bc9f3..c2b1e2b63 100644 --- a/src/WINNT/afsd/cm_ioctl.c +++ b/src/WINNT/afsd/cm_ioctl.c @@ -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); diff --git a/src/WINNT/afsd/cm_scache.c b/src/WINNT/afsd/cm_scache.c index 066781c6b..84eb8664e 100644 --- a/src/WINNT/afsd/cm_scache.c +++ b/src/WINNT/afsd/cm_scache.c @@ -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; } diff --git a/src/WINNT/afsd/cm_scache.h b/src/WINNT/afsd/cm_scache.h index 49c8e8b89..c7b1e0a9c 100644 --- a/src/WINNT/afsd/cm_scache.h +++ b/src/WINNT/afsd/cm_scache.h @@ -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__ */ -- 2.39.5