PERFORCE change 167048 for review

Edward Tomasz Napierala trasz at FreeBSD.org
Wed Aug 5 19:36:08 UTC 2009


http://perforce.freebsd.org/chv.cgi?CH=167048

Change 167048 by trasz at trasz_anger on 2009/08/05 19:35:23

	Rewrite hrl_get_rules(2) and hrl_get_limits(2).  Previous
	approach was racy.

Affected files ...

.. //depot/projects/soc2009/trasz_limits/sys/kern/kern_hrl.c#46 edit
.. //depot/projects/soc2009/trasz_limits/sys/kern/kern_loginclass.c#5 edit
.. //depot/projects/soc2009/trasz_limits/sys/kern/kern_resource.c#21 edit
.. //depot/projects/soc2009/trasz_limits/sys/sys/hrl.h#29 edit
.. //depot/projects/soc2009/trasz_limits/sys/sys/loginclass.h#3 edit
.. //depot/projects/soc2009/trasz_limits/sys/sys/resourcevar.h#11 edit

Differences ...

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

@@ -111,8 +111,8 @@
 
 static void hrl_compute_available(struct proc *p, int64_t (*availablep)[],
     struct hrl_rule *(*rulesp)[]);
-static struct sbuf *hrl_rules_to_sbuf(struct hrl_rule *usage, int nrules);
 static int hrl_rule_fully_specified(const struct hrl_rule *rule);
+static void hrl_rule_to_sbuf(struct sbuf *sb, const struct hrl_rule *rule);
 
 MALLOC_DEFINE(M_HRL, "hrl", "Hierarchical Resource Limits");
 
@@ -273,7 +273,8 @@
 		printf("hrl_enforce_proc: XXX, \"delay\" unimplemented.\n");
 		return (0);
 	case HRL_ACTION_LOG:
-		sb = hrl_rules_to_sbuf(rules[resource], 1);
+		sb = sbuf_new_auto();
+		hrl_rule_to_sbuf(sb, rules[resource]);
 		sbuf_finish(sb);
 		printf("resource limit \"%s\" exceeded by process %d (%s), "
 		    "uid %d\n", sbuf_data(sb), p->p_pid, p->p_comm,
@@ -1026,7 +1027,7 @@
 }
 
 static int
-hrl_rule_remove_callback(struct hrl_limits_head *limits, const struct hrl_rule *filter, void *arg3, void *arg4 __unused)
+hrl_rule_remove_callback(struct hrl_limits_head *limits, const struct hrl_rule *filter, void *arg3)
 {
 	int *found = (int *)arg3;
 
@@ -1057,11 +1058,11 @@
 		return (ESRCH);
 	}
 
-	error = loginclass_limits_foreach(hrl_rule_remove_callback, filter, (void *)&found, NULL);
+	error = loginclass_limits_foreach(hrl_rule_remove_callback, filter, (void *)&found);
 	KASSERT(error == 0, ("loginclass_limits_foreach failed"));
-	error = ui_limits_foreach(hrl_rule_remove_callback, filter, (void *)&found, NULL);
+	error = ui_limits_foreach(hrl_rule_remove_callback, filter, (void *)&found);
 	KASSERT(error == 0, ("ui_limits_foreach failed"));
-	error = gi_limits_foreach(hrl_rule_remove_callback, filter, (void *)&found, NULL);
+	error = gi_limits_foreach(hrl_rule_remove_callback, filter, (void *)&found);
 	KASSERT(error == 0, ("gi_limits_foreach failed"));
 
 	sx_slock(&proctree_lock);
@@ -1077,40 +1078,31 @@
 	return (ESRCH);
 }
 
-static struct sbuf *
-hrl_rules_to_sbuf(struct hrl_rule *rules, int nrules)
+/*
+ * Appends a rule to the sbuf.
+ */
+static void
+hrl_rule_to_sbuf(struct sbuf *sb, const struct hrl_rule *rule)
 {
-	int i;
-	struct sbuf *sb;
-
-	sb = sbuf_new_auto();
-	for (i = 0; i < nrules; i++) {
-		if (rules[i].hr_subject == HRL_SUBJECT_LOGINCLASS) {
-			KASSERT(rules[i].hr_subject_id != HRL_SUBJECT_ID_UNDEFINED,
-			    ("rules[i].hr_subject_id != HRL_SUBJECT_ID_UNDEFINED"));
-			sbuf_printf(sb, "%s:%s:%s:%s=%jd",
-			    hrl_subject_name(rules[i].hr_subject),
-			    ((struct loginclass *)(long)rules[i].hr_subject_id)->lc_name,
-			    hrl_resource_name(rules[i].hr_resource),
-			    hrl_action_name(rules[i].hr_action),
-			    rules[i].hr_amount);
-		} else {
-			sbuf_printf(sb, "%s:%d:%s:%s=%jd",
-			    hrl_subject_name(rules[i].hr_subject),
-			    (int)rules[i].hr_subject_id,
-			    hrl_resource_name(rules[i].hr_resource),
-			    hrl_action_name(rules[i].hr_action),
-			    rules[i].hr_amount);
-		}
-		if (rules[i].hr_per != rules[i].hr_subject)
-			sbuf_printf(sb, "/%s,",
-			    hrl_subject_name(rules[i].hr_per));
-		else
-			sbuf_printf(sb, ",");
+	if (rule->hr_subject == HRL_SUBJECT_LOGINCLASS) {
+		KASSERT(rule->hr_subject_id != HRL_SUBJECT_ID_UNDEFINED,
+		    ("rule->hr_subject_id != HRL_SUBJECT_ID_UNDEFINED"));
+		sbuf_printf(sb, "%s:%s:%s:%s=%jd",
+		    hrl_subject_name(rule->hr_subject),
+		    ((struct loginclass *)(long)rule->hr_subject_id)->lc_name,
+		    hrl_resource_name(rule->hr_resource),
+		    hrl_action_name(rule->hr_action),
+		    rule->hr_amount);
+	} else {
+		sbuf_printf(sb, "%s:%d:%s:%s=%jd",
+		    hrl_subject_name(rule->hr_subject),
+		    (int)rule->hr_subject_id,
+		    hrl_resource_name(rule->hr_resource),
+		    hrl_action_name(rule->hr_action),
+		    rule->hr_amount);
 	}
-	if (sbuf_len(sb) > 0)
-		sbuf_setpos(sb, sbuf_len(sb) - 1);
-	return (sb);
+	if (rule->hr_per != rule->hr_subject)
+		sbuf_printf(sb, "/%s", hrl_subject_name(rule->hr_per));
 }
 
 /*
@@ -1284,22 +1276,18 @@
 }
 
 static int
-hrl_get_rules_callback(struct hrl_limits_head *limits, const struct hrl_rule *filter, void *arg3, void *arg4)
+hrl_get_rules_callback(struct hrl_limits_head *limits, const struct hrl_rule *filter, void *arg3)
 {
 	struct hrl_limit *limit;
-	struct hrl_rule *buf = (struct hrl_rule *)arg3;
-	int copied = 0, *available = (int *)arg4;
+	struct sbuf *sb = (struct sbuf *)arg3;
 
 	mtx_assert(&hrl_lock, MA_OWNED);
 
 	LIST_FOREACH(limit, limits, hl_next) {
-		if (*available <= 0)
-			return (ERANGE);
 		if (!hrl_rule_matches(limit->hl_rule, filter))
 			continue;
-		*(buf + copied) = *limit->hl_rule;
-		copied++;
-		(*available)--;
+		hrl_rule_to_sbuf(sb, limit->hl_rule);
+		sbuf_printf(sb, ",");
 	}
 
 	return (0);
@@ -1308,10 +1296,11 @@
 int
 hrl_get_rules(struct thread *td, struct hrl_get_rules_args *uap)
 {
-	int error, copied, bufsize = HRL_MAX_RULES, available;
-	char *inputstr;
-	struct sbuf *outputsbuf;
-	struct hrl_rule *filter, *buf;
+	int error;
+	size_t bufsize = HRL_MAX_RULES;
+	char *inputstr, *buf;
+	struct sbuf *sb;
+	struct hrl_rule *filter;
 	struct hrl_limit *limit;
 	struct proc *p;
 
@@ -1325,20 +1314,14 @@
 		return (EINVAL);
 
 again:
-	buf = malloc(bufsize * sizeof(*buf), M_HRL, M_WAITOK);
-	available = bufsize;
-	copied = 0;
+	buf = malloc(bufsize, M_HRL, M_WAITOK);
+	sb = sbuf_new(NULL, buf, bufsize, SBUF_FIXEDLEN);
+	KASSERT(sb != NULL, ("sbuf_new failed"));
+
 	sx_slock(&proctree_lock);
 	FOREACH_PROC_IN_SYSTEM(p) {
 		mtx_lock(&hrl_lock);
 		LIST_FOREACH(limit, &p->p_limits, hl_next) {
-			if (available <= 0) {
-				mtx_unlock(&hrl_lock);
-				sx_sunlock(&proctree_lock);
-				bufsize *= 4;
-				free(buf, M_HRL);
-				goto again;
-			}
 			/*
 			 * Non-process rules will be added to the buffer later.
 			 * Adding them here would result in duplicated output.
@@ -1347,33 +1330,32 @@
 				continue;
 			if (!hrl_rule_matches(limit->hl_rule, filter))
 				continue;
-			*(buf + copied) = *limit->hl_rule;
-			copied++;
-			available--;
+			hrl_rule_to_sbuf(sb, limit->hl_rule);
+			sbuf_printf(sb, ",");
 		}
 		mtx_unlock(&hrl_lock);
 	}
 	sx_sunlock(&proctree_lock);
 
 	mtx_lock(&hrl_lock);
-	loginclass_limits_foreach(hrl_get_rules_callback, filter,
-	    buf + copied, &available);
-	copied = bufsize - available;
-	ui_limits_foreach(hrl_get_rules_callback, filter,
-	    buf + copied, &available);
-	copied = bufsize - available;
-	gi_limits_foreach(hrl_get_rules_callback, filter,
-	    buf + copied, &available);
+	loginclass_limits_foreach(hrl_get_rules_callback, filter, sb);
+	ui_limits_foreach(hrl_get_rules_callback, filter, sb);
+	gi_limits_foreach(hrl_get_rules_callback, filter, sb);
 	mtx_unlock(&hrl_lock);
-	if (available <= 0) {
+	if (sbuf_overflowed(sb)) {
+		sbuf_delete(sb);
+		free(buf, M_HRL);
 		bufsize *= 4;
-		free(buf, M_HRL);
 		goto again;
 	}
 
-	outputsbuf = hrl_rules_to_sbuf(buf, copied);
+	/*
+	 * Remove trailing ",".
+	 */
+	if (sbuf_len(sb) > 0)
+		sbuf_setpos(sb, sbuf_len(sb) - 1);
 
-	error = hrl_write_outbuf(outputsbuf, uap->outbufp, uap->outbuflen);
+	error = hrl_write_outbuf(sb, uap->outbufp, uap->outbuflen);
 
 	hrl_rule_release(filter);
 	free(buf, M_HRL);
@@ -1383,10 +1365,11 @@
 int
 hrl_get_limits(struct thread *td, struct hrl_get_limits_args *uap)
 {
-	int error, copied, maxcopied = HRL_MAX_RULES;
-	char *inputstr;
-	struct sbuf *outputsbuf;
-	struct hrl_rule *filter, *buf;
+	int error;
+	size_t bufsize = HRL_MAX_RULES;
+	char *inputstr, *buf;
+	struct sbuf *sb;
+	struct hrl_rule *filter;
 	struct hrl_limit *limit;
 	struct proc *p;
 
@@ -1400,50 +1383,52 @@
 		return (EINVAL);
 
 	if (filter->hr_subject == HRL_SUBJECT_UNDEFINED) {
-		error = EINVAL;
-		goto out;
+		hrl_rule_release(filter);
+		return (EINVAL);
 	}
 
 	if (filter->hr_subject_id == HRL_SUBJECT_ID_UNDEFINED) {
-		error = EINVAL;
-		goto out;
+		hrl_rule_release(filter);
+		return (EINVAL);
 	}
 
 	if (filter->hr_subject != HRL_SUBJECT_PROCESS) {
-		error = EOPNOTSUPP;
-		goto out;
+		hrl_rule_release(filter);
+		return (EOPNOTSUPP);
 	}
 
-again:
-	buf = malloc(maxcopied * sizeof(*buf), M_HRL, M_WAITOK);
-	copied = 0;
-
 	p = pfind(filter->hr_subject_id);
 	if (p == NULL) {
-		error = ESRCH;
-		goto out;
+		hrl_rule_release(filter);
+		return (ESRCH);
 	}
+
+again:
+	buf = malloc(bufsize, M_HRL, M_WAITOK);
+	sb = sbuf_new(NULL, buf, bufsize, SBUF_FIXEDLEN);
+	KASSERT(sb != NULL, ("sbuf_new failed"));
+
 	mtx_lock(&hrl_lock);
 	LIST_FOREACH(limit, &p->p_limits, hl_next) {
-		if (copied >= maxcopied) {
-			mtx_unlock(&hrl_lock);
-			PROC_UNLOCK(p);
-			maxcopied *= 4;
-			free(buf, M_HRL);
-			goto again;
-		}
-		*(buf + copied) = *limit->hl_rule;
-		copied++;
+		hrl_rule_to_sbuf(sb, limit->hl_rule);
+		sbuf_printf(sb, ",");
 	}
 	mtx_unlock(&hrl_lock);
 	PROC_UNLOCK(p);
-	if (error)
-		goto out;
+	if (sbuf_overflowed(sb)) {
+		sbuf_delete(sb);
+		free(buf, M_HRL);
+		bufsize *= 4;
+		goto again;
+	}
 
-	outputsbuf = hrl_rules_to_sbuf(buf, copied);
+	/*
+	 * Remove trailing ",".
+	 */
+	if (sbuf_len(sb) > 0)
+		sbuf_setpos(sb, sbuf_len(sb) - 1);
 
-	error = hrl_write_outbuf(outputsbuf, uap->outbufp, uap->outbuflen);
-out:
+	error = hrl_write_outbuf(sb, uap->outbufp, uap->outbuflen);
 	hrl_rule_release(filter);
 	free(buf, M_HRL);
 	return (error);

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

@@ -204,14 +204,14 @@
 
 int
 loginclass_limits_foreach(int (*callback)(struct hrl_limits_head *limits,
-    const struct hrl_rule *filter, void *arg3, void *arg4),
-    const struct hrl_rule *filter, void *arg3, void *arg4)
+    const struct hrl_rule *filter, void *arg3),
+    const struct hrl_rule *filter, void *arg3)
 {
 	int error;
 	struct loginclass *lc;
 
 	LIST_FOREACH(lc, &loginclasses, lc_next) {
-		error = (callback)(&lc->lc_limits, filter, arg3, arg4);
+		error = (callback)(&lc->lc_limits, filter, arg3);
 		if (error)
 			return (error);
 	}

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

@@ -1414,8 +1414,8 @@
 
 int
 ui_limits_foreach(int (*callback)(struct hrl_limits_head *limits,
-    const struct hrl_rule *filter, void *arg3, void *arg4),
-    const struct hrl_rule *filter, void *arg3, void *arg4)
+    const struct hrl_rule *filter, void *arg3),
+    const struct hrl_rule *filter, void *arg3)
 {
 	int error;
 	struct uidinfo *uip, *nextuip;
@@ -1425,7 +1425,7 @@
 	for (uih = &uihashtbl[uihash]; uih >= uihashtbl; uih--) {
 		for (uip = LIST_FIRST(uih); uip; uip = nextuip) {
 			nextuip = LIST_NEXT(uip, ui_hash);
-			error = (callback)(&uip->ui_limits, filter, arg3, arg4);
+			error = (callback)(&uip->ui_limits, filter, arg3);
 			if (error) {
 				rw_runlock(&uihashtbl_lock);
 				return (error);
@@ -1584,8 +1584,8 @@
 
 int
 gi_limits_foreach(int (*callback)(struct hrl_limits_head *limits,
-    const struct hrl_rule *filter, void *arg3, void *arg4),
-    const struct hrl_rule *filter, void *arg3, void *arg4)
+    const struct hrl_rule *filter, void *arg3),
+    const struct hrl_rule *filter, void *arg3)
 {
 	int error;
 	struct gidinfo *gip, *nextgip;
@@ -1595,7 +1595,7 @@
 	for (gih = &gihashtbl[gihash]; gih >= gihashtbl; gih--) {
 		for (gip = LIST_FIRST(gih); gip; gip = nextgip) {
 			nextgip = LIST_NEXT(gip, gi_hash);
-			error = (callback)(&gip->gi_limits, filter, arg3, arg4);
+			error = (callback)(&gip->gi_limits, filter, arg3);
 			if (error) {
 				rw_runlock(&gihashtbl_lock);
 				return (error);

==== //depot/projects/soc2009/trasz_limits/sys/sys/hrl.h#29 (text+ko) ====

@@ -138,7 +138,6 @@
 void	hrl_usage_subtract(struct hrl_usage *dest, const struct hrl_usage *src);
 void	hrl_proc_exiting(struct proc *p);
 
-
 void hrl_proc_loginclass_changed(struct proc *p);
 void hrl_proc_ucred_changed(struct proc *p);
 

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

@@ -42,8 +42,8 @@
 void	loginclass_release(struct loginclass *lc);
 struct loginclass	*loginclass_find(const char *name);
 int	loginclass_limits_foreach(int (*callback)(struct hrl_limits_head *limits,
-	    const struct hrl_rule *filter, void *arg3, void *arg4),
-	    const struct hrl_rule *filter, void *arg3, void *arg4);
+	    const struct hrl_rule *filter, void *arg3),
+	    const struct hrl_rule *filter, void *arg3);
 
 #endif /* !_SYS_LOGINCLASS_H_ */
 

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

@@ -160,8 +160,8 @@
 void	 uihashinit(void);
 void	 uihold(struct uidinfo *uip);
 int	 ui_limits_foreach(int (*callback)(struct hrl_limits_head *limits,
-	    const struct hrl_rule *filter, void *arg3, void *arg4),
-	    const struct hrl_rule *filter, void *arg3, void *arg4);
+	    const struct hrl_rule *filter, void *arg3),
+	    const struct hrl_rule *filter, void *arg3);
 struct gidinfo
 	*gifind(gid_t gid);
 struct gidinfo
@@ -170,8 +170,8 @@
 void	 gihashinit(void);
 void	 gihold(struct gidinfo *gip);
 int	 gi_limits_foreach(int (*callback)(struct hrl_limits_head *limits,
-	    const struct hrl_rule *filter, void *arg3, void *arg4),
-	    const struct hrl_rule *filter, void *arg3, void *arg4);
+	    const struct hrl_rule *filter, void *arg3),
+	    const struct hrl_rule *filter, void *arg3);
 
 #endif /* _KERNEL */
 #endif /* !_SYS_RESOURCEVAR_H_ */


More information about the p4-projects mailing list