From df13fd4cb042c65e93d97bc912aac94d9a5e8096 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Fri, 29 Feb 2008 22:59:52 +0000 Subject: [PATCH] DEVEL15-windows-cm-buf-misc-20080229 LICENSE MIT (1) Add an undocumented store behind mode for use in testing. Set EnableSMBAsyncStore to 2. When set all smb_WriteData calls are background writes, all calls to cm_FSync are skipped and file close operations do not block for dirty buffers to be written. This permits all writes to be performed in the buf_IncrSyncer thread. (2) Do not use I64 in osi_Log() format strings as all parameters are converted to size_t which is 32-bit on 32-bit Windows. (3) Reduce the number of times the cm_buf_t mutex is obtained, dropped, obtained, dropped in buf_IncrSyncer (4) In buf_CleanAsyncLocked, request that a full chunk be written instead of just the current buffer. cm_SetupStoreBIOD will stop at the first clean buffer. This reduces the overall number of RPCs that must be performed. (5) Define CM_BUF_VERSION_BAD and use it instead of -1. (cherry picked from commit 114de458ca7717cf0bcda90df61f24495fe8f922) --- src/WINNT/afsd/afsd_init.c | 2 +- src/WINNT/afsd/cm_buf.c | 60 ++++++++++++++++++++------------------ src/WINNT/afsd/cm_buf.h | 2 ++ src/WINNT/afsd/cm_dcache.c | 26 +++++++++++------ src/WINNT/afsd/cm_dir.c | 4 +-- src/WINNT/afsd/cm_scache.c | 5 ++-- src/WINNT/afsd/smb.c | 16 +++++----- 7 files changed, 65 insertions(+), 50 deletions(-) diff --git a/src/WINNT/afsd/afsd_init.c b/src/WINNT/afsd/afsd_init.c index d59955e1f8..95b9239f48 100644 --- a/src/WINNT/afsd/afsd_init.c +++ b/src/WINNT/afsd/afsd_init.c @@ -1401,7 +1401,7 @@ int afsd_InitSMB(char **reasonP, void *aMBfunc) code = RegQueryValueEx(parmKey, "EnableSMBAsyncStore", NULL, NULL, (BYTE *) &dwValue, &dummyLen); if (code == ERROR_SUCCESS) - smb_AsyncStore = dwValue ? 1 : 0; + smb_AsyncStore = dwValue == 2 ? 2 : (dwValue ? 1 : 0); afsi_log("EnableSMBAsyncStore = %d", smb_AsyncStore); dummyLen = sizeof(DWORD); diff --git a/src/WINNT/afsd/cm_buf.c b/src/WINNT/afsd/cm_buf.c index 434558500c..8aaf6036e3 100644 --- a/src/WINNT/afsd/cm_buf.c +++ b/src/WINNT/afsd/cm_buf.c @@ -200,11 +200,10 @@ void buf_IncrSyncer(long parm) /* now go through our percentage of the buffers */ for (bpp = &cm_data.buf_dirtyListp; bp = *bpp; ) { - /* all dirty buffers are held when they are added to the * dirty list. No need for an additional hold. */ - + lock_ObtainMutex(&bp->mx); if (bp->flags & CM_BUF_DIRTY) { /* start cleaning the buffer; don't touch log pages since * the log code counts on knowing exactly who is writing @@ -212,33 +211,27 @@ void buf_IncrSyncer(long parm) */ cm_InitReq(&req); req.flags |= CM_REQ_NORETRY; - wasDirty |= buf_CleanAsync(bp, &req); + wasDirty |= buf_CleanAsyncLocked(bp, &req); } /* the buffer may or may not have been dirty * and if dirty may or may not have been cleaned * successfully. check the dirty flag again. */ - if (!(bp->flags & CM_BUF_DIRTY)) { - lock_ObtainMutex(&bp->mx); - if (!(bp->flags & CM_BUF_DIRTY)) { - /* remove the buffer from the dirty list */ - lock_ObtainWrite(&buf_globalLock); - *bpp = bp->dirtyp; - bp->dirtyp = NULL; - if (cm_data.buf_dirtyListp == NULL) - cm_data.buf_dirtyListEndp = NULL; - buf_ReleaseLocked(bp, TRUE); - lock_ReleaseWrite(&buf_globalLock); - } else { - /* advance the pointer so we don't loop forever */ - bpp = &bp->dirtyp; - } - lock_ReleaseMutex(&bp->mx); - } else { - /* advance the pointer so we don't loop forever */ - bpp = &bp->dirtyp; - } + if (!(bp->flags & CM_BUF_DIRTY)) { + /* remove the buffer from the dirty list */ + lock_ObtainWrite(&buf_globalLock); + *bpp = bp->dirtyp; + bp->dirtyp = NULL; + if (cm_data.buf_dirtyListp == NULL) + cm_data.buf_dirtyListEndp = NULL; + buf_ReleaseLocked(bp, TRUE); + lock_ReleaseWrite(&buf_globalLock); + } else { + /* advance the pointer so we don't loop forever */ + bpp = &bp->dirtyp; + } + lock_ReleaseMutex(&bp->mx); } /* for loop over a bunch of buffers */ } /* whole daemon's while loop */ } @@ -653,7 +646,16 @@ long buf_CleanAsyncLocked(cm_buf_t *bp, cm_req_t *reqp) offset = bp->offset; LargeIntegerAdd(offset, ConvertLongToLargeInteger(bp->dirty_offset)); - code = (*cm_buf_opsp->Writep)(scp, &offset, bp->dirty_length, 0, bp->userp, reqp); + 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, +#else + bp->dirty_length, +#endif + 0, bp->userp, reqp); osi_Log3(buf_logp, "buf_CleanAsyncLocked I/O on scp 0x%p buf 0x%p, done=%d", scp, bp, code); cm_ReleaseSCache(scp); @@ -674,7 +676,7 @@ long buf_CleanAsyncLocked(cm_buf_t *bp, cm_req_t *reqp) bp->dirty_offset = 0; bp->dirty_length = 0; bp->error = code; - bp->dataVersion = -1; /* bad */ + bp->dataVersion = CM_BUF_VERSION_BAD; /* bad */ bp->dirtyCounter++; } @@ -910,7 +912,7 @@ long buf_GetNewLocked(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bu /* clean up junk flags */ bp->flags &= ~(CM_BUF_EOF | CM_BUF_ERROR); - bp->dataVersion = -1; /* unknown so far */ + bp->dataVersion = CM_BUF_VERSION_BAD; /* unknown so far */ /* now hash in as our new buffer, and give it the * appropriate label, if requested. @@ -1468,7 +1470,7 @@ long buf_Truncate(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp, bufp->flags &= ~CM_BUF_DIRTY; bufp->dirty_offset = 0; bufp->dirty_length = 0; - bufp->dataVersion = -1; /* known bad */ + bufp->dataVersion = CM_BUF_VERSION_BAD; /* known bad */ bufp->dirtyCounter++; } else { @@ -1559,7 +1561,7 @@ long buf_FlushCleanPages(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp) bp->error = CM_ERROR_BADFD; bp->dirty_offset = 0; bp->dirty_length = 0; - bp->dataVersion = -1; /* known bad */ + bp->dataVersion = CM_BUF_VERSION_BAD; /* known bad */ bp->dirtyCounter++; lock_ReleaseMutex(&bp->mx); } @@ -1851,7 +1853,7 @@ long buf_CleanDirtyBuffers(cm_scache_t *scp) bp->dirty_length = 0; bp->flags |= CM_BUF_ERROR; bp->error = VNOVNODE; - bp->dataVersion = -1; /* bad */ + bp->dataVersion = CM_BUF_VERSION_BAD; /* bad */ bp->dirtyCounter++; if (bp->flags & CM_BUF_WAITING) { osi_Log2(buf_logp, "BUF CleanDirtyBuffers Waking [scp 0x%x] bp 0x%x", scp, bp); diff --git a/src/WINNT/afsd/cm_buf.h b/src/WINNT/afsd/cm_buf.h index c3c3ff1d65..572a8f4b6e 100644 --- a/src/WINNT/afsd/cm_buf.h +++ b/src/WINNT/afsd/cm_buf.h @@ -44,6 +44,8 @@ extern int buf_cacheType; #define CM_BUF_MAGIC ('B' | 'U' <<8 | 'F'<<16 | 'F'<<24) +#define CM_BUF_VERSION_BAD 0xFFFFFFFFFFFFFFFF + /* represents a single buffer */ typedef struct cm_buf { osi_queue_t q; /* queue of all zero-refcount buffers */ diff --git a/src/WINNT/afsd/cm_dcache.c b/src/WINNT/afsd/cm_dcache.c index c03b1b31ac..93cb73aea0 100644 --- a/src/WINNT/afsd/cm_dcache.c +++ b/src/WINNT/afsd/cm_dcache.c @@ -569,7 +569,7 @@ long cm_CheckFetchRange(cm_scache_t *scp, osi_hyper_t *startBasep, osi_hyper_t * /* We cheat slightly by not locking the bp mutex. */ if (bp) { if ((bp->cmFlags & (CM_BUF_CMFETCHING | CM_BUF_CMSTORING)) == 0 - && bp->dataVersion != scp->dataVersion) + && (bp->dataVersion < scp->bufDataVersionLow || bp->dataVersion > scp->dataVersion)) stop = 1; buf_Release(bp); bp = NULL; @@ -1377,13 +1377,13 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *userp * which case we just retry. */ if (bufp->dataVersion <= scp->dataVersion && bufp->dataVersion >= scp->bufDataVersionLow || biod.length == 0) { - if ((bufp->dataVersion == -1 || bufp->dataVersion < scp->dataVersion) && + if ((bufp->dataVersion == CM_BUF_VERSION_BAD || bufp->dataVersion < scp->bufDataVersionLow) && LargeIntegerGreaterThanOrEqualTo(bufp->offset, scp->serverLength)) { - osi_Log3(afsd_logp, "Bad DVs %I64d, %I64d or length 0x%x", - bufp->dataVersion, scp->dataVersion, biod.length); + osi_Log4(afsd_logp, "Bad DVs 0x%x != (0x%x -> 0x%x) or length 0x%x", + bufp->dataVersion, scp->bufDataVersionLow, scp->dataVersion, biod.length); - if (bufp->dataVersion == -1) + if (bufp->dataVersion == CM_BUF_VERSION_BAD) memset(bufp->datap, 0, cm_data.buf_blockSize); bufp->dataVersion = scp->dataVersion; } @@ -1391,6 +1391,15 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *userp cm_ReleaseBIOD(&biod, 0, 0); lock_ObtainMutex(&scp->mx); return 0; + } else if ((bufp->dataVersion == CM_BUF_VERSION_BAD || bufp->dataVersion < scp->bufDataVersionLow) + && (scp->mask & CM_SCACHEMASK_TRUNCPOS) && + LargeIntegerGreaterThanOrEqualTo(bufp->offset, scp->truncPos)) { + memset(bufp->datap, 0, cm_data.buf_blockSize); + bufp->dataVersion = scp->dataVersion; + lock_ReleaseMutex(&scp->mx); + cm_ReleaseBIOD(&biod, 0, 0); + lock_ObtainMutex(&scp->mx); + return 0; } lock_ReleaseMutex(&scp->mx); @@ -1401,10 +1410,9 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *userp require_64bit_ops = 1; } -#ifdef DISKCACHE95 - DPRINTF("cm_GetBuffer: fetching data scpDV=%I64d bufDV=%I64d scp=%x bp=%x dcp=%x\n", - scp->dataVersion, bufp->dataVersion, scp, bufp, bufp->dcp); -#endif /* DISKCACHE95 */ + osi_Log2(afsd_logp, "cm_GetBuffer: fetching data scp %p bufp %p", scp, bufp); + osi_Log3(afsd_logp, "cm_GetBuffer: fetching data scpDV 0x%x scpDVLow 0x%x bufDV 0x%x", + scp->dataVersion, scp->bufDataVersionLow, bufp->dataVersion); #ifdef AFS_FREELANCE_CLIENT diff --git a/src/WINNT/afsd/cm_dir.c b/src/WINNT/afsd/cm_dir.c index 1305a87b0f..f52fb188dd 100644 --- a/src/WINNT/afsd/cm_dir.c +++ b/src/WINNT/afsd/cm_dir.c @@ -1151,7 +1151,7 @@ cm_CheckDirOpForSingleChange(cm_dirOp_t * op) osi_Log0(afsd_logp, "cm_CheckDirOpForSingleChange succeeded"); else osi_Log3(afsd_logp, - "cm_CheckDirOpForSingleChange failed. code=0x%x, old dv=%I64d, new dv=%I64d", + "cm_CheckDirOpForSingleChange failed. code=0x%x, old dv=%d, new dv=%d", code, op->dataVersion, op->scp->dataVersion); return rc; } @@ -1272,7 +1272,7 @@ cm_DirOpAddBuffer(cm_dirOp_t * op, cm_buf_t * bufferp) CM_SCACHESYNC_BUFLOCKED); if (code == 0 && bufferp->dataVersion != op->dataVersion) { - osi_Log2(afsd_logp, "cm_DirOpAddBuffer: buffer data version mismatch. buf dv = %I64d. needs %I64d", + osi_Log2(afsd_logp, "cm_DirOpAddBuffer: buffer data version mismatch. buf dv = %d. needs %d", bufferp->dataVersion, op->dataVersion); cm_SyncOpDone(op->scp, bufferp, diff --git a/src/WINNT/afsd/cm_scache.c b/src/WINNT/afsd/cm_scache.c index 953d88f0da..8b55ca9843 100644 --- a/src/WINNT/afsd/cm_scache.c +++ b/src/WINNT/afsd/cm_scache.c @@ -1579,7 +1579,7 @@ void cm_MergeStatus(cm_scache_t *dscp, if (volp) cm_PutVolume(volp); } - osi_Log3(afsd_logp, "Bad merge, scp %x, scp dv %I64d, RPC dv %I64d", + osi_Log3(afsd_logp, "Bad merge, scp %x, scp dv %d, RPC dv %d", scp, scp->dataVersion, dataVersion); /* we have a number of data fetch/store operations running * concurrently, and we can tell which one executed last at the @@ -1724,7 +1724,8 @@ void cm_MergeStatus(cm_scache_t *dscp, * the size of the file. */ if (((flags & CM_MERGEFLAG_STOREDATA) && dataVersion - scp->dataVersion > 1) || - (!(flags & CM_MERGEFLAG_STOREDATA) && scp->dataVersion != dataVersion)) + (!(flags & CM_MERGEFLAG_STOREDATA) && scp->dataVersion != dataVersion) || + scp->bufDataVersionLow == 0) scp->bufDataVersionLow = dataVersion; scp->dataVersion = dataVersion; diff --git a/src/WINNT/afsd/smb.c b/src/WINNT/afsd/smb.c index 728c85c8a5..573fc213d8 100644 --- a/src/WINNT/afsd/smb.c +++ b/src/WINNT/afsd/smb.c @@ -6011,7 +6011,7 @@ long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) userp = smb_GetUserFromVCP(vcp, inp); lock_ObtainMutex(&fidp->mx); - if (fidp->flags & SMB_FID_OPENWRITE) { + if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) { cm_scache_t * scp = fidp->scp; cm_HoldSCache(scp); lock_ReleaseMutex(&fidp->mx); @@ -6146,9 +6146,11 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp, CompensateForSmbClientLastWriteTimeBugs(&dosTime); smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime); } - lock_ReleaseMutex(&fidp->mx); - code = cm_FSync(scp, userp, &req); - lock_ObtainMutex(&fidp->mx); + if (smb_AsyncStore != 2) { + lock_ReleaseMutex(&fidp->mx); + code = cm_FSync(scp, userp, &req); + lock_ObtainMutex(&fidp->mx); + } } else code = 0; @@ -6557,7 +6559,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char * based upon cm_chunkSize but we desire cm_chunkSize to be large * so that we can read larger amounts of data at a time. */ - if (smb_AsyncStore && + if (smb_AsyncStore == 1 && (thyper.LowPart & ~(cm_data.buf_blockSize-1)) != (offset.LowPart & ~(cm_data.buf_blockSize-1))) { /* they're different */ @@ -6636,7 +6638,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char ConvertLongToLargeInteger(count)), minLength))) { if (count < cm_data.buf_blockSize - && bufferp->dataVersion == -1) + && bufferp->dataVersion == CM_BUF_VERSION_BAD) memset(bufferp->datap, 0, cm_data.buf_blockSize); bufferp->dataVersion = scp->dataVersion; @@ -6715,7 +6717,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char lock_ReleaseMutex(&fidp->mx); if (code == 0) { - if (smb_AsyncStore) { + if (smb_AsyncStore > 0) { if (doWriteBack) { long code2;