PERFORCE change 165824 for review
Edward Tomasz Napierala
trasz at FreeBSD.org
Wed Jul 8 15:29:57 UTC 2009
http://perforce.freebsd.org/chv.cgi?CH=165824
Change 165824 by trasz at trasz_victim on 2009/07/08 15:29:43
Add a mechanism to get from the given process to the applicable
resource limits.
Affected files ...
.. //depot/projects/soc2009/trasz_limits/sys/kern/kern_hrl.c#27 edit
.. //depot/projects/soc2009/trasz_limits/sys/sys/hrl.h#20 edit
.. //depot/projects/soc2009/trasz_limits/sys/sys/jail.h#7 edit
.. //depot/projects/soc2009/trasz_limits/sys/sys/proc.h#7 edit
.. //depot/projects/soc2009/trasz_limits/sys/sys/resourcevar.h#8 edit
Differences ...
==== //depot/projects/soc2009/trasz_limits/sys/kern/kern_hrl.c#27 (text+ko) ====
@@ -148,9 +148,13 @@
static void hrl_init(void);
SYSINIT(hrl, SI_SUB_CPU, SI_ORDER_FIRST, hrl_init, NULL);
-static uma_zone_t hrl_zone;
+static uma_zone_t hrl_node_zone;
+static uma_zone_t hrl_limit_zone;
static struct mtx hrl_lock;
+static void hrl_rule_remove_limits(struct hrl_rule *rule);
+static void hrl_rule_add_limits(struct hrl_rule *rule);
+
MALLOC_DEFINE(M_HRL, "hrl", "Hierarchical Resource Limits");
#if 0
@@ -267,10 +271,18 @@
int i;
mtx_lock(&hrl_lock);
+ /*
+ * Inherit resources from the parent.
+ */
for (i = 0; i < HRL_RESOURCE_MAX; i++) {
if (parent->p_usage.hu_resources[i] != 0 && hrl_resource_inheritable(i))
hrl_allocated_proc(child, i, parent->p_usage.hu_resources[i]);
}
+
+ /*
+ * Assign rules appropriate for the process.
+ */
+ LIST_INIT(&child->p_limits);
mtx_unlock(&hrl_lock);
}
@@ -485,15 +497,17 @@
KASSERT(node != NULL, ("hrl_adjust: node removal failed"));
}
mtx_unlock(&hrl_lock);
- if (node != NULL)
- uma_zfree(hrl_zone, node);
+ if (node != NULL) {
+ hrl_rule_remove_limits(&node->hn_rule);
+ uma_zfree(hrl_node_zone, node);
+ }
return;
}
/*
* Adding a new limit or changing existing one.
*/
- node = uma_zalloc(hrl_zone, M_WAITOK);
+ node = uma_zalloc(hrl_node_zone, M_WAITOK);
*node = searched;
mtx_lock(&hrl_lock);
existing = RB_INSERT(hrl_tree, &hrls, node);
@@ -503,7 +517,9 @@
node->hn_rule.hr_amount = amount;
mtx_unlock(&hrl_lock);
if (existing != NULL)
- uma_zfree(hrl_zone, node);
+ uma_zfree(hrl_node_zone, node);
+ else
+ hrl_rule_add_limits(&node->hn_rule);
}
void
@@ -629,12 +645,185 @@
return (0);
}
+/*
+ * Add a new limit for a rule, if it's not already there.
+ */
+static void
+hrl_limit_add_if_needed(struct hrl_limits_head *limits_head, struct hrl_rule *rule)
+{
+ struct hrl_limit *limit, *new_limit;
+
+ new_limit = uma_zalloc(hrl_limit_zone, M_WAITOK);
+ mtx_lock(&hrl_lock);
+ LIST_FOREACH(limit, limits_head, hl_next) {
+ if (limit->hl_rule == rule) {
+ mtx_unlock(&hrl_lock);
+ uma_zfree(hrl_limit_zone, new_limit);
+ return;
+ }
+ }
+ new_limit->hl_rule = rule;
+ LIST_INSERT_HEAD(limits_head, new_limit, hl_next);
+ mtx_unlock(&hrl_lock);
+}
+
+/*
+ * Remove a limit for a rule.
+ */
+static void
+hrl_limit_remove(struct hrl_limits_head *limits_head, struct hrl_rule *rule)
+{
+ struct hrl_limit *limit, *limittmp;
+
+ mtx_lock(&hrl_lock);
+ LIST_FOREACH_SAFE(limit, limits_head, hl_next, limittmp) {
+ if (limit->hl_rule == rule) {
+ LIST_REMOVE(limit, hl_next);
+ mtx_unlock(&hrl_lock);
+ uma_zfree(hrl_limit_zone, limit);
+ return;
+ }
+ }
+ mtx_unlock(&hrl_lock);
+}
+
+/*
+ * Bind a rule to subjects to which it applies.
+ */
+static void
+hrl_rule_add_limits(struct hrl_rule *rule)
+{
+ struct proc *p;
+ struct uidinfo *uip;
+ struct gidinfo *gip;
+ struct prison *pr;
+
+ switch (rule->hr_subject) {
+ case HRL_SUBJECT_PROCESS:
+ /*
+ * The sx lock is to keep the process from going away.
+ */
+ sx_slock(&proctree_lock);
+ p = pfind(rule->hr_subject_id);
+ if (p == NULL) {
+ sx_sunlock(&proctree_lock);
+ return;
+ }
+
+ PROC_UNLOCK(p);
+ hrl_limit_add_if_needed(&p->p_limits, rule);
+ sx_sunlock(&proctree_lock);
+ return;
+
+ case HRL_SUBJECT_USER:
+ uip = uifind_existing(rule->hr_subject_id);
+ if (uip == NULL)
+ return;
+ hrl_limit_add_if_needed(&uip->ui_limits, rule);
+ uifree(uip);
+ return;
+
+ case HRL_SUBJECT_GROUP:
+ gip = gifind_existing(rule->hr_subject_id);
+ if (gip == NULL)
+ return;
+ hrl_limit_add_if_needed(&gip->gi_limits, rule);
+ gifree(gip);
+ return;
+
+ case HRL_SUBJECT_LOGINCLASS:
+ panic("hrl_rule_add_limits: HRL_SUBJECT_LOGINCLASS unimplemented");
+ return;
+
+ case HRL_SUBJECT_JAIL:
+ sx_xlock(&allprison_lock);
+ pr = prison_find(rule->hr_subject_id);
+ if (pr == NULL) {
+ sx_xunlock(&allprison_lock);
+ return;
+ }
+ hrl_limit_add_if_needed(&pr->pr_limits, rule);
+ prison_free(pr);
+ sx_xunlock(&allprison_lock);
+ return;
+
+ default:
+ panic("hrl_rule_add_limits: unknown subject %d", rule->hr_subject);
+ }
+}
+
+static void
+hrl_rule_remove_limits(struct hrl_rule *rule)
+{
+ struct proc *p;
+ struct uidinfo *uip;
+ struct gidinfo *gip;
+ struct prison *pr;
+
+ switch (rule->hr_subject) {
+ case HRL_SUBJECT_PROCESS:
+ /*
+ * The sx lock is to keep the process from going away.
+ */
+ sx_slock(&proctree_lock);
+ p = pfind(rule->hr_subject_id);
+ if (p == NULL) {
+ sx_sunlock(&proctree_lock);
+ return;
+ }
+
+ PROC_UNLOCK(p);
+ hrl_limit_remove(&p->p_limits, rule);
+ sx_sunlock(&proctree_lock);
+ return;
+
+ case HRL_SUBJECT_USER:
+ uip = uifind_existing(rule->hr_subject_id);
+ if (uip == NULL)
+ return;
+ hrl_limit_remove(&uip->ui_limits, rule);
+ uifree(uip);
+ return;
+
+ case HRL_SUBJECT_GROUP:
+ gip = gifind_existing(rule->hr_subject_id);
+ if (gip == NULL)
+ return;
+ hrl_limit_remove(&gip->gi_limits, rule);
+ gifree(gip);
+ return;
+
+ case HRL_SUBJECT_LOGINCLASS:
+ panic("hrl_rule_remove: HRL_SUBJECT_LOGINCLASS unimplemented");
+ return;
+
+ case HRL_SUBJECT_JAIL:
+ sx_xlock(&allprison_lock);
+ pr = prison_find(rule->hr_subject_id);
+ if (pr == NULL) {
+ sx_xunlock(&allprison_lock);
+ return;
+ }
+ hrl_limit_remove(&pr->pr_limits, rule);
+ prison_free(pr);
+ sx_xunlock(&allprison_lock);
+ return;
+
+ default:
+ panic("hrl_rule_remove: unknown subject %d", rule->hr_subject);
+ }
+}
+
+/*
+ * Add a rule to the ruleset or change the 'hr_amount' of existing
+ * rule.
+ */
static int
hrl_rule_add(struct hrl_rule *rule)
{
struct hrl_node *node, *existing;
- node = uma_zalloc(hrl_zone, M_WAITOK);
+ node = uma_zalloc(hrl_node_zone, M_WAITOK);
node->hn_rule = *rule;
mtx_lock(&hrl_lock);
@@ -644,7 +833,9 @@
mtx_unlock(&hrl_lock);
if (existing != NULL)
- uma_zfree(hrl_zone, node);
+ uma_zfree(hrl_node_zone, node);
+ else
+ hrl_rule_add_limits(rule);
return (0);
}
@@ -816,6 +1007,9 @@
return (error);
}
+/*
+ * Remove a rule from the ruleset.
+ */
static int
hrl_rule_remove(struct hrl_rule *rule)
{
@@ -830,10 +1024,11 @@
continue;
found = 1;
node = RB_REMOVE(hrl_tree, &hrls, node);
- KASSERT(node != NULL, ("hrl_proc_exit: node removal failed"));
+ KASSERT(node != NULL, ("hrl_rule_remove: node removal failed"));
mtx_unlock(&hrl_lock);
- uma_zfree(hrl_zone, node);
+ hrl_rule_remove_limits(&node->hn_rule);
+ uma_zfree(hrl_node_zone, node);
goto restart;
}
mtx_unlock(&hrl_lock);
@@ -1029,6 +1224,7 @@
{
int i;
struct hrl_node *node, *next;
+ struct hrl_limit *limit;
struct uidinfo *uip;
uip = p->p_ucred->cr_ruidinfo;
@@ -1057,17 +1253,33 @@
KASSERT(node != NULL, ("hrl_proc_exit: node removal failed"));
mtx_unlock(&hrl_lock);
- uma_zfree(hrl_zone, node);
+ uma_zfree(hrl_node_zone, node);
goto restart;
}
mtx_unlock(&hrl_lock);
+
+ /*
+ * Free the hrl_limit structures.
+ */
+restart2:
+ mtx_lock(&hrl_lock);
+ while (!LIST_EMPTY(&p->p_limits)) {
+ limit = LIST_FIRST(&p->p_limits);
+ LIST_REMOVE(limit, hl_next);
+ mtx_unlock(&hrl_lock);
+ uma_zfree(hrl_limit_zone, limit);
+ goto restart2;
+ }
+ mtx_unlock(&hrl_lock);
}
static void
hrl_init(void)
{
- hrl_zone = uma_zcreate("hrl", sizeof(struct hrl_node), NULL, NULL,
+ hrl_node_zone = uma_zcreate("hrl", sizeof(struct hrl_node), NULL, NULL,
+ NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
+ hrl_limit_zone = uma_zcreate("hrl", sizeof(struct hrl_limit), NULL, NULL,
NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
mtx_init(&hrl_lock, "hrl lock", NULL, MTX_RECURSE); /* XXX: Make it non-recurseable later. */
EVENTHANDLER_REGISTER(process_exit, hrl_proc_exit, NULL, EVENTHANDLER_PRI_ANY);
==== //depot/projects/soc2009/trasz_limits/sys/sys/hrl.h#20 (text+ko) ====
@@ -30,6 +30,7 @@
#define _HRL_H_
#include <sys/cdefs.h>
+#include <sys/queue.h>
#include <sys/types.h>
/*
@@ -112,6 +113,18 @@
int64_t hu_resources[HRL_RESOURCE_MAX + 1];
};
+/*
+ * 'hrl_limit' is used to link a subject with rules that apply
+ * to it. This way we don't have to search the whole HRL rules
+ * tree to enforce the limits.
+ */
+struct hrl_limit {
+ LIST_ENTRY(hrl_limit) hl_next;
+ struct hrl_rule *hl_rule;
+};
+
+LIST_HEAD(hrl_limits_head, hrl_limit);
+
#ifdef _KERNEL
struct proc;
==== //depot/projects/soc2009/trasz_limits/sys/sys/jail.h#7 (text+ko) ====
@@ -178,6 +178,7 @@
char pr_domainname[MAXHOSTNAMELEN]; /* (p) jail domainname */
char pr_hostuuid[HOSTUUIDLEN]; /* (p) jail hostuuid */
struct hrl_usage pr_usage; /* (*) HRL resource accounting */
+ struct hrl_limits_head pr_limits; /* (*) HRL rules applicable to the prison */
};
#endif /* _KERNEL || _WANT_PRISON */
==== //depot/projects/soc2009/trasz_limits/sys/sys/proc.h#7 (text+ko) ====
@@ -515,6 +515,7 @@
int p_pendingcnt; /* how many signals are pending */
struct itimers *p_itimers; /* (c) POSIX interval timers. */
struct hrl_usage p_usage; /* (*) HRL resource accounting */
+ struct hrl_limits_head p_limits;/* (*) HRL rules applicable to the proccess */
/* End area that is zeroed on creation. */
#define p_endzero p_magic
==== //depot/projects/soc2009/trasz_limits/sys/sys/resourcevar.h#8 (text+ko) ====
@@ -99,6 +99,7 @@
uid_t ui_uid; /* (a) uid */
u_int ui_ref; /* (b) reference count */
struct hrl_usage ui_usage; /* (*) HRL resource accounting */
+ struct hrl_limits_head ui_limits;/* (*) HRL rules applicable to the uid */
};
#define UIDINFO_VMSIZE_LOCK(ui) mtx_lock(&((ui)->ui_vmsize_mtx))
@@ -117,6 +118,7 @@
gid_t gi_gid; /* (a) gid */
u_int gi_ref; /* (b) reference count */
struct hrl_usage gi_usage; /* (*) HRL resource accounting */
+ struct hrl_limits_head gi_limits;/* (*) HRL rules applicable to the gid */
};
struct proc;
More information about the p4-projects
mailing list