[PATCH 1/2] cgroups: use sighand lock instead of tasklist_lock incgroup_attach_proc

From: Ben Blum
Date: Thu Oct 13 2011 - 20:34:50 EST


Use sighand lock instead of tasklist_lock in cgroup_attach_proc.

From: Ben Blum <bblum@xxxxxxxxxxxxxx>

Signed-off-by: Ben Blum <bblum@xxxxxxxxxxxxxx>
---
kernel/cgroup.c | 27 +++++++++++++--------------
1 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 893fc3d..32fb4c8 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -2003,6 +2003,7 @@ int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
/* threadgroup list cursor and array */
struct task_struct *tsk;
struct flex_array *group;
+ unsigned long flags;
/*
* we need to make sure we have css_sets for all the tasks we're
* going to move -before- we actually start moving them, so that in
@@ -2029,20 +2030,18 @@ int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
if (retval)
goto out_free_group_list;

- /* prevent changes to the threadgroup list while we take a snapshot. */
- read_lock(&tasklist_lock);
- if (!thread_group_leader(leader)) {
- /*
- * a race with de_thread from another thread's exec() may strip
- * us of our leadership, making while_each_thread unsafe to use
- * on this task. if this happens, there is no choice but to
- * throw this task away and try again (from cgroup_procs_write);
- * this is "double-double-toil-and-trouble-check locking".
- */
- read_unlock(&tasklist_lock);
- retval = -EAGAIN;
+ /* prevent changes to the threadgroup list while we take a snapshot.
+ * If the leader exits, its links on the thread_group list become
+ * invalid. One way this can happen is if a sub-thread does exec() when
+ * de_thread() calls release_task(leader) (and leader->sighand gets set
+ * to NULL, in which case lock_task_sighand will fail). Since in that
+ * case the threadgroup is still around, cgroup_procs_write should try
+ * again (finding the new leader), which EAGAIN indicates here. This is
+ * double-double-toil-and-trouble-check locking". */
+ retval = -EAGAIN;
+ if (!lock_task_sighand(leader, &flags))
goto out_free_group_list;
- }
+
/* take a reference on each task in the group to go in the array. */
tsk = leader;
i = 0;
@@ -2058,9 +2057,9 @@ int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
BUG_ON(retval != 0);
i++;
} while_each_thread(leader, tsk);
+ unlock_task_sighand(leader, &flags);
/* remember the number of threads in the array for later. */
group_size = i;
- read_unlock(&tasklist_lock);

/*
* step 1: check that we can legitimately attach to the cgroup.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/