From 94ceae1220538dec8ba3400b1368b599fe28197d Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Mon, 12 Oct 2009 21:57:52 -0400 Subject: [PATCH] Windows: refactor afs status cloning and clone when fs fetchdata bug detected When the file server fetchdata invalid length bug is detected the cache manager must fake the AFS Status info for the file as well as the AFSVolSync info. Otherwise, the merge status is incorrect. LICENSE MIT Reviewed-on: http://gerrit.openafs.org/651 Tested-by: Jeffrey Altman Reviewed-by: Derrick Brashear Reviewed-by: Jeffrey Altman --- src/WINNT/afsd/cm_dcache.c | 115 ++++++++++++++++++++++++++++----------------- 1 file changed, 71 insertions(+), 44 deletions(-) diff --git a/src/WINNT/afsd/cm_dcache.c b/src/WINNT/afsd/cm_dcache.c index 94010d9..d15ecde 100644 --- a/src/WINNT/afsd/cm_dcache.c +++ b/src/WINNT/afsd/cm_dcache.c @@ -1383,6 +1383,60 @@ void cm_ReleaseBIOD(cm_bulkIO_t *biop, int isStore, long code, int scp_locked) biop->bufListEndp = NULL; } +static int +cm_CloneStatus(cm_scache_t *scp, cm_user_t *userp, int scp_locked, + AFSFetchStatus *afsStatusp, AFSVolSync *volSyncp) +{ + // setup the status based upon the scp data + afsStatusp->InterfaceVersion = 0x1; + switch (scp->fileType) { + case CM_SCACHETYPE_FILE: + afsStatusp->FileType = File; + break; + case CM_SCACHETYPE_DIRECTORY: + afsStatusp->FileType = Directory; + break; + case CM_SCACHETYPE_MOUNTPOINT: + afsStatusp->FileType = SymbolicLink; + break; + case CM_SCACHETYPE_SYMLINK: + case CM_SCACHETYPE_DFSLINK: + afsStatusp->FileType = SymbolicLink; + break; + default: + afsStatusp->FileType = -1; /* an invalid value */ + } + afsStatusp->LinkCount = scp->linkCount; + afsStatusp->Length = scp->length.LowPart; + afsStatusp->DataVersion = (afs_uint32)(scp->dataVersion & MAX_AFS_UINT32); + afsStatusp->Author = 0x1; + afsStatusp->Owner = scp->owner; + if (!scp_locked) { + lock_ObtainWrite(&scp->rw); + scp_locked = 1; + } + if (cm_FindACLCache(scp, userp, &afsStatusp->CallerAccess)) + afsStatusp->CallerAccess = scp->anyAccess; + afsStatusp->AnonymousAccess = scp->anyAccess; + afsStatusp->UnixModeBits = scp->unixModeBits; + afsStatusp->ParentVnode = scp->parentVnode; + afsStatusp->ParentUnique = scp->parentUnique; + afsStatusp->ResidencyMask = 0; + afsStatusp->ClientModTime = scp->clientModTime; + afsStatusp->ServerModTime = scp->serverModTime; + afsStatusp->Group = scp->group; + afsStatusp->SyncCounter = 0; + afsStatusp->dataVersionHigh = (afs_uint32)(scp->dataVersion >> 32); + afsStatusp->lockCount = 0; + afsStatusp->Length_hi = scp->length.HighPart; + afsStatusp->errorCode = 0; + + memset(volSyncp, 0, sizeof(AFSVolSync)); + volSyncp->spare1 = scp->lastUpdateRO; + + return scp_locked; +} + /* Fetch a buffer. Called with scp locked. * The scp is locked on return. */ @@ -1515,7 +1569,8 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *userp afsStatus.lockCount = 0; afsStatus.Length_hi = 0; afsStatus.errorCode = 0; - + memset(&volSync, 0, sizeof(volSync)); + // once we're done setting up the status info, // we just fill the buffer pages with fakedata // from cm_FakeRootDir. Extra pages are set to @@ -1564,47 +1619,8 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *userp scp, biod.offset.HighPart, biod.offset.LowPart, scp->length.HighPart, scp->length.LowPart); - // setup the status based upon the scp data - afsStatus.InterfaceVersion = 0x1; - switch (scp->fileType) { - case CM_SCACHETYPE_FILE: - afsStatus.FileType = File; - break; - case CM_SCACHETYPE_DIRECTORY: - afsStatus.FileType = Directory; - break; - case CM_SCACHETYPE_MOUNTPOINT: - afsStatus.FileType = SymbolicLink; - break; - case CM_SCACHETYPE_SYMLINK: - case CM_SCACHETYPE_DFSLINK: - afsStatus.FileType = SymbolicLink; - break; - default: - afsStatus.FileType = -1; /* an invalid value */ - } - afsStatus.LinkCount = scp->linkCount; - afsStatus.Length = scp->length.LowPart; - afsStatus.DataVersion = (afs_uint32)(scp->dataVersion & MAX_AFS_UINT32); - afsStatus.Author = 0x1; - afsStatus.Owner = scp->owner; - lock_ObtainWrite(&scp->rw); - scp_locked = 1; - if (cm_FindACLCache(scp, userp, &afsStatus.CallerAccess)) - afsStatus.CallerAccess = scp->anyAccess; - afsStatus.AnonymousAccess = scp->anyAccess; - afsStatus.UnixModeBits = scp->unixModeBits; - afsStatus.ParentVnode = scp->parentVnode; - afsStatus.ParentUnique = scp->parentUnique; - afsStatus.ResidencyMask = 0; - afsStatus.ClientModTime = scp->clientModTime; - afsStatus.ServerModTime = scp->serverModTime; - afsStatus.Group = scp->group; - afsStatus.SyncCounter = 0; - afsStatus.dataVersionHigh = (afs_uint32)(scp->dataVersion >> 32); - afsStatus.lockCount = 0; - afsStatus.Length_hi = scp->length.HighPart; - afsStatus.errorCode = 0; + /* Clone the current status info */ + scp_locked = cm_CloneStatus(scp, userp, scp_locked, &afsStatus, &volSync); /* status info complete, fill pages with zeros */ for (qdp = biod.bufListEndp; @@ -1619,6 +1635,11 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *userp goto fetchingcompleted; } + if (scp_locked) { + lock_ReleaseWrite(&scp->rw); + scp_locked = 0; + } + /* now make the call */ do { code = cm_ConnFromFID(&scp->fid, userp, reqp, &connp); @@ -1851,10 +1872,16 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *userp osi_Log0(afsd_logp, "CALL EndCall returns RXKADUNKNOWNKEY"); /* If we are avoiding a file server bug, ignore the error state */ - if (fs_fetchdata_offset_bug && first_read && length_found == 0 && code == -451) + if (fs_fetchdata_offset_bug && first_read && length_found == 0 && code == -451) { + /* Clone the current status info and clear the error state */ + scp_locked = cm_CloneStatus(scp, userp, scp_locked, &afsStatus, &volSync); + if (scp_locked) { + lock_ReleaseWrite(&scp->rw); + scp_locked = 0; + } code = 0; /* Prefer the error value from FetchData over rx_EndCall */ - else if (code == 0 && code1 != 0) + } else if (code == 0 && code1 != 0) code = code1; osi_Log0(afsd_logp, "CALL FetchData DONE"); -- 1.9.4