From cf0d1393f4df2c0a8840aa00db05de7bd221c275 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Wed, 31 Oct 2007 15:23:42 +0000 Subject: [PATCH] windows-begindirop-20071031 Avoid a race condition in cm_BeginDirOp() caused by the failure to hold the cm_scache_t mutex while copying status data from the scp to the dirop --- src/WINNT/afsd/cm_dir.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/WINNT/afsd/cm_dir.c b/src/WINNT/afsd/cm_dir.c index 153d88ed2..1beef9446 100644 --- a/src/WINNT/afsd/cm_dir.c +++ b/src/WINNT/afsd/cm_dir.c @@ -98,7 +98,7 @@ static int cm_DirOpDelBuffer(cm_dirOp_t * op, cm_buf_t * buffer, int flags); static long -cm_DirCheckStatus(cm_dirOp_t * op); +cm_DirCheckStatus(cm_dirOp_t * op, afs_uint32 locked); static long cm_DirReleasePage(cm_dirOp_t * op, cm_buf_t ** bufferpp, int modified); @@ -956,9 +956,9 @@ cm_DirFindItem(cm_dirOp_t * op, } } -/* Begin a sequence of directory operations. scp->mx should be - locked. -*/ +/* Begin a sequence of directory operations. + * Called with scp->mx should unlocked. + */ long cm_BeginDirOp(cm_scache_t * scp, cm_user_t * userp, cm_req_t * reqp, afs_uint32 lockType, cm_dirOp_t * op) @@ -984,13 +984,16 @@ cm_BeginDirOp(cm_scache_t * scp, cm_user_t * userp, cm_req_t * reqp, op->buffers[i].flags = 0; } - code = cm_DirCheckStatus(op); - + lock_ObtainMutex(&scp->mx); + mxheld = 1; + code = cm_DirCheckStatus(op, 1); if (code == 0) { op->length = scp->length; op->newLength = op->length; op->dataVersion = scp->dataVersion; op->newDataVersion = op->dataVersion; + lock_ReleaseMutex(&scp->mx); + mxheld = 0; #ifdef USE_BPLUS lock_ObtainRead(&scp->dirlock); @@ -998,8 +1001,6 @@ cm_BeginDirOp(cm_scache_t * scp, cm_user_t * userp, cm_req_t * reqp, (scp->dirBplus && scp->dirDataVersion == scp->dataVersion)) { - int mxheld = 0; - switch (lockType) { case CM_DIRLOCK_NONE: lock_ReleaseRead(&scp->dirlock); @@ -1061,6 +1062,9 @@ cm_BeginDirOp(cm_scache_t * scp, cm_user_t * userp, cm_req_t * reqp, cm_EndDirOp(op); } + if (mxheld) + lock_ReleaseMutex(&scp->mx); + return code; } @@ -1074,7 +1078,7 @@ cm_CheckDirOpForSingleChange(cm_dirOp_t * op) if (op->scp == NULL) return 0; - code = cm_DirCheckStatus(op); + code = cm_DirCheckStatus(op, 0); if (code == 0 && op->dataVersion == op->scp->dataVersion - 1) { @@ -1369,23 +1373,25 @@ cm_DirOpDelBuffer(cm_dirOp_t * op, cm_buf_t * bufferp, int flags) This should be called before cm_DirGetPage() is called per scp. On entry: - scp->mx unlocked + scp->mx locked state indicated by parameter On exit: - scp->mx unlocked + scp->mx same state as upon entry During: scp->mx may be released */ static long -cm_DirCheckStatus(cm_dirOp_t * op) +cm_DirCheckStatus(cm_dirOp_t * op, afs_uint32 locked) { long code; - lock_ObtainMutex(&op->scp->mx); + if (!locked) + lock_ObtainMutex(&op->scp->mx); code = cm_SyncOp(op->scp, NULL, op->userp, &op->req, PRSFS_LOOKUP, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS); - lock_ReleaseMutex(&op->scp->mx); + if (!locked) + lock_ReleaseMutex(&op->scp->mx); osi_Log2(afsd_logp, "cm_DirCheckStatus for op 0x%p returning code 0x%x", op, code); -- 2.39.5