From: Jeffrey Altman Date: Wed, 29 Dec 2010 16:35:17 +0000 (-0500) Subject: Windows: buf_CleanAsync scp->fid == bp->fid X-Git-Tag: upstream/1.6.0.pre2^2~94 X-Git-Url: https://git.michaelhowe.org/gitweb/?a=commitdiff_plain;h=63503dfda678e08fd76f5c3e5561449d663933e0;p=packages%2Fo%2Fopenafs.git Windows: buf_CleanAsync scp->fid == bp->fid If buf_CleanAsync or buf_CleanAsyncLocked are called with a non-NULL cm_scache_t parameter, that status object's fid must be the same as the associated cm_buf_t object. If not, the wrong locks will be held. If the cm_scache_t parameter is NULL and cm_FindSCache() returns NULL, it means that the cm_scache_t object associated with the bp->fid has been flushed from the cache. cm_GetSCache() must therefore be called to allocate a new status object for the FID. If the status object cannot be allocated, then any dirty data stored in the buffer will be discarded. Reviewed-on: http://gerrit.openafs.org/3604 Tested-by: BuildBot Tested-by: Jeffrey Altman Reviewed-by: Jeffrey Altman (cherry picked from commit b6576d8cb554af50dfe7b6d9b668bd35ff202a83) Change-Id: I41b190d15bff93be656c6f844a740cce9812ae04 Reviewed-on: http://gerrit.openafs.org/3810 Reviewed-by: Derrick Brashear Tested-by: Derrick Brashear --- diff --git a/src/WINNT/afsd/cm_buf.c b/src/WINNT/afsd/cm_buf.c index 5a30adc0d..72cc7ffe2 100644 --- a/src/WINNT/afsd/cm_buf.c +++ b/src/WINNT/afsd/cm_buf.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -740,6 +739,9 @@ cm_buf_t *buf_FindAll(struct cm_scache *scp, osi_hyper_t *offsetp, afs_uint32 fl * if this buffer contains logged data. * * Returns non-zero if the buffer was dirty. + * + * 'scp' may or may not be NULL. If it is not NULL, the FID for both cm_scache_t + * and cm_buf_t must match. */ afs_uint32 buf_CleanAsyncLocked(cm_scache_t *scp, cm_buf_t *bp, cm_req_t *reqp, afs_uint32 flags, afs_uint32 *pisdirty) @@ -750,35 +752,54 @@ afs_uint32 buf_CleanAsyncLocked(cm_scache_t *scp, cm_buf_t *bp, cm_req_t *reqp, int release_scp = 0; osi_assertx(bp->magic == CM_BUF_MAGIC, "invalid cm_buf_t magic"); + osi_assertx(scp == NULL || cm_FidCmp(&scp->fid, &bp->fid) == 0, "scp fid != bp fid"); - if (scp = cm_FindSCache(&bp->fid)) - release_scp = 1; - - if (!scp) { - osi_Log1(buf_logp, "buf_CleanAsyncLocked unable to start I/O - scp not found buf 0x%p", bp); - code = CM_ERROR_NOSUCHFILE; + /* + * If the matching cm_scache_t was not provided as a parameter + * we must either find one or allocate a new one. It is possible + * that the cm_scache_t was recycled out of the cache even though + * a cm_buf_t with the same FID is in the cache. + */ + if (scp == NULL) { + if ((scp = cm_FindSCache(&bp->fid)) || + (cm_GetSCache(&bp->fid, &scp, + bp->userp ? bp->userp : cm_rootUserp, + reqp) == 0)) { + release_scp = 1; + } } while ((bp->flags & CM_BUF_DIRTY) == CM_BUF_DIRTY) { isdirty = 1; lock_ReleaseMutex(&bp->mx); - osi_Log2(buf_logp, "buf_CleanAsyncLocked starts I/O on scp 0x%p buf 0x%p", scp, bp); + if (!scp) { + /* + * If we didn't find a cm_scache_t object for bp->fid it means + * that we no longer have that FID in the cache. It does not + * mean that the object does not exist in the cell. That may + * in fact be the case but we don't know that until we attempt + * a FetchStatus on the FID. + */ + osi_Log1(buf_logp, "buf_CleanAsyncLocked unable to start I/O - scp not found buf 0x%p", bp); + code = CM_ERROR_NOSUCHFILE; + } else { + osi_Log2(buf_logp, "buf_CleanAsyncLocked starts I/O on scp 0x%p buf 0x%p", scp, bp); - offset = bp->offset; - LargeIntegerAdd(offset, ConvertLongToLargeInteger(bp->dirty_offset)); - code = (*cm_buf_opsp->Writep)(scp, &offset, + offset = bp->offset; + LargeIntegerAdd(offset, ConvertLongToLargeInteger(bp->dirty_offset)); + code = (*cm_buf_opsp->Writep)(scp, &offset, #if 1 - /* we might as well try to write all of the contiguous - * dirty buffers in one RPC - */ - cm_chunkSize, + /* we might as well try to write all of the contiguous + * dirty buffers in one RPC + */ + cm_chunkSize, #else - bp->dirty_length, + bp->dirty_length, #endif - flags, bp->userp, reqp); - osi_Log3(buf_logp, "buf_CleanAsyncLocked I/O on scp 0x%p buf 0x%p, done=%d", scp, bp, code); - + flags, bp->userp, reqp); + osi_Log3(buf_logp, "buf_CleanAsyncLocked I/O on scp 0x%p buf 0x%p, done=%d", scp, bp, code); + } lock_ObtainMutex(&bp->mx); /* if the Write routine returns No Such File, clear the dirty flag * because we aren't going to be able to write this data to the file @@ -1021,7 +1042,10 @@ long buf_GetNewLocked(struct cm_scache *scp, osi_hyper_t *offsetp, cm_req_t *req * have the WRITING flag set, so we won't get * back here. */ - buf_CleanAsync(scp, bp, reqp, 0, NULL); + if (cm_FidCmp(&scp->fid, &bp->fid) == 0) + buf_CleanAsync(scp, bp, reqp, 0, NULL); + else + buf_CleanAsync(NULL, bp, reqp, 0, NULL); /* now put it back and go around again */ buf_Release(bp);