summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorjamie <jamie@FreeBSD.org>2011-08-26 16:03:34 +0000
committerjamie <jamie@FreeBSD.org>2011-08-26 16:03:34 +0000
commitfaaa2dc21f1a608ad5900b982c54b74851ba71b9 (patch)
tree2a14165a8a808b12c14438a87d436bc641f9825d /sys/kern
parenta6e9ddddeabe3d609303aa5b60184265cdbd1aae (diff)
downloadFreeBSD-src-faaa2dc21f1a608ad5900b982c54b74851ba71b9.zip
FreeBSD-src-faaa2dc21f1a608ad5900b982c54b74851ba71b9.tar.gz
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
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_jail.c31
1 files changed, 5 insertions, 26 deletions
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
index 050563b..8ce8327 100644
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -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;
}
}
OpenPOWER on IntegriCloud