cgroup: add cgroup_subsys->free() method and use it to fix pids controller
authorTejun Heo <tj@kernel.org>
Thu, 15 Oct 2015 20:41:53 +0000 (16:41 -0400)
committerTejun Heo <tj@kernel.org>
Thu, 15 Oct 2015 20:41:53 +0000 (16:41 -0400)
pids controller is completely broken in that it uncharges when a task
exits allowing zombies to escape resource control.  With the recent
updates, cgroup core now maintains cgroup association till task free
and pids controller can be fixed by uncharging on free instead of
exit.

This patch adds cgroup_subsys->free() method and update pids
controller to use it instead of ->exit() for uncharging.

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Aleksa Sarai <cyphar@cyphar.com>
Documentation/cgroups/cgroups.txt
include/linux/cgroup-defs.h
kernel/cgroup.c
kernel/cgroup_pids.c

index f935fac1e73b9e18981b8b0ff2a69ba534b5e34d..c6256ae9885b8ac7445f6d10066ee541ebb388b8 100644 (file)
@@ -637,6 +637,10 @@ void exit(struct task_struct *task)
 
 Called during task exit.
 
+void free(struct task_struct *task)
+
+Called when the task_struct is freed.
+
 void bind(struct cgroup *root)
 (cgroup_mutex held by caller)
 
index 6a1ab64ee5f91d53495739ecd0a4f9ec50b43565..60d44b26276d84a77d7f7e3379ae12821a8b3eeb 100644 (file)
@@ -436,6 +436,7 @@ struct cgroup_subsys {
        void (*cancel_fork)(struct task_struct *task, void *priv);
        void (*fork)(struct task_struct *task, void *priv);
        void (*exit)(struct task_struct *task);
+       void (*free)(struct task_struct *task);
        void (*bind)(struct cgroup_subsys_state *root_css);
 
        int early_init;
index 918658497625389c21691357c83ec284622e783d..8673843696693b0f2e3649f6b94aaf5dc3acc561 100644 (file)
@@ -206,6 +206,7 @@ static u64 css_serial_nr_next = 1;
  */
 static unsigned long have_fork_callback __read_mostly;
 static unsigned long have_exit_callback __read_mostly;
+static unsigned long have_free_callback __read_mostly;
 
 /* Ditto for the can_fork callback. */
 static unsigned long have_canfork_callback __read_mostly;
@@ -5180,6 +5181,7 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss, bool early)
 
        have_fork_callback |= (bool)ss->fork << ss->id;
        have_exit_callback |= (bool)ss->exit << ss->id;
+       have_free_callback |= (bool)ss->free << ss->id;
        have_canfork_callback |= (bool)ss->can_fork << ss->id;
 
        /* At system boot, before all subsystems have been
@@ -5637,6 +5639,11 @@ void cgroup_exit(struct task_struct *tsk)
 void cgroup_free(struct task_struct *task)
 {
        struct css_set *cset = task_css_set(task);
+       struct cgroup_subsys *ss;
+       int ssid;
+
+       for_each_subsys_which(ss, ssid, &have_free_callback)
+               ss->free(task);
 
        put_css_set(cset);
 }
index 45f0856a61fe784d025a671d4f0b6705fa54c327..cdd8df4e991c7781ac5996677d724bcd23314623 100644 (file)
@@ -266,7 +266,7 @@ static void pids_fork(struct task_struct *task, void *priv)
        css_put(old_css);
 }
 
-static void pids_exit(struct task_struct *task)
+static void pids_free(struct task_struct *task)
 {
        struct pids_cgroup *pids = css_pids(task_css(task, pids_cgrp_id));
 
@@ -347,7 +347,7 @@ struct cgroup_subsys pids_cgrp_subsys = {
        .can_fork       = pids_can_fork,
        .cancel_fork    = pids_cancel_fork,
        .fork           = pids_fork,
-       .exit           = pids_exit,
+       .free           = pids_free,
        .legacy_cftypes = pids_files,
        .dfl_cftypes    = pids_files,
 };