mirror of
https://git.openafs.org/openafs.git
synced 2025-02-01 14:07:39 +00:00
Windows: Negative Caching for Volume Lookups
If a volume lookup returns VL_NOENT or VL_BADNAME, cache the negative response for five minutes. This prevents volume lookup storms caused by the same volume lookup being performed repeated during a short time period. This can happen if mount points to volumes that do not exist are present in a directory that is being evaluated by Windows Explorer or Common Control File Dialogs. This functionality is implemented by storing the most recent update time for the volume group as part of the cm_volume_t. A non-existing volume group is identified with a new CM_VOLUMEFLAG_NOEXIST flag. The presence of the lastUpdateTime value also permits volume location information to expire at lastUpdateTime + lifetime instead of expiring all volume information simultaneously each lifetime period. LICENSE MIT Reviewed-on: http://gerrit.openafs.org/2771 Reviewed-by: Derrick Brashear <shadow@dementia.org> Tested-by: BuildBot <buildbot@rampaginggeek.com> Reviewed-by: Jeffrey Altman <jaltman@openafs.org> Tested-by: Jeffrey Altman <jaltman@openafs.org> (cherry picked from commit a00da7d2c9a66f1e5984ec2b3bd3efe10793e1c9) Change-Id: I3603e746a6df1834612647931cc09228428842db Reviewed-on: http://gerrit.openafs.org/3132 Tested-by: Derrick Brashear <shadow@dementia.org>
This commit is contained in:
parent
22cae170a5
commit
47d79237b6
@ -507,11 +507,15 @@ void cm_Daemon(long parm)
|
|||||||
cm_VolStatus_Network_Addr_Change();
|
cm_VolStatus_Network_Addr_Change();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (now > lastVolCheck + cm_daemonCheckVolInterval &&
|
/*
|
||||||
|
* Once every five minutes inspect the volume list and enforce
|
||||||
|
* the volume location expiration time.
|
||||||
|
*/
|
||||||
|
if (now > lastVolCheck + 300 &&
|
||||||
daemon_ShutdownFlag == 0 &&
|
daemon_ShutdownFlag == 0 &&
|
||||||
powerStateSuspended == 0) {
|
powerStateSuspended == 0) {
|
||||||
lastVolCheck = now;
|
lastVolCheck = now;
|
||||||
cm_RefreshVolumes();
|
cm_RefreshVolumes(cm_daemonCheckVolInterval);
|
||||||
if (daemon_ShutdownFlag == 1)
|
if (daemon_ShutdownFlag == 1)
|
||||||
break;
|
break;
|
||||||
now = osi_Time();
|
now = osi_Time();
|
||||||
|
@ -1285,7 +1285,7 @@ cm_IoctlCheckServers(struct cm_ioctl *ioctlp, struct cm_user *userp)
|
|||||||
afs_int32
|
afs_int32
|
||||||
cm_IoctlCheckVolumes(cm_ioctl_t *ioctlp, cm_user_t *userp)
|
cm_IoctlCheckVolumes(cm_ioctl_t *ioctlp, cm_user_t *userp)
|
||||||
{
|
{
|
||||||
cm_RefreshVolumes();
|
cm_RefreshVolumes(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -874,7 +874,7 @@ cm_InitMappedMemory(DWORD virtualCache, char * cachePath, DWORD stats, DWORD max
|
|||||||
cm_data.buf_blockSize = blockSize;
|
cm_data.buf_blockSize = blockSize;
|
||||||
cm_data.buf_hashSize = osi_PrimeLessThan((afs_uint32)(cacheBlocks/7 + 1));
|
cm_data.buf_hashSize = osi_PrimeLessThan((afs_uint32)(cacheBlocks/7 + 1));
|
||||||
|
|
||||||
cm_data.mountRootGen = time(NULL);
|
cm_data.mountRootGen = 0;
|
||||||
|
|
||||||
baseAddress += ComputeSizeOfConfigData();
|
baseAddress += ComputeSizeOfConfigData();
|
||||||
cm_data.volumeBaseAddress = (cm_volume_t *) baseAddress;
|
cm_data.volumeBaseAddress = (cm_volume_t *) baseAddress;
|
||||||
|
@ -145,7 +145,7 @@ typedef struct cm_scache {
|
|||||||
* the link contents here.
|
* the link contents here.
|
||||||
*/
|
*/
|
||||||
cm_fid_t mountRootFid; /* mounted on root */
|
cm_fid_t mountRootFid; /* mounted on root */
|
||||||
time_t mountRootGen; /* time to update mountRootFidp? */
|
time_t mountRootGen; /* time to update mountRootFid? */
|
||||||
cm_fid_t dotdotFid; /* parent of volume root */
|
cm_fid_t dotdotFid; /* parent of volume root */
|
||||||
|
|
||||||
/* callback info */
|
/* callback info */
|
||||||
|
@ -190,6 +190,17 @@ long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *
|
|||||||
|
|
||||||
lock_AssertWrite(&volp->rw);
|
lock_AssertWrite(&volp->rw);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the last volume update was in the last five
|
||||||
|
* minutes and it did not exist, then avoid the RPC
|
||||||
|
* and return No Such Volume immediately.
|
||||||
|
*/
|
||||||
|
if ((volp->flags & CM_VOLUMEFLAG_NOEXIST) &&
|
||||||
|
volp->lastUpdateTime + 600 < time(0))
|
||||||
|
{
|
||||||
|
return CM_ERROR_NOSUCHVOLUME;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef AFS_FREELANCE_CLIENT
|
#ifdef AFS_FREELANCE_CLIENT
|
||||||
if ( cellp->cellID == AFS_FAKE_ROOT_CELL_ID && volp->vol[RWVOL].ID == AFS_FAKE_ROOT_VOL_ID )
|
if ( cellp->cellID == AFS_FAKE_ROOT_CELL_ID && volp->vol[RWVOL].ID == AFS_FAKE_ROOT_VOL_ID )
|
||||||
{
|
{
|
||||||
@ -614,28 +625,13 @@ long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *
|
|||||||
cm_RandomizeServer(&volp->vol[ROVOL].serversp);
|
cm_RandomizeServer(&volp->vol[ROVOL].serversp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
rwNewstate = rwServers_alldown ? vl_alldown : vl_online;
|
rwNewstate = rwServers_alldown ? vl_alldown : vl_online;
|
||||||
roNewstate = roServers_alldown ? vl_alldown : vl_online;
|
roNewstate = roServers_alldown ? vl_alldown : vl_online;
|
||||||
bkNewstate = bkServers_alldown ? vl_alldown : vl_online;
|
bkNewstate = bkServers_alldown ? vl_alldown : vl_online;
|
||||||
|
|
||||||
|
volp->flags &= ~CM_VOLUMEFLAG_NOEXIST;
|
||||||
} else if (code == CM_ERROR_NOSUCHVOLUME || code == VL_NOENT || code == VL_BADNAME) {
|
} else if (code == CM_ERROR_NOSUCHVOLUME || code == VL_NOENT || code == VL_BADNAME) {
|
||||||
/* this volume does not exist - we should discard it */
|
volp->flags |= CM_VOLUMEFLAG_NOEXIST;
|
||||||
if (volp->flags & CM_VOLUMEFLAG_IN_HASH)
|
|
||||||
cm_RemoveVolumeFromNameHashTable(volp);
|
|
||||||
for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
|
|
||||||
if (volp->vol[volType].flags & CM_VOLUMEFLAG_IN_HASH)
|
|
||||||
cm_RemoveVolumeFromIDHashTable(volp, volType);
|
|
||||||
if (volp->vol[volType].ID) {
|
|
||||||
cm_VolumeStatusNotification(volp, volp->vol[volType].ID, volp->vol[volType].state, vl_alldown);
|
|
||||||
volp->vol[volType].ID = 0;
|
|
||||||
}
|
|
||||||
cm_SetFid(&volp->vol[volType].dotdotFid, 0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Move to the end so it will be recycled first */
|
|
||||||
cm_MoveVolumeToLRULast(volp);
|
|
||||||
|
|
||||||
volp->namep[0] ='\0';
|
|
||||||
} else {
|
} else {
|
||||||
rwNewstate = roNewstate = bkNewstate = vl_alldown;
|
rwNewstate = roNewstate = bkNewstate = vl_alldown;
|
||||||
}
|
}
|
||||||
@ -656,6 +652,8 @@ long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *
|
|||||||
volp->vol[BACKVOL].state = bkNewstate;
|
volp->vol[BACKVOL].state = bkNewstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
volp->lastUpdateTime = time(0);
|
||||||
|
|
||||||
if (code == 0)
|
if (code == 0)
|
||||||
volp->flags &= ~CM_VOLUMEFLAG_RESET;
|
volp->flags &= ~CM_VOLUMEFLAG_RESET;
|
||||||
|
|
||||||
@ -1144,48 +1142,40 @@ long cm_GetROVolumeID(cm_volume_t *volp)
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cm_RefreshVolumes(void)
|
void cm_RefreshVolumes(int lifetime)
|
||||||
{
|
{
|
||||||
cm_volume_t *volp;
|
cm_volume_t *volp;
|
||||||
cm_scache_t *scp;
|
cm_scache_t *scp;
|
||||||
afs_int32 refCount;
|
afs_int32 refCount;
|
||||||
|
time_t now;
|
||||||
|
|
||||||
cm_data.mountRootGen = time(NULL);
|
now = time(NULL);
|
||||||
|
|
||||||
/* force a re-loading of volume data from the vldb */
|
/* force mount point target updates */
|
||||||
|
if (cm_data.mountRootGen + lifetime <= now)
|
||||||
|
cm_data.mountRootGen = now;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* force a re-loading of volume data from the vldb
|
||||||
|
* if the lifetime for the cached data has expired
|
||||||
|
*/
|
||||||
lock_ObtainRead(&cm_volumeLock);
|
lock_ObtainRead(&cm_volumeLock);
|
||||||
for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
|
for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
|
||||||
InterlockedIncrement(&volp->refCount);
|
InterlockedIncrement(&volp->refCount);
|
||||||
lock_ReleaseRead(&cm_volumeLock);
|
lock_ReleaseRead(&cm_volumeLock);
|
||||||
|
|
||||||
|
if (!(volp->flags & CM_VOLUMEFLAG_RESET)) {
|
||||||
lock_ObtainWrite(&volp->rw);
|
lock_ObtainWrite(&volp->rw);
|
||||||
|
if (volp->lastUpdateTime + lifetime <= now)
|
||||||
volp->flags |= CM_VOLUMEFLAG_RESET;
|
volp->flags |= CM_VOLUMEFLAG_RESET;
|
||||||
lock_ReleaseWrite(&volp->rw);
|
lock_ReleaseWrite(&volp->rw);
|
||||||
|
}
|
||||||
|
|
||||||
lock_ObtainRead(&cm_volumeLock);
|
lock_ObtainRead(&cm_volumeLock);
|
||||||
refCount = InterlockedDecrement(&volp->refCount);
|
refCount = InterlockedDecrement(&volp->refCount);
|
||||||
osi_assertx(refCount >= 0, "cm_volume_t refCount underflow");
|
osi_assertx(refCount >= 0, "cm_volume_t refCount underflow");
|
||||||
}
|
}
|
||||||
lock_ReleaseRead(&cm_volumeLock);
|
lock_ReleaseRead(&cm_volumeLock);
|
||||||
|
|
||||||
/* force mount points to be re-evaluated so that
|
|
||||||
* if the volume location has changed we will pick
|
|
||||||
* that up
|
|
||||||
*/
|
|
||||||
for ( scp = cm_data.scacheLRUFirstp;
|
|
||||||
scp;
|
|
||||||
scp = (cm_scache_t *) osi_QNext(&scp->q)) {
|
|
||||||
if ( scp->fileType == CM_SCACHETYPE_MOUNTPOINT
|
|
||||||
#ifdef AFS_FREELANCE_CLIENT
|
|
||||||
&& !(scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID)
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
lock_ObtainWrite(&scp->rw);
|
|
||||||
scp->mountPointStringp[0] = '\0';
|
|
||||||
lock_ReleaseWrite(&scp->rw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -45,6 +45,7 @@ typedef struct cm_volume {
|
|||||||
struct cm_server *cbServerpRO; /* server granting RO callback; by cm_scacheLock */
|
struct cm_server *cbServerpRO; /* server granting RO callback; by cm_scacheLock */
|
||||||
time_t cbExpiresRO; /* latest RO expiration time; by cm_scacheLock */
|
time_t cbExpiresRO; /* latest RO expiration time; by cm_scacheLock */
|
||||||
time_t creationDateRO; /* latest volume creation date; 0 if unknown; by cm_scacheLock */
|
time_t creationDateRO; /* latest volume creation date; 0 if unknown; by cm_scacheLock */
|
||||||
|
time_t lastUpdateTime; /* most recent volume location update cm_volumeLock */
|
||||||
} cm_volume_t;
|
} cm_volume_t;
|
||||||
|
|
||||||
#define CM_VOLUMEFLAG_RESET 1 /* reload this info on next use */
|
#define CM_VOLUMEFLAG_RESET 1 /* reload this info on next use */
|
||||||
@ -52,6 +53,7 @@ typedef struct cm_volume {
|
|||||||
#define CM_VOLUMEFLAG_IN_LRU_QUEUE 4
|
#define CM_VOLUMEFLAG_IN_LRU_QUEUE 4
|
||||||
#define CM_VOLUMEFLAG_UPDATING_VL 8
|
#define CM_VOLUMEFLAG_UPDATING_VL 8
|
||||||
#define CM_VOLUMEFLAG_DFS_VOLUME 16
|
#define CM_VOLUMEFLAG_DFS_VOLUME 16
|
||||||
|
#define CM_VOLUMEFLAG_NOEXIST 32
|
||||||
|
|
||||||
typedef struct cm_volumeRef {
|
typedef struct cm_volumeRef {
|
||||||
struct cm_volumeRef * next;
|
struct cm_volumeRef * next;
|
||||||
@ -100,7 +102,7 @@ extern cm_serverRef_t **cm_GetVolServers(cm_volume_t *volp, afs_uint32 volume,
|
|||||||
|
|
||||||
extern void cm_ChangeRankVolume(cm_server_t *tsp);
|
extern void cm_ChangeRankVolume(cm_server_t *tsp);
|
||||||
|
|
||||||
extern void cm_RefreshVolumes(void);
|
extern void cm_RefreshVolumes(int lifetime);
|
||||||
|
|
||||||
extern long cm_ValidateVolume(void);
|
extern long cm_ValidateVolume(void);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user