mirror of
https://git.openafs.org/openafs.git
synced 2025-01-31 21:47:45 +00:00
DEVEL15-windows-head-tail-queue-removal-20060525
while investigating the cause of the delayed write errors it was observed that all of the sleep queues are LIFO. This has the side effect of encouraging starvation. Changing the queues to FIFOs revealed a serious problem affecting the use of all queues which use both head and tail pointers. The removal function osi_QRemove does not take a tail pointer and therefore the pointer is always left hanging. If the number of elements ever drops to zero the queue becomes corrupted. Added osi_QRemoveHT to be used whenever head and tail pointers are used. Updated all callers in afsd. (cherry picked from commit c1e79275079cfa68d73cc3a008c3fb3b201f1068)
This commit is contained in:
parent
4b6e5b7e69
commit
3b3f0704b1
@ -82,7 +82,7 @@ long cm_FindACLCache(cm_scache_t *scp, cm_user_t *userp, afs_uint32 *rightsp)
|
|||||||
if (aclp->userp == userp) {
|
if (aclp->userp == userp) {
|
||||||
if (aclp->tgtLifetime && aclp->tgtLifetime <= osi_Time()) {
|
if (aclp->tgtLifetime && aclp->tgtLifetime <= osi_Time()) {
|
||||||
/* ticket expired */
|
/* ticket expired */
|
||||||
osi_QRemove((osi_queue_t **) &cm_data.aclLRUp, &aclp->q);
|
osi_QRemoveHT((osi_queue_t **) &cm_data.aclLRUp, (osi_queue_t **) &cm_data.aclLRUEndp, &aclp->q);
|
||||||
CleanupACLEnt(aclp);
|
CleanupACLEnt(aclp);
|
||||||
|
|
||||||
/* move to the tail of the LRU queue */
|
/* move to the tail of the LRU queue */
|
||||||
@ -96,7 +96,7 @@ long cm_FindACLCache(cm_scache_t *scp, cm_user_t *userp, afs_uint32 *rightsp)
|
|||||||
cm_data.aclLRUEndp = (cm_aclent_t *) osi_QPrev(&aclp->q);
|
cm_data.aclLRUEndp = (cm_aclent_t *) osi_QPrev(&aclp->q);
|
||||||
|
|
||||||
/* move to the head of the LRU queue */
|
/* move to the head of the LRU queue */
|
||||||
osi_QRemove((osi_queue_t **) &cm_data.aclLRUp, &aclp->q);
|
osi_QRemoveHT((osi_queue_t **) &cm_data.aclLRUp, (osi_queue_t **) &cm_data.aclLRUEndp, &aclp->q);
|
||||||
osi_QAddH((osi_queue_t **) &cm_data.aclLRUp,
|
osi_QAddH((osi_queue_t **) &cm_data.aclLRUp,
|
||||||
(osi_queue_t **) &cm_data.aclLRUEndp,
|
(osi_queue_t **) &cm_data.aclLRUEndp,
|
||||||
&aclp->q);
|
&aclp->q);
|
||||||
@ -125,7 +125,7 @@ static cm_aclent_t *GetFreeACLEnt(cm_scache_t * scp)
|
|||||||
|
|
||||||
aclp = cm_data.aclLRUEndp;
|
aclp = cm_data.aclLRUEndp;
|
||||||
cm_data.aclLRUEndp = (cm_aclent_t *) osi_QPrev(&aclp->q);
|
cm_data.aclLRUEndp = (cm_aclent_t *) osi_QPrev(&aclp->q);
|
||||||
osi_QRemove((osi_queue_t **) &cm_data.aclLRUp, &aclp->q);
|
osi_QRemoveHT((osi_queue_t **) &cm_data.aclLRUp, (osi_queue_t **) &cm_data.aclLRUEndp, &aclp->q);
|
||||||
|
|
||||||
if (aclp->backp && scp != aclp->backp) {
|
if (aclp->backp && scp != aclp->backp) {
|
||||||
ascp = aclp->backp;
|
ascp = aclp->backp;
|
||||||
|
@ -46,7 +46,7 @@ void cm_AdjustLRU(cm_scache_t *scp)
|
|||||||
{
|
{
|
||||||
if (scp == cm_data.scacheLRULastp)
|
if (scp == cm_data.scacheLRULastp)
|
||||||
cm_data.scacheLRULastp = (cm_scache_t *) osi_QPrev(&scp->q);
|
cm_data.scacheLRULastp = (cm_scache_t *) osi_QPrev(&scp->q);
|
||||||
osi_QRemove((osi_queue_t **) &cm_data.scacheLRUFirstp, &scp->q);
|
osi_QRemoveHT((osi_queue_t **) &cm_data.scacheLRUFirstp, (osi_queue_t **) &cm_data.scacheLRULastp, &scp->q);
|
||||||
osi_QAdd((osi_queue_t **) &cm_data.scacheLRUFirstp, &scp->q);
|
osi_QAdd((osi_queue_t **) &cm_data.scacheLRUFirstp, &scp->q);
|
||||||
if (!cm_data.scacheLRULastp)
|
if (!cm_data.scacheLRULastp)
|
||||||
cm_data.scacheLRULastp = scp;
|
cm_data.scacheLRULastp = scp;
|
||||||
|
@ -3832,7 +3832,7 @@ long cm_UnlockByKey(cm_scache_t * scp,
|
|||||||
|
|
||||||
if (scp->fileLocksT == q)
|
if (scp->fileLocksT == q)
|
||||||
scp->fileLocksT = osi_QPrev(q);
|
scp->fileLocksT = osi_QPrev(q);
|
||||||
osi_QRemove(&scp->fileLocksH,q);
|
osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, q);
|
||||||
|
|
||||||
if (IS_LOCK_CLIENTONLY(fileLock)) {
|
if (IS_LOCK_CLIENTONLY(fileLock)) {
|
||||||
scp->clientLocks--;
|
scp->clientLocks--;
|
||||||
@ -4020,7 +4020,7 @@ long cm_Unlock(cm_scache_t *scp,
|
|||||||
lock_ObtainWrite(&cm_scacheLock);
|
lock_ObtainWrite(&cm_scacheLock);
|
||||||
if (scp->fileLocksT == q)
|
if (scp->fileLocksT == q)
|
||||||
scp->fileLocksT = osi_QPrev(q);
|
scp->fileLocksT = osi_QPrev(q);
|
||||||
osi_QRemove(&scp->fileLocksH, q);
|
osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, q);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't delete it here; let the daemon delete it, to simplify
|
* Don't delete it here; let the daemon delete it, to simplify
|
||||||
@ -4605,7 +4605,7 @@ long cm_RetryLock(cm_file_lock_t *oldFileLock, int client_is_dead)
|
|||||||
lock_ObtainWrite(&cm_scacheLock);
|
lock_ObtainWrite(&cm_scacheLock);
|
||||||
if (scp->fileLocksT == &oldFileLock->fileq)
|
if (scp->fileLocksT == &oldFileLock->fileq)
|
||||||
scp->fileLocksT = osi_QPrev(&oldFileLock->fileq);
|
scp->fileLocksT = osi_QPrev(&oldFileLock->fileq);
|
||||||
osi_QRemove(&scp->fileLocksH, &oldFileLock->fileq);
|
osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, &oldFileLock->fileq);
|
||||||
lock_ReleaseWrite(&cm_scacheLock);
|
lock_ReleaseWrite(&cm_scacheLock);
|
||||||
} else if (code == 0 && IS_LOCK_WAITLOCK(oldFileLock)) {
|
} else if (code == 0 && IS_LOCK_WAITLOCK(oldFileLock)) {
|
||||||
scp->serverLock = newLock;
|
scp->serverLock = newLock;
|
||||||
|
@ -65,7 +65,8 @@ EXPORTS
|
|||||||
osi_LogPrint @58
|
osi_LogPrint @58
|
||||||
osi_LogSaveString @59
|
osi_LogSaveString @59
|
||||||
osi_InitPanic @60
|
osi_InitPanic @60
|
||||||
osi_InitTraceOption @61
|
osi_InitTraceOption @61
|
||||||
osi_LogEvent0 @62
|
osi_LogEvent0 @62
|
||||||
osi_LogEvent @63
|
osi_LogEvent @63
|
||||||
osi_HexifyString @64
|
osi_HexifyString @64
|
||||||
|
osi_QRemoveHT @65
|
||||||
|
@ -93,19 +93,53 @@ void osi_QAddT(osi_queue_t **headpp, osi_queue_t **tailpp, osi_queue_t *eltp)
|
|||||||
|
|
||||||
void osi_QRemove(osi_queue_t **headpp, osi_queue_t *eltp)
|
void osi_QRemove(osi_queue_t **headpp, osi_queue_t *eltp)
|
||||||
{
|
{
|
||||||
osi_queue_t *np; /* next dude */
|
osi_queue_t *np = eltp->nextp; /* next dude */
|
||||||
|
osi_queue_t *pp = eltp->prevp; /* prev dude */
|
||||||
|
|
||||||
np = eltp->nextp; /* useful for both paths */
|
if (eltp == *headpp) {
|
||||||
|
/* we're the first element in the list */
|
||||||
|
*headpp = np;
|
||||||
|
if (np)
|
||||||
|
np->prevp = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pp->nextp = np;
|
||||||
|
if (np)
|
||||||
|
np->prevp = pp;
|
||||||
|
}
|
||||||
|
eltp->prevp = NULL;
|
||||||
|
eltp->nextp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (eltp == *headpp) {
|
void osi_QRemoveHT(osi_queue_t **headpp, osi_queue_t **tailpp, osi_queue_t *eltp)
|
||||||
/* we're the first element in the list */
|
{
|
||||||
*headpp = np;
|
osi_queue_t *np = eltp->nextp; /* next dude */
|
||||||
if (np) np->prevp = NULL;
|
osi_queue_t *pp = eltp->prevp; /* prev dude */
|
||||||
}
|
|
||||||
else {
|
if (eltp == *headpp && eltp == *tailpp)
|
||||||
eltp->prevp->nextp = np;
|
{
|
||||||
if (np) np->prevp = eltp->prevp;
|
*headpp = *tailpp = NULL;
|
||||||
}
|
}
|
||||||
|
else if (eltp == *headpp) {
|
||||||
|
/* we're the first element in the list */
|
||||||
|
*headpp = np;
|
||||||
|
if (np)
|
||||||
|
np->prevp = NULL;
|
||||||
|
}
|
||||||
|
else if (eltp == *tailpp) {
|
||||||
|
/* we're the last element in the list */
|
||||||
|
*tailpp = pp;
|
||||||
|
if (pp)
|
||||||
|
pp->nextp = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (pp)
|
||||||
|
pp->nextp = np;
|
||||||
|
if (np)
|
||||||
|
np->prevp = pp;
|
||||||
|
}
|
||||||
|
eltp->prevp = NULL;
|
||||||
|
eltp->nextp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void osi_InitQueue(void)
|
void osi_InitQueue(void)
|
||||||
|
@ -59,6 +59,11 @@ extern void osi_QAddH(osi_queue_t **headpp, osi_queue_t **tailpp, osi_queue_t *e
|
|||||||
*/
|
*/
|
||||||
extern void osi_QRemove(osi_queue_t **headpp, osi_queue_t *eltp);
|
extern void osi_QRemove(osi_queue_t **headpp, osi_queue_t *eltp);
|
||||||
|
|
||||||
|
/* remove an element from a queue with both head and tail pointers;
|
||||||
|
* takes address of head and tail lists, and element to remove as parameters.
|
||||||
|
*/
|
||||||
|
extern void osi_QRemoveHT(osi_queue_t **headpp, osi_queue_t **tailpp, osi_queue_t *eltp);
|
||||||
|
|
||||||
/* initialize the queue package */
|
/* initialize the queue package */
|
||||||
extern void osi_InitQueue(void);
|
extern void osi_InitQueue(void);
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ static CRITICAL_SECTION osi_critSec[OSI_SLEEPHASHSIZE];
|
|||||||
* should be ignored.
|
* should be ignored.
|
||||||
*/
|
*/
|
||||||
static osi_sleepInfo_t *osi_sleepers[OSI_SLEEPHASHSIZE];
|
static osi_sleepInfo_t *osi_sleepers[OSI_SLEEPHASHSIZE];
|
||||||
|
static osi_sleepInfo_t *osi_sleepersEnd[OSI_SLEEPHASHSIZE];
|
||||||
|
|
||||||
/* allocate space for lock operations */
|
/* allocate space for lock operations */
|
||||||
osi_lockOps_t *osi_lockOps[OSI_NLOCKTYPES];
|
osi_lockOps_t *osi_lockOps[OSI_NLOCKTYPES];
|
||||||
@ -109,7 +110,7 @@ void osi_FreeSleepInfo(osi_sleepInfo_t *ap)
|
|||||||
if (ap->states & OSI_SLEEPINFO_INHASH) {
|
if (ap->states & OSI_SLEEPINFO_INHASH) {
|
||||||
ap->states &= ~OSI_SLEEPINFO_INHASH;
|
ap->states &= ~OSI_SLEEPINFO_INHASH;
|
||||||
idx = osi_SLEEPHASH(ap->value);
|
idx = osi_SLEEPHASH(ap->value);
|
||||||
osi_QRemove((osi_queue_t **) &osi_sleepers[idx], &ap->q);
|
osi_QRemoveHT((osi_queue_t **) &osi_sleepers[idx], (osi_queue_t **) &osi_sleepersEnd[idx], &ap->q);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ap->states & OSI_SLEEPINFO_DELETED) {
|
if (ap->states & OSI_SLEEPINFO_DELETED) {
|
||||||
@ -226,6 +227,7 @@ void osi_Init(void)
|
|||||||
for(i=0;i<OSI_SLEEPHASHSIZE; i++) {
|
for(i=0;i<OSI_SLEEPHASHSIZE; i++) {
|
||||||
InitializeCriticalSection(&osi_critSec[i]);
|
InitializeCriticalSection(&osi_critSec[i]);
|
||||||
osi_sleepers[i] = (osi_sleepInfo_t *) NULL;
|
osi_sleepers[i] = (osi_sleepInfo_t *) NULL;
|
||||||
|
osi_sleepersEnd[i] = (osi_sleepInfo_t *) NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* free list CS */
|
/* free list CS */
|
||||||
@ -257,22 +259,24 @@ void osi_Init(void)
|
|||||||
|
|
||||||
void osi_TWait(osi_turnstile_t *turnp, int waitFor, void *patchp, CRITICAL_SECTION *releasep)
|
void osi_TWait(osi_turnstile_t *turnp, int waitFor, void *patchp, CRITICAL_SECTION *releasep)
|
||||||
{
|
{
|
||||||
osi_sleepInfo_t *sp;
|
osi_sleepInfo_t *sp;
|
||||||
unsigned int code;
|
unsigned int code;
|
||||||
|
|
||||||
sp = TlsGetValue(osi_SleepSlot);
|
sp = TlsGetValue(osi_SleepSlot);
|
||||||
if (sp == NULL) {
|
if (sp == NULL) {
|
||||||
sp = osi_AllocSleepInfo();
|
sp = osi_AllocSleepInfo();
|
||||||
TlsSetValue(osi_SleepSlot, sp);
|
TlsSetValue(osi_SleepSlot, sp);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
sp->states = 0;
|
sp->states = 0;
|
||||||
sp->refCount = 0;
|
}
|
||||||
sp->waitFor = waitFor;
|
sp->refCount = 0;
|
||||||
sp->value = (LONG_PTR) patchp;
|
sp->waitFor = waitFor;
|
||||||
osi_QAdd((osi_queue_t **) &turnp->firstp, &sp->q);
|
sp->value = (LONG_PTR) patchp;
|
||||||
if (!turnp->lastp) turnp->lastp = sp;
|
osi_QAddT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &sp->q);
|
||||||
LeaveCriticalSection(releasep);
|
if (!turnp->lastp)
|
||||||
|
turnp->lastp = sp;
|
||||||
|
LeaveCriticalSection(releasep);
|
||||||
|
|
||||||
/* now wait for the signal */
|
/* now wait for the signal */
|
||||||
while(1) {
|
while(1) {
|
||||||
@ -309,11 +313,12 @@ void osi_TSignal(osi_turnstile_t *turnp)
|
|||||||
{
|
{
|
||||||
osi_sleepInfo_t *sp;
|
osi_sleepInfo_t *sp;
|
||||||
|
|
||||||
if (!turnp->lastp) return;
|
if (!turnp->lastp)
|
||||||
|
return;
|
||||||
|
|
||||||
sp = turnp->lastp;
|
sp = turnp->lastp;
|
||||||
turnp->lastp = (osi_sleepInfo_t *) osi_QPrev(&sp->q);
|
turnp->lastp = (osi_sleepInfo_t *) osi_QPrev(&sp->q);
|
||||||
osi_QRemove((osi_queue_t **) &turnp->firstp, &sp->q);
|
osi_QRemoveHT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &sp->q);
|
||||||
sp->states |= OSI_SLEEPINFO_SIGNALLED;
|
sp->states |= OSI_SLEEPINFO_SIGNALLED;
|
||||||
ReleaseSemaphore(sp->sema, 1, (long *) 0);
|
ReleaseSemaphore(sp->sema, 1, (long *) 0);
|
||||||
}
|
}
|
||||||
@ -325,7 +330,7 @@ void osi_TBroadcast(osi_turnstile_t *turnp)
|
|||||||
|
|
||||||
while(sp = turnp->lastp) {
|
while(sp = turnp->lastp) {
|
||||||
turnp->lastp = (osi_sleepInfo_t *) osi_QPrev(&sp->q);
|
turnp->lastp = (osi_sleepInfo_t *) osi_QPrev(&sp->q);
|
||||||
osi_QRemove((osi_queue_t **) &turnp->firstp, &sp->q);
|
osi_QRemoveHT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &sp->q);
|
||||||
sp->states |= OSI_SLEEPINFO_SIGNALLED;
|
sp->states |= OSI_SLEEPINFO_SIGNALLED;
|
||||||
ReleaseSemaphore(sp->sema, 1, (long *) 0);
|
ReleaseSemaphore(sp->sema, 1, (long *) 0);
|
||||||
} /* while someone's still asleep */
|
} /* while someone's still asleep */
|
||||||
@ -370,7 +375,7 @@ void osi_TSignalForMLs(osi_turnstile_t *turnp, int stillHaveReaders, CRITICAL_SE
|
|||||||
* the crit sec.
|
* the crit sec.
|
||||||
*/
|
*/
|
||||||
turnp->lastp = (osi_sleepInfo_t *) osi_QPrev(&tsp->q);
|
turnp->lastp = (osi_sleepInfo_t *) osi_QPrev(&tsp->q);
|
||||||
osi_QRemove((osi_queue_t **) &turnp->firstp, &tsp->q);
|
osi_QRemoveHT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &tsp->q);
|
||||||
|
|
||||||
/* do the patching required for lock obtaining */
|
/* do the patching required for lock obtaining */
|
||||||
if (tsp->waitFor & OSI_SLEEPINFO_W4WRITE) {
|
if (tsp->waitFor & OSI_SLEEPINFO_W4WRITE) {
|
||||||
@ -425,14 +430,15 @@ void osi_SleepSpin(LONG_PTR sleepValue, CRITICAL_SECTION *releasep)
|
|||||||
sp = osi_AllocSleepInfo();
|
sp = osi_AllocSleepInfo();
|
||||||
TlsSetValue(osi_SleepSlot, sp);
|
TlsSetValue(osi_SleepSlot, sp);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
sp->states = 0;
|
sp->states = 0;
|
||||||
|
}
|
||||||
sp->refCount = 0;
|
sp->refCount = 0;
|
||||||
sp->value = sleepValue;
|
sp->value = sleepValue;
|
||||||
idx = osi_SLEEPHASH(sleepValue);
|
idx = osi_SLEEPHASH(sleepValue);
|
||||||
csp = &osi_critSec[idx];
|
csp = &osi_critSec[idx];
|
||||||
EnterCriticalSection(csp);
|
EnterCriticalSection(csp);
|
||||||
osi_QAdd((osi_queue_t **) &osi_sleepers[idx], &sp->q);
|
osi_QAddT((osi_queue_t **) &osi_sleepers[idx], (osi_queue_t **) &osi_sleepersEnd[idx], &sp->q);
|
||||||
sp->states |= OSI_SLEEPINFO_INHASH;
|
sp->states |= OSI_SLEEPINFO_INHASH;
|
||||||
LeaveCriticalSection(releasep);
|
LeaveCriticalSection(releasep);
|
||||||
LeaveCriticalSection(csp);
|
LeaveCriticalSection(csp);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user