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.
====================
This delta was composed from multiple commits as part of the CVS->Git migration.
The checkin message with each commit was inconsistent.
The following are the additional commit messages.
====================
fix typo caused by pullup failure
(cherry picked from commit
c1e79275079cfa68d73cc3a008c3fb3b201f1068)
if (aclp->userp == userp) {
if (aclp->tgtLifetime && aclp->tgtLifetime <= osi_Time()) {
/* 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);
/* move to the tail of the LRU queue */
cm_data.aclLRUEndp = (cm_aclent_t *) osi_QPrev(&aclp->q);
/* 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_queue_t **) &cm_data.aclLRUEndp,
&aclp->q);
aclp = cm_data.aclLRUEndp;
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) {
ascp = aclp->backp;
{
if (scp == cm_data.scacheLRULastp)
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);
if (!cm_data.scacheLRULastp)
cm_data.scacheLRULastp = scp;
if (scp->fileLocksT == q)
scp->fileLocksT = osi_QPrev(q);
- osi_QRemove(&scp->fileLocksH,q);
+ osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, q);
if(IS_LOCK_ACCEPTED(fileLock)) {
if(fileLock->lockType == LockRead)
lock_ObtainWrite(&cm_scacheLock);
if (scp->fileLocksT == 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
lock_ObtainWrite(&cm_scacheLock);
if (scp->fileLocksT == &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);
} else if (code == 0 && IS_LOCK_WAITLOCK(oldFileLock)) {
scp->serverLock = newLock;
osi_LogPrint @58
osi_LogSaveString @59
osi_InitPanic @60
- osi_InitTraceOption @61
+ osi_InitTraceOption @61
osi_LogEvent0 @62
osi_LogEvent @63
- osi_HexifyString @64
+ osi_HexifyString @64
+ osi_QRemoveHT @65
void osi_QRemove(osi_queue_t **headpp, osi_queue_t *eltp)
{
- osi_queue_t *np; /* next dude */
-
- np = eltp->nextp; /* useful for both paths */
+ osi_queue_t *np = eltp->nextp; /* next dude */
+ osi_queue_t *pp = eltp->prevp; /* prev dude */
+
+ 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) {
- /* we're the first element in the list */
- *headpp = np;
- if (np) np->prevp = NULL;
- }
- else {
- eltp->prevp->nextp = np;
- if (np) np->prevp = eltp->prevp;
- }
+void osi_QRemoveHT(osi_queue_t **headpp, osi_queue_t **tailpp, osi_queue_t *eltp)
+{
+ osi_queue_t *np = eltp->nextp; /* next dude */
+ osi_queue_t *pp = eltp->prevp; /* prev dude */
+
+ if (eltp == *headpp && eltp == *tailpp)
+ {
+ *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)
*/
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 */
extern void osi_InitQueue(void);
* should be ignored.
*/
static osi_sleepInfo_t *osi_sleepers[OSI_SLEEPHASHSIZE];
+static osi_sleepInfo_t *osi_sleepersEnd[OSI_SLEEPHASHSIZE];
/* allocate space for lock operations */
osi_lockOps_t *osi_lockOps[OSI_NLOCKTYPES];
if (ap->states & OSI_SLEEPINFO_INHASH) {
ap->states &= ~OSI_SLEEPINFO_INHASH;
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) {
for(i=0;i<OSI_SLEEPHASHSIZE; i++) {
InitializeCriticalSection(&osi_critSec[i]);
osi_sleepers[i] = (osi_sleepInfo_t *) NULL;
+ osi_sleepersEnd[i] = (osi_sleepInfo_t *) NULL;
}
/* free list CS */
sp = osi_AllocSleepInfo();
TlsSetValue(osi_SleepSlot, sp);
}
- else
+ else {
sp->states = 0;
+ }
sp->refCount = 0;
sp->waitFor = waitFor;
sp->value = (long) patchp;
- osi_QAdd((osi_queue_t **) &turnp->firstp, &sp->q);
- if (!turnp->lastp) turnp->lastp = sp;
+ osi_QAddT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &sp->q);
+ if (!turnp->lastp)
+ turnp->lastp = sp;
LeaveCriticalSection(releasep);
/* now wait for the signal */
{
osi_sleepInfo_t *sp;
- if (!turnp->lastp) return;
+ if (!turnp->lastp)
+ return;
sp = turnp->lastp;
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;
ReleaseSemaphore(sp->sema, 1, (long *) 0);
}
while(sp = turnp->lastp) {
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;
ReleaseSemaphore(sp->sema, 1, (long *) 0);
} /* while someone's still asleep */
* the crit sec.
*/
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 */
if (tsp->waitFor & OSI_SLEEPINFO_W4WRITE) {
sp = osi_AllocSleepInfo();
TlsSetValue(osi_SleepSlot, sp);
}
- else
+ else {
sp->states = 0;
+ }
sp->refCount = 0;
sp->value = sleepValue;
idx = osi_SLEEPHASH(sleepValue);
csp = &osi_critSec[idx];
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;
LeaveCriticalSection(releasep);
LeaveCriticalSection(csp);