From owner-p4-projects@FreeBSD.ORG Sun Oct 18 20:32:01 2009 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id A5AEA106566C; Sun, 18 Oct 2009 20:32:01 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 518F7106568F for ; Sun, 18 Oct 2009 20:32:01 +0000 (UTC) (envelope-from trasz@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 3DBFC8FC12 for ; Sun, 18 Oct 2009 20:32:01 +0000 (UTC) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id n9IKW1sP038139 for ; Sun, 18 Oct 2009 20:32:01 GMT (envelope-from trasz@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id n9IKW1up038137 for perforce@freebsd.org; Sun, 18 Oct 2009 20:32:01 GMT (envelope-from trasz@freebsd.org) Date: Sun, 18 Oct 2009 20:32:01 GMT Message-Id: <200910182032.n9IKW1up038137@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to trasz@freebsd.org using -f From: Edward Tomasz Napierala To: Perforce Change Reviews Precedence: bulk Cc: Subject: PERFORCE change 169582 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 18 Oct 2009 20:32:01 -0000 http://p4web.freebsd.org/chv.cgi?CH=169582 Change 169582 by trasz@trasz_victim on 2009/10/18 20:31:35 Working container hierarchy. Affected files ... .. //depot/projects/soc2009/trasz_limits/sys/kern/init_main.c#17 edit .. //depot/projects/soc2009/trasz_limits/sys/kern/kern_hrl.c#70 edit .. //depot/projects/soc2009/trasz_limits/sys/sys/hrl.h#39 edit Differences ... ==== //depot/projects/soc2009/trasz_limits/sys/kern/init_main.c#17 (text+ko) ==== @@ -477,6 +477,9 @@ #endif td->td_ucred = crhold(p->p_ucred); + /* Let the HRL know about the new process. */ + hrl_proc_init(p); + /* Create sigacts. */ p->p_sigacts = sigacts_alloc(); ==== //depot/projects/soc2009/trasz_limits/sys/kern/kern_hrl.c#70 (text+ko) ==== @@ -386,37 +386,6 @@ } } -#ifdef DIAGNOSTIC -/* - * Go through the resource usage info and verify that it makes sense. - */ -static void -hrl_assert_proc(const struct proc *p __unused) -{ - int resource; - struct ucred *cred; - struct prison *pr; - - cred = p->p_ucred; - mtx_assert(&hrl_lock, MA_OWNED); - for (resource = 0; resource <= HRL_RESOURCE_MAX; resource++) - KASSERT(p->p_container.hc_resources[resource] >= 0, - ("resource usage propagation meltdown")); - KASSERT(cred->cr_ruidinfo->ui_container.hc_resources[resource] >= 0, - ("resource usage propagation meltdown")); - KASSERT(cred->cr_ruidinfo->ui_container.hc_resources[resource] >= - p->p_container.hc_resources[resource], - ("resource usage propagation meltdown")); - for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent) { - KASSERT(pr->pr_container.hc_resources[resource] >= 0, - ("resource usage propagation meltdown")); - KASSERT(pr->pr_container.hc_resources[resource] >= - p->p_container.hc_resources[resource], - ("resource usage propagation meltdown")); - } -} -#endif /* DIAGNOSTIC */ - static void hrl_container_add(struct hrl_container *dest, const struct hrl_container *src) { @@ -426,12 +395,12 @@ for (i = 0; i <= HRL_RESOURCE_MAX; i++) { KASSERT(dest->hc_resources[i] >= 0, - ("resource usage propagation meltdown")); + ("resource usage propagation meltdown: dest < 0")); KASSERT(src->hc_resources[i] >= 0, - ("resource usage propagation meltdown")); + ("resource usage propagation meltdown: src < 0")); dest->hc_resources[i] += src->hc_resources[i]; KASSERT(dest->hc_resources[i] >= 0, - ("resource usage propagation meltdown")); + ("resource usage propagation meltdown: dest < 0 after addition")); } } @@ -444,63 +413,70 @@ for (i = 0; i <= HRL_RESOURCE_MAX; i++) { KASSERT(dest->hc_resources[i] >= 0, - ("resource usage propagation meltdown")); + ("resource usage propagation meltdown: dest < 0")); KASSERT(src->hc_resources[i] >= 0, - ("resource usage propagation meltdown")); + ("resource usage propagation meltdown: src < 0")); KASSERT(src->hc_resources[i] <= dest->hc_resources[i], - ("resource usage propagation meltdown")); + ("resource usage propagation meltdown: src > dest")); dest->hc_resources[i] -= src->hc_resources[i]; KASSERT(dest->hc_resources[i] >= 0, - ("resource usage propagation meltdown")); + ("resource usage propagation meltdown: dest < 0 after subtraction")); } } static void hrl_container_join(struct hrl_container *child, struct hrl_container *parent) { - struct hrl_container *container; + int i; mtx_assert(&hrl_lock, MA_OWNED); KASSERT(child != NULL, ("child != NULL")); KASSERT(parent != NULL, ("parent != NULL")); - LIST_FOREACH(container, &child->hc_parents, hc_next) - KASSERT(container != parent, ("container already joined")); - - LIST_INSERT_HEAD(&child->hc_parents, parent, hc_next); - hrl_container_add(parent, child); + for (i = 0; i <= HRL_HC_PARENTS_MAX; i++) { + KASSERT(child->hc_parents[i] != parent, + ("container already joined")); + if (child->hc_parents[i] == NULL) { + child->hc_parents[i] = parent; + hrl_container_add(parent, child); + return; + } + } + panic("container has too many parents"); } static void hrl_container_leave(struct hrl_container *child, struct hrl_container *parent) { - struct hrl_container *container, *containertmp; + int i; mtx_assert(&hrl_lock, MA_OWNED); KASSERT(child != NULL, ("child != NULL")); KASSERT(parent != NULL, ("parent != NULL")); - hrl_container_subtract(parent, child); - LIST_FOREACH_SAFE(container, &child->hc_parents, hc_next, containertmp) { - if (container != parent) - continue; - LIST_REMOVE(container, hc_next); - break; + for (i = 0; i <= HRL_HC_PARENTS_MAX; i++) { + if (child->hc_parents[i] == parent) { + hrl_container_subtract(parent, child); + child->hc_parents[i] = NULL; + return; + } } + panic("container not joined"); } static void hrl_container_leave_parents(struct hrl_container *child) { - struct hrl_container *parent; + int i; mtx_assert(&hrl_lock, MA_OWNED); KASSERT(child != NULL, ("child != NULL")); - while (!LIST_EMPTY(&child->hc_parents)) { - parent = LIST_FIRST(&child->hc_parents); - hrl_container_subtract(parent, child); - LIST_REMOVE(parent, hc_next); + for (i = 0; i <= HRL_HC_PARENTS_MAX; i++) { + if (child->hc_parents[i] == NULL) + continue; + hrl_container_subtract(child->hc_parents[i], child); + child->hc_parents[i] = NULL; } } @@ -511,9 +487,10 @@ for (i = 0; i <= HRL_RESOURCE_MAX; i++) KASSERT(container->hc_resources[i] == 0, - ("container not zeroed")); - - LIST_INIT(&container->hc_parents); + ("container->hc_resources[%d] != NULL", i)); + for (i = 0; i <= HRL_HC_PARENTS_MAX; i++) + KASSERT(container->hc_parents[i] == NULL, + ("container->hc_parents[%d] != NULL", i)); } void @@ -535,6 +512,63 @@ mtx_unlock(&hrl_lock); } +#ifdef DIAGNOSTIC +/* + * Go through the resource consumption information and make sure it makes sense. + */ +static void +hrl_container_assert(const struct hrl_container *container) +{ + int i, resource; + struct hrl_container *parent; + + mtx_assert(&hrl_lock, MA_OWNED); + KASSERT(container != NULL, ("NULL container")); + + for (resource = 0; resource <= HRL_RESOURCE_MAX; resource++) { + KASSERT(container->hc_resources[resource] >= 0, + ("resource usage propagation meltdown: resource < 0")); + } + + for (i = 0; i <= HRL_HC_PARENTS_MAX; i++) { + parent = container->hc_parents[i]; + if (parent == NULL); + continue; + hrl_container_assert(parent); + for (resource = 0; resource <= HRL_RESOURCE_MAX; resource++) { + KASSERT(parent->hc_resources[resource] >= + container->hc_resources[resource], + ("resource usage propagation meltdown: child > parent")); + } + } +} +#endif /* DIAGNOSTIC */ + +/* + * Increase consumption of 'resource' by 'amount' for 'container' + * and all its parents. Differently from other cases, 'amount' here + * may be less than zero. + */ +static void +hrl_container_alloc_resource(struct hrl_container *container, int resource, + uint64_t amount) +{ + int i; + + mtx_assert(&hrl_lock, MA_OWNED); + KASSERT(container != NULL, ("NULL container")); + + container->hc_resources[resource] += amount; + for (i = 0; i <= HRL_HC_PARENTS_MAX; i++) { + if (container->hc_parents[i] == NULL) + continue; + hrl_container_alloc_resource(container->hc_parents[i], resource, amount); + } +#ifdef DIAGNOSTIC + hrl_container_assert(container); +#endif +} + /* * Increase allocation of 'resource' by 'amount' for process 'p'. * Return 0 if it's below limits, or errno, if it's not. @@ -543,31 +577,21 @@ hrl_alloc(struct proc *p, int resource, uint64_t amount) { int error; - struct ucred *cred; - struct prison *pr; - KASSERT(amount > 0, ("hrl_alloc: invalid amount for %s: %ju", - hrl_resource_name(resource), amount)); - #if 0 printf("hrl_alloc: allocating %ju of %s for %s (pid %d)\n", amount, hrl_resource_name(resource), p->p_comm, p->p_pid); #endif + KASSERT(amount > 0, ("hrl_alloc: invalid amount for %s: %ju", + hrl_resource_name(resource), amount)); + mtx_lock(&hrl_lock); error = hrl_enforce_proc(p, resource, amount); if (error) { mtx_unlock(&hrl_lock); return (error); } - p->p_container.hc_resources[resource] += amount; - cred = p->p_ucred; - cred->cr_ruidinfo->ui_container.hc_resources[resource] += amount; - for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent) - pr->pr_container.hc_resources[resource] += amount; - cred->cr_loginclass->lc_container.hc_resources[resource] += amount; -#ifdef DIAGNOSTIC - hrl_assert_proc(p); -#endif + hrl_container_alloc_resource(&p->p_container, resource, amount); mtx_unlock(&hrl_lock); return (0); @@ -585,16 +609,14 @@ { int error; int64_t diff; - struct ucred *cred; - struct prison *pr; - KASSERT(amount >= 0, ("hrl_allocated: invalid amount for %s: %ju", - hrl_resource_name(resource), amount)); - #if 0 printf("hrl_allocated: allocated %lld of %s for %s (pid %d)\n", amount, hrl_resource_name(resource), p->p_comm, p->p_pid); #endif + KASSERT(amount >= 0, ("hrl_allocated: invalid amount for %s: %ju", + hrl_resource_name(resource), amount)); + mtx_lock(&hrl_lock); diff = amount - p->p_container.hc_resources[resource]; if (diff > 0) { @@ -604,15 +626,7 @@ return (error); } } - p->p_container.hc_resources[resource] = amount; - cred = p->p_ucred; - cred->cr_ruidinfo->ui_container.hc_resources[resource] += diff; - for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent) - pr->pr_container.hc_resources[resource] += diff; - cred->cr_loginclass->lc_container.hc_resources[resource] += diff; -#ifdef DIAGNOSTIC - hrl_assert_proc(p); -#endif + hrl_container_alloc_resource(&p->p_container, resource, diff); mtx_unlock(&hrl_lock); return (0); @@ -624,30 +638,21 @@ void hrl_free(struct proc *p, int resource, uint64_t amount) { - struct ucred *cred; - struct prison *pr; - - KASSERT(amount > 0, ("hrl_free: invalid amount for %s: %ju", - hrl_resource_name(resource), amount)); #if 0 printf("hrl_free: freeing %lld of %s for %s (pid %d)\n", amount, hrl_resource_name(resource), p->p_comm, p->p_pid); #endif + KASSERT(amount > 0, ("hrl_free: invalid amount for %s: %ju", + hrl_resource_name(resource), amount)); + mtx_lock(&hrl_lock); KASSERT(amount <= p->p_container.hc_resources[resource], ("hrl_free: freeing %ju of %s, which is more than allocated " "%ld for %s (pid %d)", amount, hrl_resource_name(resource), p->p_container.hc_resources[resource], p->p_comm, p->p_pid)); - p->p_container.hc_resources[resource] -= amount; - cred = p->p_ucred; - cred->cr_ruidinfo->ui_container.hc_resources[resource] -= amount; - for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent) - pr->pr_container.hc_resources[resource] -= amount; - cred->cr_loginclass->lc_container.hc_resources[resource] -= amount; -#ifdef DIAGNOSTIC - hrl_assert_proc(p); -#endif + + hrl_container_alloc_resource(&p->p_container, resource, -amount); mtx_unlock(&hrl_lock); } @@ -1380,7 +1385,7 @@ struct sbuf *sb; sb = sbuf_new_auto(); - for (i = 1; i <= HRL_RESOURCE_MAX; i++) { + for (i = 0; i <= HRL_RESOURCE_MAX; i++) { sbuf_printf(sb, "%s=%jd,", hrl_resource_name(i), container->hc_resources[i]); } @@ -1697,6 +1702,24 @@ } /* + * Called from kern/init_main.c, for proc0 and initproc. + */ +void +hrl_proc_init(struct proc *p) +{ + struct ucred *cred = p->p_ucred; + + mtx_lock(&hrl_lock); + + hrl_container_create(&p->p_container); + hrl_container_join(&p->p_container, &cred->cr_ruidinfo->ui_container); + hrl_container_join(&p->p_container, &cred->cr_loginclass->lc_container); + hrl_container_join(&p->p_container, &cred->cr_prison->pr_container); + + mtx_unlock(&hrl_lock); +} + +/* * Called before credentials change, to adjust HRL data structures * assigned to the process. */ @@ -1794,11 +1817,24 @@ int error, i; struct hrl_limit *limit; struct hrl_rule *rule; + struct hrl_container *container; PROC_LOCK(parent); PROC_LOCK(child); mtx_lock(&hrl_lock); + /* + * Create container for the child process and inherit containing + * containers from the parent. + */ + hrl_container_create(&child->p_container); + for (i = 0; i <= HRL_HC_PARENTS_MAX; i++) { + container = parent->p_container.hc_parents[i]; + if (container == NULL) + continue; + hrl_container_join(&child->p_container, container); + } + for (i = 0; i <= HRL_RESOURCE_MAX; i++) { if (parent->p_container.hc_resources[i] != 0 && hrl_resource_inheritable(i)) @@ -1806,6 +1842,11 @@ parent->p_container.hc_resources[i]); } + /* + * Go through limits applicable to the parent and assign them to the child. + * Rules with 'process' subject have to be duplicated in order to make their + * hr_subject point to the new process. + */ LIST_FOREACH(limit, &parent->p_limits, hl_next) { if (limit->hl_rule->hr_subject_type == HRL_SUBJECT_TYPE_PROCESS) { rule = hrl_rule_duplicate(limit->hl_rule, M_NOWAIT); @@ -1830,8 +1871,6 @@ void hrl_proc_exiting(struct proc *p) { - int i; - /* * XXX: Free these three some other way. */ @@ -1840,10 +1879,7 @@ hrl_allocated(p, HRL_RESOURCE_PTY, 0); mtx_lock(&hrl_lock); - for (i = 0; i <= HRL_RESOURCE_MAX; i++) { - KASSERT(p->p_container.hc_resources[i] == 0, - ("dead process still holding resources")); - } + hrl_container_destroy(&p->p_container); mtx_unlock(&hrl_lock); } ==== //depot/projects/soc2009/trasz_limits/sys/sys/hrl.h#39 (text+ko) ==== @@ -123,6 +123,8 @@ #define HRL_AMOUNT_UNDEFINED -1 +#define HRL_HC_PARENTS_MAX 32 + /* * 'hrl_container' defines resource consumption for a particular * subject, such as process or jail. Containers form a graph - each @@ -139,9 +141,8 @@ * is HRL_SUBJECT_TYPE_USER. */ struct hrl_container { - LIST_ENTRY(hrl_container) hc_next; int64_t hc_resources[HRL_RESOURCE_MAX + 1]; - LIST_HEAD(, hrl_container) hc_parents; + struct hrl_container *hc_parents[HRL_HC_PARENTS_MAX + 1]; }; /* @@ -164,6 +165,7 @@ void hrl_proc_exiting(struct proc *p); +void hrl_proc_init(struct proc *p); void hrl_proc_ucred_changing(struct proc *p, struct ucred *newcred); struct hrl_rule *hrl_rule_alloc(int flags);