diff options
author | jamie <jamie@FreeBSD.org> | 2011-08-26 16:03:34 +0000 |
---|---|---|
committer | jamie <jamie@FreeBSD.org> | 2011-08-26 16:03:34 +0000 |
commit | faaa2dc21f1a608ad5900b982c54b74851ba71b9 (patch) | |
tree | 2a14165a8a808b12c14438a87d436bc641f9825d /sys/kern/kern_jail.c | |
parent | a6e9ddddeabe3d609303aa5b60184265cdbd1aae (diff) | |
download | FreeBSD-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/kern_jail.c')
-rw-r--r-- | sys/kern/kern_jail.c | 31 |
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; } } |