All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] cgroup: Add pids controller event when fork fails because of pid limit
@ 2016-06-21  3:09 ` Kenny Yu
  0 siblings, 0 replies; 18+ messages in thread
From: Kenny Yu @ 2016-06-21  3:09 UTC (permalink / raw)
  To: tj, lizefan, hannes, cyphar; +Cc: kennyyu, cgroups, linux-kernel, kernel-team

Summary:
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 adds an atomic boolean to prevent logging too much (e.g. a fork
bomb). The message is logged once per cgroup until the next time the pids limit
changes.

Signed-off-by: Kenny Yu <kennyyu@fb.com>
---
 kernel/cgroup_pids.c | 46 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 45 insertions(+), 1 deletion(-)

diff --git a/kernel/cgroup_pids.c b/kernel/cgroup_pids.c
index b93cbe3..8ba8c8f 100644
--- a/kernel/cgroup_pids.c
+++ b/kernel/cgroup_pids.c
@@ -49,6 +49,18 @@ struct pids_cgroup {
 	 */
 	atomic64_t			counter;
 	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;
+
+	/*
+	 * To avoid logging too much (e.g. during a fork bomb), log only once
+	 * per cgroup and reset this when the limit changes.
+	 */
+	atomic_t			events_limit_logged;
 };
 
 static struct pids_cgroup *css_pids(struct cgroup_subsys_state *css)
@@ -72,6 +84,8 @@ pids_css_alloc(struct cgroup_subsys_state *parent)
 
 	pids->limit = PIDS_MAX;
 	atomic64_set(&pids->counter, 0);
+	atomic64_set(&pids->events_limit, 0);
+	atomic_set(&pids->events_limit_logged, 0);
 	return &pids->css;
 }
 
@@ -205,6 +219,17 @@ static void pids_cancel_attach(struct cgroup_taskset *tset)
 	}
 }
 
+static void pids_fork_failed_event(struct pids_cgroup *pids)
+{
+	atomic64_inc(&pids->events_limit);
+	cgroup_file_notify(&pids->events_file);
+	if (!atomic_xchg(&pids->events_limit_logged, 1)) {
+		pr_info("cgroup: fork rejected by pids controller in ");
+		pr_cont_cgroup_path(task_cgroup(current, pids_cgrp_id));
+		pr_cont("\n");
+	}
+}
+
 /*
  * task_css_check(true) in pids_can_fork() and pids_cancel_fork() relies
  * on threadgroup_change_begin() held by the copy_process().
@@ -213,10 +238,14 @@ static int pids_can_fork(struct task_struct *task)
 {
 	struct cgroup_subsys_state *css;
 	struct pids_cgroup *pids;
+	int err;
 
 	css = task_css_check(current, pids_cgrp_id, true);
 	pids = css_pids(css);
-	return pids_try_charge(pids, 1);
+	err = pids_try_charge(pids, 1);
+	if (err)
+		pids_fork_failed_event(pids);
+	return err;
 }
 
 static void pids_cancel_fork(struct task_struct *task)
@@ -263,6 +292,7 @@ set_limit:
 	 * critical that any racing fork()s follow the new limit.
 	 */
 	pids->limit = limit;
+	atomic_set(&pids->events_limit_logged, 0);
 	return nbytes;
 }
 
@@ -288,6 +318,14 @@ static s64 pids_current_read(struct cgroup_subsys_state *css,
 	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[] = {
 	{
 		.name = "max",
@@ -299,6 +337,12 @@ static struct cftype pids_files[] = {
 		.name = "current",
 		.read_s64 = pids_current_read,
 	},
+	{
+		.name = "events",
+		.seq_show = pids_events_show,
+		.file_offset = offsetof(struct pids_cgroup, events_file),
+		.flags = CFTYPE_NOT_ON_ROOT,
+	},
 	{ }	/* terminate */
 };
 
-- 
2.8.0.rc2

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH] cgroup: Add pids controller event when fork fails because of pid limit
@ 2016-06-21  3:09 ` Kenny Yu
  0 siblings, 0 replies; 18+ messages in thread
From: Kenny Yu @ 2016-06-21  3:09 UTC (permalink / raw)
  To: tj-DgEjT+Ai2ygdnm+yROfE0A, lizefan-hv44wF8Li93QT0dZR+AlfA,
	hannes-druUgvl0LCNAfugRpC6u6w, cyphar-gVpy/LI/lHzQT0dZR+AlfA
  Cc: kennyyu-b10kYP2dOMg, cgroups-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, kernel-team-b10kYP2dOMg

Summary:
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 adds an atomic boolean to prevent logging too much (e.g. a fork
bomb). The message is logged once per cgroup until the next time the pids limit
changes.

Signed-off-by: Kenny Yu <kennyyu-b10kYP2dOMg@public.gmane.org>
---
 kernel/cgroup_pids.c | 46 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 45 insertions(+), 1 deletion(-)

diff --git a/kernel/cgroup_pids.c b/kernel/cgroup_pids.c
index b93cbe3..8ba8c8f 100644
--- a/kernel/cgroup_pids.c
+++ b/kernel/cgroup_pids.c
@@ -49,6 +49,18 @@ struct pids_cgroup {
 	 */
 	atomic64_t			counter;
 	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;
+
+	/*
+	 * To avoid logging too much (e.g. during a fork bomb), log only once
+	 * per cgroup and reset this when the limit changes.
+	 */
+	atomic_t			events_limit_logged;
 };
 
 static struct pids_cgroup *css_pids(struct cgroup_subsys_state *css)
@@ -72,6 +84,8 @@ pids_css_alloc(struct cgroup_subsys_state *parent)
 
 	pids->limit = PIDS_MAX;
 	atomic64_set(&pids->counter, 0);
+	atomic64_set(&pids->events_limit, 0);
+	atomic_set(&pids->events_limit_logged, 0);
 	return &pids->css;
 }
 
@@ -205,6 +219,17 @@ static void pids_cancel_attach(struct cgroup_taskset *tset)
 	}
 }
 
+static void pids_fork_failed_event(struct pids_cgroup *pids)
+{
+	atomic64_inc(&pids->events_limit);
+	cgroup_file_notify(&pids->events_file);
+	if (!atomic_xchg(&pids->events_limit_logged, 1)) {
+		pr_info("cgroup: fork rejected by pids controller in ");
+		pr_cont_cgroup_path(task_cgroup(current, pids_cgrp_id));
+		pr_cont("\n");
+	}
+}
+
 /*
  * task_css_check(true) in pids_can_fork() and pids_cancel_fork() relies
  * on threadgroup_change_begin() held by the copy_process().
@@ -213,10 +238,14 @@ static int pids_can_fork(struct task_struct *task)
 {
 	struct cgroup_subsys_state *css;
 	struct pids_cgroup *pids;
+	int err;
 
 	css = task_css_check(current, pids_cgrp_id, true);
 	pids = css_pids(css);
-	return pids_try_charge(pids, 1);
+	err = pids_try_charge(pids, 1);
+	if (err)
+		pids_fork_failed_event(pids);
+	return err;
 }
 
 static void pids_cancel_fork(struct task_struct *task)
@@ -263,6 +292,7 @@ set_limit:
 	 * critical that any racing fork()s follow the new limit.
 	 */
 	pids->limit = limit;
+	atomic_set(&pids->events_limit_logged, 0);
 	return nbytes;
 }
 
@@ -288,6 +318,14 @@ static s64 pids_current_read(struct cgroup_subsys_state *css,
 	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[] = {
 	{
 		.name = "max",
@@ -299,6 +337,12 @@ static struct cftype pids_files[] = {
 		.name = "current",
 		.read_s64 = pids_current_read,
 	},
+	{
+		.name = "events",
+		.seq_show = pids_events_show,
+		.file_offset = offsetof(struct pids_cgroup, events_file),
+		.flags = CFTYPE_NOT_ON_ROOT,
+	},
 	{ }	/* terminate */
 };
 
-- 
2.8.0.rc2

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH] cgroup: Add pids controller event when fork fails because of pid limit
  2016-06-21  3:09 ` Kenny Yu
  (?)
@ 2016-06-21  4:44 ` Johannes Weiner
  2016-06-21 16:01     ` Kenny Yu
  -1 siblings, 1 reply; 18+ messages in thread
From: Johannes Weiner @ 2016-06-21  4:44 UTC (permalink / raw)
  To: Kenny Yu; +Cc: tj, lizefan, cyphar, cgroups, linux-kernel, kernel-team

On Mon, Jun 20, 2016 at 08:09:22PM -0700, Kenny Yu wrote:
> Summary:
> 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 adds an atomic boolean to prevent logging too much (e.g. a fork
> bomb). The message is logged once per cgroup until the next time the pids limit
> changes.
> 
> Signed-off-by: Kenny Yu <kennyyu@fb.com>

This makes sense to me. Hitting the cgroup PID limit right now is
somewhat ominous. A little more visibility would help.

Acked-by: Johannes Weiner <hannes@cmpxchg.org>

One comment below, but mostly a matter of preference:

> @@ -205,6 +219,17 @@ static void pids_cancel_attach(struct cgroup_taskset *tset)
>  	}
>  }
>  
> +static void pids_fork_failed_event(struct pids_cgroup *pids)
> +{
> +	atomic64_inc(&pids->events_limit);
> +	cgroup_file_notify(&pids->events_file);
> +	if (!atomic_xchg(&pids->events_limit_logged, 1)) {
> +		pr_info("cgroup: fork rejected by pids controller in ");
> +		pr_cont_cgroup_path(task_cgroup(current, pids_cgrp_id));
> +		pr_cont("\n");
> +	}
> +}
> +
>  /*
>   * task_css_check(true) in pids_can_fork() and pids_cancel_fork() relies
>   * on threadgroup_change_begin() held by the copy_process().
> @@ -213,10 +238,14 @@ static int pids_can_fork(struct task_struct *task)
>  {
>  	struct cgroup_subsys_state *css;
>  	struct pids_cgroup *pids;
> +	int err;
>  
>  	css = task_css_check(current, pids_cgrp_id, true);
>  	pids = css_pids(css);
> -	return pids_try_charge(pids, 1);
> +	err = pids_try_charge(pids, 1);
> +	if (err)
> +		pids_fork_failed_event(pids);

That function call/name seems somewhat clunky. Maybe it would be
better to inline its body directly into pids_try_charge() before
return -EAGAIN?

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v2] cgroup: Add pids controller event when fork fails because of pid limit
  2016-06-21  4:44 ` Johannes Weiner
@ 2016-06-21 16:01     ` Kenny Yu
  0 siblings, 0 replies; 18+ messages in thread
From: Kenny Yu @ 2016-06-21 16:01 UTC (permalink / raw)
  To: tj, lizefan, hannes, cyphar; +Cc: kennyyu, cgroups, linux-kernel, kernel-team

Summary:
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 adds an atomic boolean to prevent logging too much (e.g. a fork
bomb). The message is logged once per cgroup until the next time the pids limit
changes.

Signed-off-by: Kenny Yu <kennyyu@fb.com>
Acked-by: Johannes Weiner <hannes <at> cmpxchg.org>
---
 kernel/cgroup_pids.c | 42 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/kernel/cgroup_pids.c b/kernel/cgroup_pids.c
index b93cbe3..412f4d8 100644
--- a/kernel/cgroup_pids.c
+++ b/kernel/cgroup_pids.c
@@ -49,6 +49,18 @@ struct pids_cgroup {
 	 */
 	atomic64_t			counter;
 	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;
+
+	/*
+	 * To avoid logging too much (e.g. during a fork bomb), log only once
+	 * per cgroup and reset this when the limit changes.
+	 */
+	atomic_t			events_limit_logged;
 };
 
 static struct pids_cgroup *css_pids(struct cgroup_subsys_state *css)
@@ -72,6 +84,8 @@ pids_css_alloc(struct cgroup_subsys_state *parent)
 
 	pids->limit = PIDS_MAX;
 	atomic64_set(&pids->counter, 0);
+	atomic64_set(&pids->events_limit, 0);
+	atomic_set(&pids->events_limit_logged, 0);
 	return &pids->css;
 }
 
@@ -213,10 +227,21 @@ static int pids_can_fork(struct task_struct *task)
 {
 	struct cgroup_subsys_state *css;
 	struct pids_cgroup *pids;
+	int err;
 
 	css = task_css_check(current, pids_cgrp_id, true);
 	pids = css_pids(css);
-	return pids_try_charge(pids, 1);
+	err = pids_try_charge(pids, 1);
+	if (err) {
+		atomic64_inc(&pids->events_limit);
+		cgroup_file_notify(&pids->events_file);
+		if (!atomic_xchg(&pids->events_limit_logged, 1)) {
+			pr_info("cgroup: fork rejected by pids controller in ");
+			pr_cont_cgroup_path(task_cgroup(current, pids_cgrp_id));
+			pr_cont("\n");
+		}
+	}
+	return err;
 }
 
 static void pids_cancel_fork(struct task_struct *task)
@@ -263,6 +288,7 @@ set_limit:
 	 * critical that any racing fork()s follow the new limit.
 	 */
 	pids->limit = limit;
+	atomic_set(&pids->events_limit_logged, 0);
 	return nbytes;
 }
 
@@ -288,6 +314,14 @@ static s64 pids_current_read(struct cgroup_subsys_state *css,
 	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[] = {
 	{
 		.name = "max",
@@ -299,6 +333,12 @@ static struct cftype pids_files[] = {
 		.name = "current",
 		.read_s64 = pids_current_read,
 	},
+	{
+		.name = "events",
+		.seq_show = pids_events_show,
+		.file_offset = offsetof(struct pids_cgroup, events_file),
+		.flags = CFTYPE_NOT_ON_ROOT,
+	},
 	{ }	/* terminate */
 };
 
-- 
2.8.0.rc2

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v2] cgroup: Add pids controller event when fork fails because of pid limit
@ 2016-06-21 16:01     ` Kenny Yu
  0 siblings, 0 replies; 18+ messages in thread
From: Kenny Yu @ 2016-06-21 16:01 UTC (permalink / raw)
  To: tj, lizefan, hannes, cyphar; +Cc: kennyyu, cgroups, linux-kernel, kernel-team

Summary:
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 adds an atomic boolean to prevent logging too much (e.g. a fork
bomb). The message is logged once per cgroup until the next time the pids limit
changes.

Signed-off-by: Kenny Yu <kennyyu@fb.com>
Acked-by: Johannes Weiner <hannes <at> cmpxchg.org>
---
 kernel/cgroup_pids.c | 42 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/kernel/cgroup_pids.c b/kernel/cgroup_pids.c
index b93cbe3..412f4d8 100644
--- a/kernel/cgroup_pids.c
+++ b/kernel/cgroup_pids.c
@@ -49,6 +49,18 @@ struct pids_cgroup {
 	 */
 	atomic64_t			counter;
 	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;
+
+	/*
+	 * To avoid logging too much (e.g. during a fork bomb), log only once
+	 * per cgroup and reset this when the limit changes.
+	 */
+	atomic_t			events_limit_logged;
 };
 
 static struct pids_cgroup *css_pids(struct cgroup_subsys_state *css)
@@ -72,6 +84,8 @@ pids_css_alloc(struct cgroup_subsys_state *parent)
 
 	pids->limit = PIDS_MAX;
 	atomic64_set(&pids->counter, 0);
+	atomic64_set(&pids->events_limit, 0);
+	atomic_set(&pids->events_limit_logged, 0);
 	return &pids->css;
 }
 
@@ -213,10 +227,21 @@ static int pids_can_fork(struct task_struct *task)
 {
 	struct cgroup_subsys_state *css;
 	struct pids_cgroup *pids;
+	int err;
 
 	css = task_css_check(current, pids_cgrp_id, true);
 	pids = css_pids(css);
-	return pids_try_charge(pids, 1);
+	err = pids_try_charge(pids, 1);
+	if (err) {
+		atomic64_inc(&pids->events_limit);
+		cgroup_file_notify(&pids->events_file);
+		if (!atomic_xchg(&pids->events_limit_logged, 1)) {
+			pr_info("cgroup: fork rejected by pids controller in ");
+			pr_cont_cgroup_path(task_cgroup(current, pids_cgrp_id));
+			pr_cont("\n");
+		}
+	}
+	return err;
 }
 
 static void pids_cancel_fork(struct task_struct *task)
@@ -263,6 +288,7 @@ set_limit:
 	 * critical that any racing fork()s follow the new limit.
 	 */
 	pids->limit = limit;
+	atomic_set(&pids->events_limit_logged, 0);
 	return nbytes;
 }
 
@@ -288,6 +314,14 @@ static s64 pids_current_read(struct cgroup_subsys_state *css,
 	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[] = {
 	{
 		.name = "max",
@@ -299,6 +333,12 @@ static struct cftype pids_files[] = {
 		.name = "current",
 		.read_s64 = pids_current_read,
 	},
+	{
+		.name = "events",
+		.seq_show = pids_events_show,
+		.file_offset = offsetof(struct pids_cgroup, events_file),
+		.flags = CFTYPE_NOT_ON_ROOT,
+	},
 	{ }	/* terminate */
 };
 
-- 
2.8.0.rc2


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH v2] cgroup: Add pids controller event when fork fails because of pid limit
@ 2016-06-21 16:07       ` Aleksa Sarai
  0 siblings, 0 replies; 18+ messages in thread
From: Aleksa Sarai @ 2016-06-21 16:07 UTC (permalink / raw)
  To: Kenny Yu
  Cc: Tejun Heo, Li Zefan, Johannes Weiner, cgroups, linux-kernel, kernel-team

> @@ -213,10 +227,21 @@ static int pids_can_fork(struct task_struct *task)
>  {
>         struct cgroup_subsys_state *css;
>         struct pids_cgroup *pids;
> +       int err;
>
>         css = task_css_check(current, pids_cgrp_id, true);
>         pids = css_pids(css);
> -       return pids_try_charge(pids, 1);
> +       err = pids_try_charge(pids, 1);
> +       if (err) {
> +               atomic64_inc(&pids->events_limit);
> +               cgroup_file_notify(&pids->events_file);
> +               if (!atomic_xchg(&pids->events_limit_logged, 1)) {
> +                       pr_info("cgroup: fork rejected by pids controller in ");
> +                       pr_cont_cgroup_path(task_cgroup(current, pids_cgrp_id));
> +                       pr_cont("\n");
> +               }
> +       }
> +       return err;
>  }

Why are we logging this? Isn't the pids.events file enough
information? I feel like you could remove a lot of logic if you don't
log this.

And even if we do end up logging it, why have the boolean flag (the
counter always increases, just log if the counter is currently 0 and
you're incrementing it).

-- 
Aleksa Sarai (cyphar)
www.cyphar.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2] cgroup: Add pids controller event when fork fails because of pid limit
@ 2016-06-21 16:07       ` Aleksa Sarai
  0 siblings, 0 replies; 18+ messages in thread
From: Aleksa Sarai @ 2016-06-21 16:07 UTC (permalink / raw)
  To: Kenny Yu
  Cc: Tejun Heo, Li Zefan, Johannes Weiner,
	cgroups-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, kernel-team-b10kYP2dOMg

> @@ -213,10 +227,21 @@ static int pids_can_fork(struct task_struct *task)
>  {
>         struct cgroup_subsys_state *css;
>         struct pids_cgroup *pids;
> +       int err;
>
>         css = task_css_check(current, pids_cgrp_id, true);
>         pids = css_pids(css);
> -       return pids_try_charge(pids, 1);
> +       err = pids_try_charge(pids, 1);
> +       if (err) {
> +               atomic64_inc(&pids->events_limit);
> +               cgroup_file_notify(&pids->events_file);
> +               if (!atomic_xchg(&pids->events_limit_logged, 1)) {
> +                       pr_info("cgroup: fork rejected by pids controller in ");
> +                       pr_cont_cgroup_path(task_cgroup(current, pids_cgrp_id));
> +                       pr_cont("\n");
> +               }
> +       }
> +       return err;
>  }

Why are we logging this? Isn't the pids.events file enough
information? I feel like you could remove a lot of logic if you don't
log this.

And even if we do end up logging it, why have the boolean flag (the
counter always increases, just log if the counter is currently 0 and
you're incrementing it).

-- 
Aleksa Sarai (cyphar)
www.cyphar.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2] cgroup: Add pids controller event when fork fails because of pid limit
  2016-06-21 16:07       ` Aleksa Sarai
  (?)
@ 2016-06-21 16:34       ` Tejun Heo
  2016-06-21 16:56           ` Kenny Yu
  -1 siblings, 1 reply; 18+ messages in thread
From: Tejun Heo @ 2016-06-21 16:34 UTC (permalink / raw)
  To: Aleksa Sarai
  Cc: Kenny Yu, Li Zefan, Johannes Weiner, cgroups, linux-kernel, kernel-team

Hello,

On Wed, Jun 22, 2016 at 02:07:09AM +1000, Aleksa Sarai wrote:
> Why are we logging this? Isn't the pids.events file enough
> information? I feel like you could remove a lot of logic if you don't
> log this.

I think logging it is a good idea.  People aren't used to think about
the pids controller when fork fails and I've seen people getting
royally confused by it.  Also, if fork is being rejected on the right
(or wrong) cgroup, investigating why that's happening can be extremely
challenging (e.g. can't login).

> And even if we do end up logging it, why have the boolean flag (the
> counter always increases, just log if the counter is currently 0 and
> you're incrementing it).

Ah, that's true.  I like the fact that the warning message will be
printed after each change to the limit but yeah going off of zero
events_limit count should be fine too.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v3] cgroup: Add pids controller event when fork fails because of pid limit
@ 2016-06-21 16:56           ` Kenny Yu
  0 siblings, 0 replies; 18+ messages in thread
From: Kenny Yu @ 2016-06-21 16:56 UTC (permalink / raw)
  To: tj, lizefan, hannes, cyphar; +Cc: kennyyu, cgroups, linux-kernel, kernel-team

Summary:
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 adds an atomic boolean to prevent logging too much (e.g. a fork
bomb). The message is logged once per cgroup until the next time the pids limit
changes.

Signed-off-by: Kenny Yu <kennyyu@fb.com>
Acked-by: Johannes Weiner <hannes <at> cmpxchg.org>
---
 kernel/cgroup_pids.c | 36 +++++++++++++++++++++++++++++++++++-
 1 file changed, 35 insertions(+), 1 deletion(-)

diff --git a/kernel/cgroup_pids.c b/kernel/cgroup_pids.c
index b93cbe3..74cb0fe 100644
--- a/kernel/cgroup_pids.c
+++ b/kernel/cgroup_pids.c
@@ -49,6 +49,12 @@ struct pids_cgroup {
 	 */
 	atomic64_t			counter;
 	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)
@@ -72,6 +78,7 @@ pids_css_alloc(struct cgroup_subsys_state *parent)
 
 	pids->limit = PIDS_MAX;
 	atomic64_set(&pids->counter, 0);
+	atomic64_set(&pids->events_limit, 0);
 	return &pids->css;
 }
 
@@ -213,10 +220,23 @@ static int pids_can_fork(struct task_struct *task)
 {
 	struct cgroup_subsys_state *css;
 	struct pids_cgroup *pids;
+	int err;
+	int events_limit;
 
 	css = task_css_check(current, pids_cgrp_id, true);
 	pids = css_pids(css);
-	return pids_try_charge(pids, 1);
+	err = pids_try_charge(pids, 1);
+	if (err) {
+		events_limit = atomic64_inc_return(&pids->events_limit);
+		cgroup_file_notify(&pids->events_file);
+		/* Only log the first time events_limit is incremented. */
+		if (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");
+		}
+	}
+	return err;
 }
 
 static void pids_cancel_fork(struct task_struct *task)
@@ -288,6 +308,14 @@ static s64 pids_current_read(struct cgroup_subsys_state *css,
 	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[] = {
 	{
 		.name = "max",
@@ -299,6 +327,12 @@ static struct cftype pids_files[] = {
 		.name = "current",
 		.read_s64 = pids_current_read,
 	},
+	{
+		.name = "events",
+		.seq_show = pids_events_show,
+		.file_offset = offsetof(struct pids_cgroup, events_file),
+		.flags = CFTYPE_NOT_ON_ROOT,
+	},
 	{ }	/* terminate */
 };
 
-- 
2.8.0.rc2

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v3] cgroup: Add pids controller event when fork fails because of pid limit
@ 2016-06-21 16:56           ` Kenny Yu
  0 siblings, 0 replies; 18+ messages in thread
From: Kenny Yu @ 2016-06-21 16:56 UTC (permalink / raw)
  To: tj-DgEjT+Ai2ygdnm+yROfE0A, lizefan-hv44wF8Li93QT0dZR+AlfA,
	hannes-druUgvl0LCNAfugRpC6u6w, cyphar-gVpy/LI/lHzQT0dZR+AlfA
  Cc: kennyyu-b10kYP2dOMg, cgroups-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, kernel-team-b10kYP2dOMg

Summary:
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 adds an atomic boolean to prevent logging too much (e.g. a fork
bomb). The message is logged once per cgroup until the next time the pids limit
changes.

Signed-off-by: Kenny Yu <kennyyu-b10kYP2dOMg@public.gmane.org>
Acked-by: Johannes Weiner <hannes <at> cmpxchg.org>
---
 kernel/cgroup_pids.c | 36 +++++++++++++++++++++++++++++++++++-
 1 file changed, 35 insertions(+), 1 deletion(-)

diff --git a/kernel/cgroup_pids.c b/kernel/cgroup_pids.c
index b93cbe3..74cb0fe 100644
--- a/kernel/cgroup_pids.c
+++ b/kernel/cgroup_pids.c
@@ -49,6 +49,12 @@ struct pids_cgroup {
 	 */
 	atomic64_t			counter;
 	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)
@@ -72,6 +78,7 @@ pids_css_alloc(struct cgroup_subsys_state *parent)
 
 	pids->limit = PIDS_MAX;
 	atomic64_set(&pids->counter, 0);
+	atomic64_set(&pids->events_limit, 0);
 	return &pids->css;
 }
 
@@ -213,10 +220,23 @@ static int pids_can_fork(struct task_struct *task)
 {
 	struct cgroup_subsys_state *css;
 	struct pids_cgroup *pids;
+	int err;
+	int events_limit;
 
 	css = task_css_check(current, pids_cgrp_id, true);
 	pids = css_pids(css);
-	return pids_try_charge(pids, 1);
+	err = pids_try_charge(pids, 1);
+	if (err) {
+		events_limit = atomic64_inc_return(&pids->events_limit);
+		cgroup_file_notify(&pids->events_file);
+		/* Only log the first time events_limit is incremented. */
+		if (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");
+		}
+	}
+	return err;
 }
 
 static void pids_cancel_fork(struct task_struct *task)
@@ -288,6 +308,14 @@ static s64 pids_current_read(struct cgroup_subsys_state *css,
 	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[] = {
 	{
 		.name = "max",
@@ -299,6 +327,12 @@ static struct cftype pids_files[] = {
 		.name = "current",
 		.read_s64 = pids_current_read,
 	},
+	{
+		.name = "events",
+		.seq_show = pids_events_show,
+		.file_offset = offsetof(struct pids_cgroup, events_file),
+		.flags = CFTYPE_NOT_ON_ROOT,
+	},
 	{ }	/* terminate */
 };
 
-- 
2.8.0.rc2

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH v3] cgroup: Add pids controller event when fork fails because of pid limit
@ 2016-06-21 17:12             ` Tejun Heo
  0 siblings, 0 replies; 18+ messages in thread
From: Tejun Heo @ 2016-06-21 17:12 UTC (permalink / raw)
  To: Kenny Yu; +Cc: lizefan, hannes, cyphar, cgroups, linux-kernel, kernel-team

Hello,

Just a couple nits.

On Tue, Jun 21, 2016 at 09:56:38AM -0700, Kenny Yu wrote:
> Summary:

No need for "Summary:" tag.

> 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 adds an atomic boolean to prevent logging too much (e.g. a fork
> bomb). The message is logged once per cgroup until the next time the pids limit
> changes.

The above paragraph isn't uptodate anymore.

> @@ -213,10 +220,23 @@ static int pids_can_fork(struct task_struct *task)
>  {
>  	struct cgroup_subsys_state *css;
>  	struct pids_cgroup *pids;
> +	int err;
> +	int events_limit;
>  
>  	css = task_css_check(current, pids_cgrp_id, true);
>  	pids = css_pids(css);
> -	return pids_try_charge(pids, 1);
> +	err = pids_try_charge(pids, 1);
> +	if (err) {
> +		events_limit = atomic64_inc_return(&pids->events_limit);
> +		cgroup_file_notify(&pids->events_file);
> +		/* Only log the first time events_limit is incremented. */
> +		if (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");
> +		}
> +	}
> +	return err;
>  }

It'd be better to use atomic64_inc_and_test() instead.

	if (err) {
		if (atomic64_inc_and_test()) {
			pr_xxx...;
		}
		cgroup_file_notify(&pids->events_file);
	}

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3] cgroup: Add pids controller event when fork fails because of pid limit
@ 2016-06-21 17:12             ` Tejun Heo
  0 siblings, 0 replies; 18+ messages in thread
From: Tejun Heo @ 2016-06-21 17:12 UTC (permalink / raw)
  To: Kenny Yu
  Cc: lizefan-hv44wF8Li93QT0dZR+AlfA, hannes-druUgvl0LCNAfugRpC6u6w,
	cyphar-gVpy/LI/lHzQT0dZR+AlfA, cgroups-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, kernel-team-b10kYP2dOMg

Hello,

Just a couple nits.

On Tue, Jun 21, 2016 at 09:56:38AM -0700, Kenny Yu wrote:
> Summary:

No need for "Summary:" tag.

> 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 adds an atomic boolean to prevent logging too much (e.g. a fork
> bomb). The message is logged once per cgroup until the next time the pids limit
> changes.

The above paragraph isn't uptodate anymore.

> @@ -213,10 +220,23 @@ static int pids_can_fork(struct task_struct *task)
>  {
>  	struct cgroup_subsys_state *css;
>  	struct pids_cgroup *pids;
> +	int err;
> +	int events_limit;
>  
>  	css = task_css_check(current, pids_cgrp_id, true);
>  	pids = css_pids(css);
> -	return pids_try_charge(pids, 1);
> +	err = pids_try_charge(pids, 1);
> +	if (err) {
> +		events_limit = atomic64_inc_return(&pids->events_limit);
> +		cgroup_file_notify(&pids->events_file);
> +		/* Only log the first time events_limit is incremented. */
> +		if (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");
> +		}
> +	}
> +	return err;
>  }

It'd be better to use atomic64_inc_and_test() instead.

	if (err) {
		if (atomic64_inc_and_test()) {
			pr_xxx...;
		}
		cgroup_file_notify(&pids->events_file);
	}

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3] cgroup: Add pids controller event when fork fails because of pid limit
  2016-06-21 17:12             ` Tejun Heo
  (?)
@ 2016-06-21 17:23             ` Kenny Yu
  2016-06-21 17:28                 ` Tejun Heo
  -1 siblings, 1 reply; 18+ messages in thread
From: Kenny Yu @ 2016-06-21 17:23 UTC (permalink / raw)
  To: Tejun Heo; +Cc: lizefan, hannes, cyphar, cgroups, linux-kernel, Kernel Team

Thanks for the feedback Tejun!

On 6/21/16, 1:12 PM, "Tejun Heo" <htejun@gmail.com on behalf of tj@kernel.org> wrote:

>Hello,
>
>Just a couple nits.
>
>On Tue, Jun 21, 2016 at 09:56:38AM -0700, Kenny Yu wrote:
>> Summary:
>
>No need for "Summary:" tag.
>
>> 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 adds an atomic boolean to prevent logging too much (e.g. a fork
>> bomb). The message is logged once per cgroup until the next time the pids limit
>> changes.
>
>The above paragraph isn't uptodate anymore.

Thanks! Will change.

>
>> @@ -213,10 +220,23 @@ static int pids_can_fork(struct task_struct *task)
>>  {
>>  	struct cgroup_subsys_state *css;
>>  	struct pids_cgroup *pids;
>> +	int err;
>> +	int events_limit;
>>  
>>  	css = task_css_check(current, pids_cgrp_id, true);
>>  	pids = css_pids(css);
>> -	return pids_try_charge(pids, 1);
>> +	err = pids_try_charge(pids, 1);
>> +	if (err) {
>> +		events_limit = atomic64_inc_return(&pids->events_limit);
>> +		cgroup_file_notify(&pids->events_file);
>> +		/* Only log the first time events_limit is incremented. */
>> +		if (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");
>> +		}
>> +	}
>> +	return err;
>>  }
>
>It'd be better to use atomic64_inc_and_test() instead.
>
>	if (err) {
>		if (atomic64_inc_and_test()) {
>			pr_xxx...;
>		}
>		cgroup_file_notify(&pids->events_file);
>	}
>

According to the docs https://www.kernel.org/doc/Documentation/atomic_ops.txt ,
it looks like atomic_inc_and_test returns "a boolean indicating whether the resulting
counter value was zero or not", which will only happen when the counter goes from
negative to 0. I'll keep it as atomic_inc_return and get rid of the temp variable.

>Thanks.
>
>-- 
>tejun

Thanks,
Kenny

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3] cgroup: Add pids controller event when fork fails because of pid limit
@ 2016-06-21 17:28                 ` Tejun Heo
  0 siblings, 0 replies; 18+ messages in thread
From: Tejun Heo @ 2016-06-21 17:28 UTC (permalink / raw)
  To: Kenny Yu; +Cc: lizefan, hannes, cyphar, cgroups, linux-kernel, Kernel Team

Hello,

On Tue, Jun 21, 2016 at 05:23:40PM +0000, Kenny Yu wrote:
> >It'd be better to use atomic64_inc_and_test() instead.
> >
> >	if (err) {
> >		if (atomic64_inc_and_test()) {
> >			pr_xxx...;
> >		}
> >		cgroup_file_notify(&pids->events_file);
> >	}
> >
> 
> According to the docs https://www.kernel.org/doc/Documentation/atomic_ops.txt ,
> it looks like atomic_inc_and_test returns "a boolean indicating whether the resulting
> counter value was zero or not", which will only happen when the counter goes from
> negative to 0. I'll keep it as atomic_inc_return and get rid of the temp variable.

Right you're.  Sorry about the confusion.  Yeah, that sounds good to
me.

Thanks!

-- 
tejun

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3] cgroup: Add pids controller event when fork fails because of pid limit
@ 2016-06-21 17:28                 ` Tejun Heo
  0 siblings, 0 replies; 18+ messages in thread
From: Tejun Heo @ 2016-06-21 17:28 UTC (permalink / raw)
  To: Kenny Yu
  Cc: lizefan-hv44wF8Li93QT0dZR+AlfA, hannes-druUgvl0LCNAfugRpC6u6w,
	cyphar-gVpy/LI/lHzQT0dZR+AlfA, cgroups-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Kernel Team

Hello,

On Tue, Jun 21, 2016 at 05:23:40PM +0000, Kenny Yu wrote:
> >It'd be better to use atomic64_inc_and_test() instead.
> >
> >	if (err) {
> >		if (atomic64_inc_and_test()) {
> >			pr_xxx...;
> >		}
> >		cgroup_file_notify(&pids->events_file);
> >	}
> >
> 
> According to the docs https://www.kernel.org/doc/Documentation/atomic_ops.txt ,
> it looks like atomic_inc_and_test returns "a boolean indicating whether the resulting
> counter value was zero or not", which will only happen when the counter goes from
> negative to 0. I'll keep it as atomic_inc_return and get rid of the temp variable.

Right you're.  Sorry about the confusion.  Yeah, that sounds good to
me.

Thanks!

-- 
tejun

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v4] cgroup: Add pids controller event when fork fails because of pid limit
@ 2016-06-21 17:44                   ` Kenny Yu
  0 siblings, 0 replies; 18+ messages in thread
From: Kenny Yu @ 2016-06-21 17:44 UTC (permalink / raw)
  To: tj, lizefan, hannes, cyphar; +Cc: kennyyu, cgroups, linux-kernel, kernel-team

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>
---
 kernel/cgroup_pids.c | 34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/kernel/cgroup_pids.c b/kernel/cgroup_pids.c
index b93cbe3..bd2490b 100644
--- a/kernel/cgroup_pids.c
+++ b/kernel/cgroup_pids.c
@@ -49,6 +49,12 @@ struct pids_cgroup {
 	 */
 	atomic64_t			counter;
 	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)
@@ -72,6 +78,7 @@ pids_css_alloc(struct cgroup_subsys_state *parent)
 
 	pids->limit = PIDS_MAX;
 	atomic64_set(&pids->counter, 0);
+	atomic64_set(&pids->events_limit, 0);
 	return &pids->css;
 }
 
@@ -213,10 +220,21 @@ static int pids_can_fork(struct task_struct *task)
 {
 	struct cgroup_subsys_state *css;
 	struct pids_cgroup *pids;
+	int err;
 
 	css = task_css_check(current, pids_cgrp_id, true);
 	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)
@@ -288,6 +306,14 @@ static s64 pids_current_read(struct cgroup_subsys_state *css,
 	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[] = {
 	{
 		.name = "max",
@@ -299,6 +325,12 @@ static struct cftype pids_files[] = {
 		.name = "current",
 		.read_s64 = pids_current_read,
 	},
+	{
+		.name = "events",
+		.seq_show = pids_events_show,
+		.file_offset = offsetof(struct pids_cgroup, events_file),
+		.flags = CFTYPE_NOT_ON_ROOT,
+	},
 	{ }	/* terminate */
 };
 
-- 
2.8.0.rc2

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4] cgroup: Add pids controller event when fork fails because of pid limit
@ 2016-06-21 17:44                   ` Kenny Yu
  0 siblings, 0 replies; 18+ messages in thread
From: Kenny Yu @ 2016-06-21 17:44 UTC (permalink / raw)
  To: tj-DgEjT+Ai2ygdnm+yROfE0A, lizefan-hv44wF8Li93QT0dZR+AlfA,
	hannes-druUgvl0LCNAfugRpC6u6w, cyphar-gVpy/LI/lHzQT0dZR+AlfA
  Cc: kennyyu-b10kYP2dOMg, cgroups-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, kernel-team-b10kYP2dOMg

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-b10kYP2dOMg@public.gmane.org>
Acked-by: Johannes Weiner <hannes <at> cmpxchg.org>
---
 kernel/cgroup_pids.c | 34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/kernel/cgroup_pids.c b/kernel/cgroup_pids.c
index b93cbe3..bd2490b 100644
--- a/kernel/cgroup_pids.c
+++ b/kernel/cgroup_pids.c
@@ -49,6 +49,12 @@ struct pids_cgroup {
 	 */
 	atomic64_t			counter;
 	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)
@@ -72,6 +78,7 @@ pids_css_alloc(struct cgroup_subsys_state *parent)
 
 	pids->limit = PIDS_MAX;
 	atomic64_set(&pids->counter, 0);
+	atomic64_set(&pids->events_limit, 0);
 	return &pids->css;
 }
 
@@ -213,10 +220,21 @@ static int pids_can_fork(struct task_struct *task)
 {
 	struct cgroup_subsys_state *css;
 	struct pids_cgroup *pids;
+	int err;
 
 	css = task_css_check(current, pids_cgrp_id, true);
 	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)
@@ -288,6 +306,14 @@ static s64 pids_current_read(struct cgroup_subsys_state *css,
 	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[] = {
 	{
 		.name = "max",
@@ -299,6 +325,12 @@ static struct cftype pids_files[] = {
 		.name = "current",
 		.read_s64 = pids_current_read,
 	},
+	{
+		.name = "events",
+		.seq_show = pids_events_show,
+		.file_offset = offsetof(struct pids_cgroup, events_file),
+		.flags = CFTYPE_NOT_ON_ROOT,
+	},
 	{ }	/* terminate */
 };
 
-- 
2.8.0.rc2

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH v4] cgroup: Add pids controller event when fork fails because of pid limit
  2016-06-21 17:44                   ` Kenny Yu
  (?)
@ 2016-06-21 18:06                   ` Tejun Heo
  -1 siblings, 0 replies; 18+ messages in thread
From: Tejun Heo @ 2016-06-21 18:06 UTC (permalink / raw)
  To: Kenny Yu; +Cc: lizefan, hannes, cyphar, cgroups, linux-kernel, kernel-team

On Tue, Jun 21, 2016 at 10:44:50AM -0700, Kenny Yu wrote:
> 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>

Applied to cgroup/for-4.8.  Thanks!

-- 
tejun

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2016-06-21 18:33 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-21  3:09 [PATCH] cgroup: Add pids controller event when fork fails because of pid limit Kenny Yu
2016-06-21  3:09 ` Kenny Yu
2016-06-21  4:44 ` Johannes Weiner
2016-06-21 16:01   ` [PATCH v2] " Kenny Yu
2016-06-21 16:01     ` Kenny Yu
2016-06-21 16:07     ` Aleksa Sarai
2016-06-21 16:07       ` Aleksa Sarai
2016-06-21 16:34       ` Tejun Heo
2016-06-21 16:56         ` [PATCH v3] " Kenny Yu
2016-06-21 16:56           ` Kenny Yu
2016-06-21 17:12           ` Tejun Heo
2016-06-21 17:12             ` Tejun Heo
2016-06-21 17:23             ` Kenny Yu
2016-06-21 17:28               ` Tejun Heo
2016-06-21 17:28                 ` Tejun Heo
2016-06-21 17:44                 ` [PATCH v4] " Kenny Yu
2016-06-21 17:44                   ` Kenny Yu
2016-06-21 18:06                   ` Tejun Heo

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.