Delay the recursive decrement of pr_uref when jails are made invisible

but not removed; decrement it instead when the child jail actually
goes away. This avoids letting the counter go below zero in the case
where dying (pr_uref==0) jails are "resurrected", and an associated
KASSERT panic.

Submitted by:	Steven Hartland
Approved by:	re (bz)
MFC after:	1 week
This commit is contained in:
jamie 2011-08-26 16:03:34 +00:00
parent a6e9ddddea
commit faaa2dc21f

View File

@ -2470,32 +2470,11 @@ prison_deref(struct prison *pr, int flags)
if (!(flags & PD_LOCKED))
mtx_lock(&pr->pr_mtx);
/* Decrement the user references in a separate loop. */
if (flags & PD_DEUREF) {
for (tpr = pr;; tpr = tpr->pr_parent) {
if (tpr != pr)
mtx_lock(&tpr->pr_mtx);
if (--tpr->pr_uref > 0)
break;
KASSERT(tpr != &prison0, ("prison0 pr_uref=0"));
mtx_unlock(&tpr->pr_mtx);
}
/* Done if there were only user references to remove. */
if (!(flags & PD_DEREF)) {
mtx_unlock(&tpr->pr_mtx);
if (flags & PD_LIST_SLOCKED)
sx_sunlock(&allprison_lock);
else if (flags & PD_LIST_XLOCKED)
sx_xunlock(&allprison_lock);
return;
}
if (tpr != pr) {
mtx_unlock(&tpr->pr_mtx);
mtx_lock(&pr->pr_mtx);
}
}
for (;;) {
if (flags & PD_DEUREF) {
pr->pr_uref--;
KASSERT(prison0.pr_uref != 0, ("prison0 pr_uref=0"));
}
if (flags & PD_DEREF)
pr->pr_ref--;
/* If the prison still has references, nothing else to do. */
@ -2551,7 +2530,7 @@ prison_deref(struct prison *pr, int flags)
/* Removing a prison frees a reference on its parent. */
pr = ppr;
mtx_lock(&pr->pr_mtx);
flags = PD_DEREF;
flags = PD_DEREF | PD_DEUREF;
}
}