diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c index c96d271a20cd..b782b977500e 100644 --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -130,6 +130,7 @@ static char *prison_path(struct prison *pr1, struct prison *pr2); static void prison_remove_one(struct prison *pr); #ifdef RACCT static void prison_racct_attach(struct prison *pr); +static void prison_racct_modify(struct prison *pr); static void prison_racct_detach(struct prison *pr); #endif #ifdef INET @@ -1830,6 +1831,12 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) if (!(flags & JAIL_ATTACH)) sx_sunlock(&allprison_lock); } + +#ifdef RACCT + if (!created) + prison_racct_modify(pr); +#endif + td->td_retval[0] = pr->pr_id; goto done_errmsg; @@ -4427,24 +4434,32 @@ prison_racct_hold(struct prison_racct *prr) refcount_acquire(&prr->prr_refcount); } +static void +prison_racct_free_locked(struct prison_racct *prr) +{ + + sx_assert(&allprison_lock, SA_XLOCKED); + + if (refcount_release(&prr->prr_refcount)) { + racct_destroy(&prr->prr_racct); + LIST_REMOVE(prr, prr_next); + free(prr, M_PRISON_RACCT); + } +} + void prison_racct_free(struct prison_racct *prr) { int old; + sx_assert(&allprison_lock, SA_UNLOCKED); + old = prr->prr_refcount; if (old > 1 && atomic_cmpset_int(&prr->prr_refcount, old, old - 1)) return; sx_xlock(&allprison_lock); - if (refcount_release(&prr->prr_refcount)) { - racct_destroy(&prr->prr_racct); - LIST_REMOVE(prr, prr_next); - sx_xunlock(&allprison_lock); - free(prr, M_PRISON_RACCT); - - return; - } + prison_racct_free_locked(prr); sx_xunlock(&allprison_lock); } @@ -4454,15 +4469,63 @@ prison_racct_attach(struct prison *pr) { struct prison_racct *prr; + sx_assert(&allprison_lock, SA_XLOCKED); + prr = prison_racct_find_locked(pr->pr_name); KASSERT(prr != NULL, ("cannot find prison_racct")); pr->pr_prison_racct = prr; } +/* + * Handle jail renaming. From the racct point of view, renaming means + * moving from one prison_racct to another. + */ +static void +prison_racct_modify(struct prison *pr) +{ + struct proc *p; + struct ucred *cred; + struct prison_racct *oldprr; + + sx_slock(&allproc_lock); + sx_xlock(&allprison_lock); + + if (strcmp(pr->pr_name, pr->pr_prison_racct->prr_name) == 0) + return; + + oldprr = pr->pr_prison_racct; + pr->pr_prison_racct = NULL; + + prison_racct_attach(pr); + + /* + * Move resource utilisation records. + */ + racct_move(pr->pr_prison_racct->prr_racct, oldprr->prr_racct); + + /* + * Force rctl to reattach rules to processes. + */ + FOREACH_PROC_IN_SYSTEM(p) { + PROC_LOCK(p); + cred = crhold(p->p_ucred); + PROC_UNLOCK(p); + racct_proc_ucred_changed(p, cred, cred); + crfree(cred); + } + + sx_sunlock(&allproc_lock); + prison_racct_free_locked(oldprr); + sx_xunlock(&allprison_lock); +} + static void prison_racct_detach(struct prison *pr) { + + sx_assert(&allprison_lock, SA_UNLOCKED); + prison_racct_free(pr->pr_prison_racct); pr->pr_prison_racct = NULL; } diff --git a/sys/kern/kern_racct.c b/sys/kern/kern_racct.c index ac0e98d8bb4e..b1008bc490d1 100644 --- a/sys/kern/kern_racct.c +++ b/sys/kern/kern_racct.c @@ -697,6 +697,18 @@ racct_proc_ucred_changed(struct proc *p, struct ucred *oldcred, #endif } +void +racct_move(struct racct *dest, struct racct *src) +{ + + mtx_lock(&racct_lock); + + racct_add_racct(dest, src); + racct_sub_racct(src, src); + + mtx_unlock(&racct_lock); +} + static void racctd(void) { diff --git a/sys/sys/racct.h b/sys/sys/racct.h index 095932c22f9a..b4aeee8d21f8 100644 --- a/sys/sys/racct.h +++ b/sys/sys/racct.h @@ -142,5 +142,6 @@ void racct_proc_exit(struct proc *p); void racct_proc_ucred_changed(struct proc *p, struct ucred *oldcred, struct ucred *newcred); +void racct_move(struct racct *dest, struct racct *src); #endif /* !_RACCT_H_ */