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:
parent
a6e9ddddea
commit
faaa2dc21f
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user