PERFORCE change 188093 for review

Edward Tomasz Napierala trasz at FreeBSD.org
Sun Jan 23 13:31:39 UTC 2011


http://p4web.freebsd.org/@@188093?ac=10

Change 188093 by trasz at trasz_victim on 2011/01/23 13:31:18

	Stop trying to be clever in *_foreach() routines and just defer freeing
	rctl rules to a taskqueue.

Affected files ...

.. //depot/projects/soc2009/trasz_limits/sys/kern/kern_container.c#59 edit
.. //depot/projects/soc2009/trasz_limits/sys/kern/kern_jail.c#32 edit
.. //depot/projects/soc2009/trasz_limits/sys/kern/kern_loginclass.c#27 edit
.. //depot/projects/soc2009/trasz_limits/sys/kern/kern_rctl.c#14 edit
.. //depot/projects/soc2009/trasz_limits/sys/kern/kern_resource.c#59 edit
.. //depot/projects/soc2009/trasz_limits/sys/sys/jail.h#19 edit
.. //depot/projects/soc2009/trasz_limits/sys/sys/loginclass.h#12 edit
.. //depot/projects/soc2009/trasz_limits/sys/sys/rctl.h#7 edit
.. //depot/projects/soc2009/trasz_limits/sys/sys/resourcevar.h#24 edit

Differences ...

==== //depot/projects/soc2009/trasz_limits/sys/kern/kern_container.c#59 (text+ko) ====

@@ -739,7 +739,7 @@
 	}
 }
 
-static int
+static void
 container_dampen_callback(struct container *container, void *arg2, void *arg3)
 {
 	int orig, diff, hz;
@@ -751,7 +751,7 @@
 	KASSERT(orig >= 0, ("container_dampen_callback: orig < 0"));
 	if (orig == 0) {
 		mtx_unlock(&container_lock);
-		return (0);
+		return;
 	}
 	diff = orig / 10;
 	if (diff == 0)
@@ -760,8 +760,6 @@
 	KASSERT(container->c_resources[RUSAGE_PCTCPU] >= 0,
 	    ("container_dampen_callback: result < 0"));
 	mtx_unlock(&container_lock);
-
-	return (0);
 }
 
 static void

==== //depot/projects/soc2009/trasz_limits/sys/kern/kern_jail.c#32 (text+ko) ====

@@ -4262,25 +4262,16 @@
 SYSCTL_JAIL_PARAM(_allow, socket_af, CTLTYPE_INT | CTLFLAG_RW,
     "B", "Jail may create sockets other than just UNIX/IPv4/IPv6/route");
 
-int
-prison_container_foreach(int (*callback)(struct container *container,
+void
+prison_container_foreach(void (*callback)(struct container *container,
     void *arg2, void *arg3), void *arg2, void *arg3)
 {
-	int again;
 	struct prison *pr;
 
-again:
 	sx_slock(&allprison_lock);
-	TAILQ_FOREACH(pr, &allprison, pr_list) {
-		again = (callback)(&pr->pr_container, arg2, arg3);
-		if (again != 0) {
-			sx_sunlock(&allprison_lock);
-			goto again;
-		}
-	}
+	TAILQ_FOREACH(pr, &allprison, pr_list)
+		(callback)(&pr->pr_container, arg2, arg3);
 	sx_sunlock(&allprison_lock);
-
-	return (0);
 }
 
 #ifdef DDB

==== //depot/projects/soc2009/trasz_limits/sys/kern/kern_loginclass.c#27 (text+ko) ====

@@ -214,33 +214,16 @@
 	return (0);
 }
 
-int
-loginclass_container_foreach(int (*callback)(struct container *container,
+void
+loginclass_container_foreach(void (*callback)(struct container *container,
     void *arg2, void *arg3), void *arg2, void *arg3)
 {
-	int again;
 	struct loginclass *lc;
 
-again:
 	mtx_lock(&loginclasses_lock);
-	LIST_FOREACH(lc, &loginclasses, lc_next) {
-		/*
-		 * Callback might free the rule, which in turn could
-		 * result in freeing loginclass, which would cause
-		 * recursion on loginclasses_lock.
-		 */
-		loginclass_acquire(lc);
-		again = (callback)(&lc->lc_container, arg2, arg3);
-		if (again != 0) {
-			mtx_unlock(&loginclasses_lock);
-			loginclass_release(lc);
-			goto again;
-		}
-		loginclass_release(lc);
-	}
+	LIST_FOREACH(lc, &loginclasses, lc_next)
+		(callback)(&lc->lc_container, arg2, arg3);
 	mtx_unlock(&loginclasses_lock);
-
-	return (0);
 }
 
 static void

==== //depot/projects/soc2009/trasz_limits/sys/kern/kern_rctl.c#14 (text+ko) ====

@@ -55,6 +55,7 @@
 #include <sys/mutex.h>
 #include <sys/rwlock.h>
 #include <sys/sbuf.h>
+#include <sys/taskqueue.h>
 #include <sys/tree.h>
 #include <vm/uma.h>
 
@@ -689,6 +690,23 @@
 	refcount_acquire(&rule->rr_refcount);
 }
 
+static void
+rctl_rule_free(void *context, int pending)
+{
+	struct rctl_rule *rule;
+	
+	rule = (struct rctl_rule *)context;
+
+	KASSERT(rule->rr_refcount == 0, ("rule->rr_refcount == 0"));
+	
+	/*
+	 * We don't need locking here; rule is guaranteed to be inaccessible.
+	 */
+	
+	rctl_rule_release_subject(rule);
+	uma_zfree(rctl_rule_zone, rule);
+}
+
 void
 rctl_rule_release(struct rctl_rule *rule)
 {
@@ -696,8 +714,15 @@
 	KASSERT(rule->rr_refcount > 0, ("rule->rr_refcount > 0"));
 
 	if (refcount_release(&rule->rr_refcount)) {
-		rctl_rule_release_subject(rule);
-		uma_zfree(rctl_rule_zone, rule);
+		/*
+		 * rctl_rule_release() is often called when iterating
+		 * over all the uidinfo structures in the system,
+		 * holding uihashtbl_lock.  Since rctl_rule_free()
+		 * might end up calling uifree(), this would lead
+		 * to lock recursion.  Use taskqueue to avoid this.
+		 */
+		TASK_INIT(&rule->rr_task, 0, rctl_rule_free, rule);
+		taskqueue_enqueue(taskqueue_thread, &rule->rr_task);
 	}
 }
 
@@ -959,7 +984,7 @@
 	return (0);
 }
 
-static int
+static void
 rctl_rule_remove_callback(struct container *container, void *arg2, void *arg3)
 {
 	struct rctl_rule *filter = (struct rctl_rule *)arg2;
@@ -970,8 +995,6 @@
 	rw_wunlock(&rctl_lock);
 
 	*((int *)arg3) += found;
-
-	return (found);
 }
 
 /*
@@ -980,7 +1003,7 @@
 int
 rctl_rule_remove(struct rctl_rule *filter)
 {
-	int error, found = 0;
+	int found = 0;
 	struct proc *p;
 
 	if (filter->rr_subject_type == RCTL_SUBJECT_TYPE_PROCESS &&
@@ -994,15 +1017,12 @@
 		return (ESRCH);
 	}
 
-	error = loginclass_container_foreach(rctl_rule_remove_callback, filter,
+	loginclass_container_foreach(rctl_rule_remove_callback, filter,
 	    (void *)&found);
-	KASSERT(error == 0, ("loginclass_container_foreach failed"));
-	error = ui_container_foreach(rctl_rule_remove_callback, filter,
+	ui_container_foreach(rctl_rule_remove_callback, filter,
 	    (void *)&found);
-	KASSERT(error == 0, ("ui_container_foreach failed"));
-	error = prison_container_foreach(rctl_rule_remove_callback, filter,
+	prison_container_foreach(rctl_rule_remove_callback, filter,
 	    (void *)&found);
-	KASSERT(error == 0, ("prison_container_foreach failed"));
 
 	sx_assert(&allproc_lock, SA_LOCKED);
 	rw_wlock(&rctl_lock);
@@ -1196,7 +1216,7 @@
 	return (error);
 }
 
-static int
+static void
 rctl_get_rules_callback(struct container *container, void *arg2, void *arg3)
 {
 	struct rctl_rule *filter = (struct rctl_rule *)arg2;
@@ -1211,8 +1231,6 @@
 		sbuf_printf(sb, ",");
 	}
 	rw_runlock(&rctl_lock);
-
-	return (0);
 }
 
 int

==== //depot/projects/soc2009/trasz_limits/sys/kern/kern_resource.c#59 (text+ko) ====

@@ -1292,36 +1292,20 @@
 	rw_wunlock(&uihashtbl_lock);
 }
 
-int
-ui_container_foreach(int (*callback)(struct container *container,
+void
+ui_container_foreach(void (*callback)(struct container *container,
     void *arg2, void *arg3), void *arg2, void *arg3)
 {
-	int again;
 	struct uidinfo *uip;
 	struct uihashhead *uih;
 
-again:
 	rw_rlock(&uihashtbl_lock);
 	for (uih = &uihashtbl[uihash]; uih >= uihashtbl; uih--) {
 		LIST_FOREACH(uip, uih, ui_hash) {
-			/*
-			 * Callback might free the rule, which in turn could
-			 * result in freeing uidinfo, which would cause recursion
-			 * on uihashtbl_lock.
-			 */
-			uihold(uip);
-			again = (callback)(&uip->ui_container, arg2, arg3);
-			if (again != 0) {
-				rw_runlock(&uihashtbl_lock);
-				uifree(uip);
-				goto again;
-			}
-			uifree(uip);
+			(callback)(&uip->ui_container, arg2, arg3);
 		}
 	}
 	rw_runlock(&uihashtbl_lock);
-
-	return (0);
 }
 
 /*

==== //depot/projects/soc2009/trasz_limits/sys/sys/jail.h#19 (text+ko) ====

@@ -384,7 +384,7 @@
 char *prison_name(struct prison *, struct prison *);
 int prison_priv_check(struct ucred *cred, int priv);
 int sysctl_jail_param(struct sysctl_oid *, void *, int , struct sysctl_req *);
-int prison_container_foreach(int (*callback)(struct container *container,
+void prison_container_foreach(void (*callback)(struct container *container,
     void *arg2, void *arg3), void *arg2, void *arg3);
 
 #endif /* _KERNEL */

==== //depot/projects/soc2009/trasz_limits/sys/sys/loginclass.h#12 (text+ko) ====

@@ -42,7 +42,7 @@
 void	loginclass_acquire(struct loginclass *lc);
 void	loginclass_release(struct loginclass *lc);
 struct loginclass	*loginclass_find(const char *name);
-int	loginclass_container_foreach(int (*callback)(struct container
+void	loginclass_container_foreach(void (*callback)(struct container
 	    *container, void *arg2, void *arg3), void *arg2, void *arg3);
 
 #endif /* !_SYS_LOGINCLASS_H_ */

==== //depot/projects/soc2009/trasz_limits/sys/sys/rctl.h#7 (text+ko) ====

@@ -35,6 +35,7 @@
 #include <sys/cdefs.h>
 #include <sys/queue.h>
 #include <sys/types.h>
+#include <sys/_task.h>
 
 struct proc;
 struct uidinfo;
@@ -65,7 +66,7 @@
  * rule and remove the previous one.
  */
 struct rctl_rule {
-	int	rr_subject_type;
+	int		rr_subject_type;
 #ifdef DIAGNOSTIC
 	struct {
 #else
@@ -76,11 +77,12 @@
 		struct loginclass *hr_loginclass;
 		struct prison	*rs_prison;
 	} rr_subject;
-	int	rr_per;
-	int	rr_resource;
-	int	rr_action;
-	int64_t	rr_amount;
-	u_int	rr_refcount;
+	int		rr_per;
+	int		rr_resource;
+	int		rr_action;
+	int64_t		rr_amount;
+	u_int		rr_refcount;
+	struct task	rr_task;
 };
 
 #define	RCTL_SUBJECT_TYPE_UNDEFINED	-1

==== //depot/projects/soc2009/trasz_limits/sys/sys/resourcevar.h#24 (text+ko) ====

@@ -142,7 +142,7 @@
 void	 uifree(struct uidinfo *uip);
 void	 uihashinit(void);
 void	 uihold(struct uidinfo *uip);
-int	 ui_container_foreach(int (*callback)(struct container *container,
+void	 ui_container_foreach(void (*callback)(struct container *container,
 	    void *arg2, void *arg3), void *arg2, void *arg3);
 
 #endif /* _KERNEL */


More information about the p4-projects mailing list