From: Jeffrey Altman Date: Thu, 31 Jul 2008 05:45:44 +0000 (+0000) Subject: windows-volume-recycling-race-condition-20080731 X-Git-Tag: openafs-devel-1_5_61~928 X-Git-Url: https://git.openafs.org/?p=openafs.git;a=commitdiff_plain;h=b61ac7dc6ffb05b03011fef8cfdd5e72886fb705;hp=aa24715f068dad4dfdc2140bf8f793297ba10ac9 windows-volume-recycling-race-condition-20080731 LICENSE MIT When recycling cm_volume_t objects, avoid a race condition that could result in the same cm_volume_t object being recycling simultaneously in two threads. The end result would be a reference count miscount and an undercount assertion being thrown. --- diff --git a/src/WINNT/afsd/cm_volume.c b/src/WINNT/afsd/cm_volume.c index 3e181e5..fbe2b55 100644 --- a/src/WINNT/afsd/cm_volume.c +++ b/src/WINNT/afsd/cm_volume.c @@ -795,6 +795,13 @@ long cm_FindVolumeByName(struct cm_cell *cellp, char *volumeNamep, afs_uint32 volType; /* otherwise, get from VLDB */ + /* + * Change to a write lock so that we have exclusive use of + * the first cm_volume_t with a refCount of 0 so that we + * have time to increment it. + */ + lock_ConvertRToW(&cm_volumeLock); + if ( cm_data.currentVolumes >= cm_data.maxVolumes ) { #ifdef RECYCLE_FROM_ALL_VOLUMES_LIST for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) { @@ -817,7 +824,8 @@ long cm_FindVolumeByName(struct cm_cell *cellp, char *volumeNamep, if (!volp) osi_panic("Exceeded Max Volumes", __FILE__, __LINE__); - lock_ReleaseRead(&cm_volumeLock); + InterlockedIncrement(&volp->refCount); + lock_ReleaseWrite(&cm_volumeLock); lock_ObtainWrite(&volp->rw); lock_ObtainWrite(&cm_volumeLock); @@ -844,14 +852,14 @@ long cm_FindVolumeByName(struct cm_cell *cellp, char *volumeNamep, volp->allNextp = cm_data.allVolumesp; cm_data.allVolumesp = volp; lock_InitializeRWLock(&volp->rw, "cm_volume_t rwlock"); - lock_ReleaseRead(&cm_volumeLock); + lock_ReleaseWrite(&cm_volumeLock); lock_ObtainWrite(&volp->rw); lock_ObtainWrite(&cm_volumeLock); + volp->refCount = 1; /* starts off held */ } volp->cellp = cellp; strncpy(volp->namep, name, VL_MAXNAMELEN); volp->namep[VL_MAXNAMELEN-1] = '\0'; - volp->refCount = 1; /* starts off held */ volp->flags = CM_VOLUMEFLAG_RESET; for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {