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