| From b2b2cbc4b2a2f389442549399a993a8306420baf Mon Sep 17 00:00:00 2001 |
| From: Eric W. Biederman <ebiederm@xmission.com> |
| Date: Thu, 21 Dec 2006 21:28:40 -0700 |
| Subject: [PATCH] Fix reparenting to the same thread group. (take 2) |
| |
| This patch fixes the case when we reparent to a different thread in the |
| same thread group. This modifies the code so that we do not send |
| signals and do not change the signal to send to SIGCHLD unless we have |
| change the thread group of our parents. It also suppresses sending |
| pdeath_sig in this cas as well since the result of geppid doesn't |
| change. |
| |
| Thanks to Oleg for spotting my bug of only fixing this for non-ptraced |
| tasks. |
| |
| This fixes the issues identified by Albert Cahalan in thread |
| http://lkml.org/lkml/2006/12/21/22. |
| |
| Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> |
| Acked-by: Mike Galbraith <efault@gmx.de> |
| Cc: Albert Cahalan <acahalan@gmail.com> |
| Cc: Andrew Morton <akpm@osdl.org> |
| Cc: Roland McGrath <roland@redhat.com> |
| Cc: Ingo Molnar <mingo@elte.hu> |
| Cc: Coywolf Qi Hunt <qiyong@fc-cn.com> |
| Acked-by: Oleg Nesterov <oleg@tv-sign.ru> |
| Signed-off-by: Linus Torvalds <torvalds@osdl.org> |
| [chrisw: fold in 241ceee0b442, Oleg's fix to restore user visible behaviour] |
| Signed-off-by: Chris Wright <chrisw@sous-sol.org> |
| --- |
| kernel/exit.c | 29 ++++++++++++++++++----------- |
| 1 file changed, 18 insertions(+), 11 deletions(-) |
| |
| --- linux-2.6.19.2.orig/kernel/exit.c |
| +++ linux-2.6.19.2/kernel/exit.c |
| @@ -603,10 +603,6 @@ choose_new_parent(struct task_struct *p, |
| static void |
| reparent_thread(struct task_struct *p, struct task_struct *father, int traced) |
| { |
| - /* We don't want people slaying init. */ |
| - if (p->exit_signal != -1) |
| - p->exit_signal = SIGCHLD; |
| - |
| if (p->pdeath_signal) |
| /* We already hold the tasklist_lock here. */ |
| group_send_sig_info(p->pdeath_signal, SEND_SIG_NOINFO, p); |
| @@ -626,13 +622,7 @@ reparent_thread(struct task_struct *p, s |
| p->parent = p->real_parent; |
| add_parent(p); |
| |
| - /* If we'd notified the old parent about this child's death, |
| - * also notify the new parent. |
| - */ |
| - if (p->exit_state == EXIT_ZOMBIE && p->exit_signal != -1 && |
| - thread_group_empty(p)) |
| - do_notify_parent(p, p->exit_signal); |
| - else if (p->state == TASK_TRACED) { |
| + if (p->state == TASK_TRACED) { |
| /* |
| * If it was at a trace stop, turn it into |
| * a normal stop since it's no longer being |
| @@ -642,6 +632,23 @@ reparent_thread(struct task_struct *p, s |
| } |
| } |
| |
| + /* If this is a threaded reparent there is no need to |
| + * notify anyone anything has happened. |
| + */ |
| + if (p->real_parent->group_leader == father->group_leader) |
| + return; |
| + |
| + /* We don't want people slaying init. */ |
| + if (p->exit_signal != -1) |
| + p->exit_signal = SIGCHLD; |
| + |
| + /* If we'd notified the old parent about this child's death, |
| + * also notify the new parent. |
| + */ |
| + if (!traced && p->exit_state == EXIT_ZOMBIE && |
| + p->exit_signal != -1 && thread_group_empty(p)) |
| + do_notify_parent(p, p->exit_signal); |
| + |
| /* |
| * process group orphan check |
| * Case ii: Our child is in a different pgrp |