Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit de12a787 authored by Eric W. Biederman's avatar Eric W. Biederman Committed by Linus Torvalds
Browse files

[PATCH] de_thread: Don't confuse users do_each_thread.



Oleg Nesterov spotted two interesting bugs with the current de_thread
code.  The simplest is a long standing double decrement of
__get_cpu_var(process_counts) in __unhash_process.  Caused by
two processes exiting when only one was created.

The other is that since we no longer detach from the thread_group list
it is possible for do_each_thread when run under the tasklist_lock to
see the same task_struct twice.  Once on the task list as a
thread_group_leader, and once on the thread list of another
thread.

The double appearance in do_each_thread can cause a double increment
of mm_core_waiters in zap_threads resulting in problems later on in
coredump_wait.

To remedy those two problems this patch takes the simple approach
of changing the old thread group leader into a child thread.
The only routine in release_task that cares is __unhash_process,
and it can be trivially seen that we handle cleaning up a
thread group leader properly.

Since de_thread doesn't change the pid of the exiting leader process
and instead shares it with the new leader process.  I change
thread_group_leader to recognize group leadership based on the
group_leader field and not based on pids.  This should also be
slightly cheaper then the existing thread_group_leader macro.

I performed a quick audit and I couldn't see any user of
thread_group_leader that cared about the difference.

Signed-off-by: default avatarEric W. Biederman <ebiederm@xmission.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 1b723734
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -723,7 +723,12 @@ static int de_thread(struct task_struct *tsk)
		current->parent = current->real_parent = leader->real_parent;
		leader->parent = leader->real_parent = child_reaper;
		current->group_leader = current;
		leader->group_leader = leader;
		leader->group_leader = current;

		/* Reduce leader to a thread */
		detach_pid(leader, PIDTYPE_PGID);
		detach_pid(leader, PIDTYPE_SID);
		list_del_init(&leader->tasks);

		add_parent(current);
		add_parent(leader);
+2 −1
Original line number Diff line number Diff line
@@ -1203,7 +1203,8 @@ extern void wait_task_inactive(task_t * p);
#define while_each_thread(g, t) \
	while ((t = next_thread(t)) != g)

#define thread_group_leader(p)	(p->pid == p->tgid)
/* de_thread depends on thread_group_leader not being a pid based check */
#define thread_group_leader(p)	(p == p->group_leader)

static inline task_t *next_thread(task_t *p)
{