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);
/* 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
*/
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 */
}
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);
bp->dirty_offset = 0;
bp->dirty_length = 0;
bp->error = code;
- bp->dataVersion = -1; /* bad */
+ bp->dataVersion = CM_BUF_VERSION_BAD; /* bad */
bp->dirtyCounter++;
}
/* 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.
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 {
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);
}
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);
#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 */
/* 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;
* 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;
}
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);
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
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;
}
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,
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
* 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;
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);
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;
* 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 */
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;
lock_ReleaseMutex(&fidp->mx);
if (code == 0) {
- if (smb_AsyncStore) {
+ if (smb_AsyncStore > 0) {
if (doWriteBack) {
long code2;