فهرست منبع

cgroup: Add pids controller event when fork fails because of pid limit

This patch adds more visibility into the pids controller when the controller
rejects a fork request. Whenever fork fails because the limit on the number of
pids in the cgroup is reached, the controller will log this and also notify the
newly added cgroups events file. The `max` key in the events file represents
the number of times fork failed because of the pids controller.

This change also logs only the first time the `max` event counter is
incremented. This is to provide a hint to the user to understand why fork
failed, as users are not yet used to seeing fork failures because of the
pids controller.

Signed-off-by: Kenny Yu <kennyyu@fb.com>
Acked-by: Johannes Weiner <hannes <at> cmpxchg.org>
Signed-off-by: Tejun Heo <tj@kernel.org>
Kenny Yu 9 سال پیش
والد
کامیت
135b8b37bd
1فایلهای تغییر یافته به همراه33 افزوده شده و 1 حذف شده
  1. 33 1
      kernel/cgroup_pids.c

+ 33 - 1
kernel/cgroup_pids.c

@@ -49,6 +49,12 @@ struct pids_cgroup {
 	 */
 	 */
 	atomic64_t			counter;
 	atomic64_t			counter;
 	int64_t				limit;
 	int64_t				limit;
+
+	/* Handle for "pids.events" */
+	struct cgroup_file		events_file;
+
+	/* Number of times fork failed because limit was hit. */
+	atomic64_t			events_limit;
 };
 };
 
 
 static struct pids_cgroup *css_pids(struct cgroup_subsys_state *css)
 static struct pids_cgroup *css_pids(struct cgroup_subsys_state *css)
@@ -72,6 +78,7 @@ pids_css_alloc(struct cgroup_subsys_state *parent)
 
 
 	pids->limit = PIDS_MAX;
 	pids->limit = PIDS_MAX;
 	atomic64_set(&pids->counter, 0);
 	atomic64_set(&pids->counter, 0);
+	atomic64_set(&pids->events_limit, 0);
 	return &pids->css;
 	return &pids->css;
 }
 }
 
 
@@ -213,10 +220,21 @@ static int pids_can_fork(struct task_struct *task)
 {
 {
 	struct cgroup_subsys_state *css;
 	struct cgroup_subsys_state *css;
 	struct pids_cgroup *pids;
 	struct pids_cgroup *pids;
+	int err;
 
 
 	css = task_css_check(current, pids_cgrp_id, true);
 	css = task_css_check(current, pids_cgrp_id, true);
 	pids = css_pids(css);
 	pids = css_pids(css);
-	return pids_try_charge(pids, 1);
+	err = pids_try_charge(pids, 1);
+	if (err) {
+		/* Only log the first time events_limit is incremented. */
+		if (atomic64_inc_return(&pids->events_limit) == 1) {
+			pr_info("cgroup: fork rejected by pids controller in ");
+			pr_cont_cgroup_path(task_cgroup(current, pids_cgrp_id));
+			pr_cont("\n");
+		}
+		cgroup_file_notify(&pids->events_file);
+	}
+	return err;
 }
 }
 
 
 static void pids_cancel_fork(struct task_struct *task)
 static void pids_cancel_fork(struct task_struct *task)
@@ -288,6 +306,14 @@ static s64 pids_current_read(struct cgroup_subsys_state *css,
 	return atomic64_read(&pids->counter);
 	return atomic64_read(&pids->counter);
 }
 }
 
 
+static int pids_events_show(struct seq_file *sf, void *v)
+{
+	struct pids_cgroup *pids = css_pids(seq_css(sf));
+
+	seq_printf(sf, "max %ld\n", atomic64_read(&pids->events_limit));
+	return 0;
+}
+
 static struct cftype pids_files[] = {
 static struct cftype pids_files[] = {
 	{
 	{
 		.name = "max",
 		.name = "max",
@@ -300,6 +326,12 @@ static struct cftype pids_files[] = {
 		.read_s64 = pids_current_read,
 		.read_s64 = pids_current_read,
 		.flags = CFTYPE_NOT_ON_ROOT,
 		.flags = CFTYPE_NOT_ON_ROOT,
 	},
 	},
+	{
+		.name = "events",
+		.seq_show = pids_events_show,
+		.file_offset = offsetof(struct pids_cgroup, events_file),
+		.flags = CFTYPE_NOT_ON_ROOT,
+	},
 	{ }	/* terminate */
 	{ }	/* terminate */
 };
 };