coredump: set ->group_exit_code for other CLONE_VM tasks too
authorOleg Nesterov <oleg@redhat.com>
Fri, 5 Mar 2010 21:44:14 +0000 (13:44 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 6 Mar 2010 19:26:46 +0000 (11:26 -0800)
User visible change.

do_coredump() kills all threads which share the same ->mm but only the
coredumping process gets the proper exit_code.  Other tasks which share
the same ->mm die "silently" and return status == 0 to parent.

This is historical behaviour, not actually a bug.  But I think Frank
Heckenbach rightly dislikes the current behaviour.  Simple test-case:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

int main(void)
{
int stat;

if (!fork()) {
if (!vfork())
kill(getpid(), SIGQUIT);
}

wait(&stat);
printf("stat=%x\n", stat);
return 0;
}

Before this patch it prints "stat=0" despite the fact the child was killed
by SIGQUIT.  After this patch the output is "stat=3" which obviously makes
more sense.

Even with this patch, only the task which originates the coredumping gets
"|= 0x80" if the core was actually dumped, but at least the coredumping
signal is visible to do_wait/etc.

Reported-by: Frank Heckenbach <f.heckenbach@fh-soft.de>
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Acked-by: WANG Cong <xiyou.wangcong@gmail.com>
Cc: Roland McGrath <roland@redhat.com>
Cc: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
fs/exec.c

index 89d4080..829a6c6 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1561,12 +1561,13 @@ out:
        return ispipe;
 }
 
-static int zap_process(struct task_struct *start)
+static int zap_process(struct task_struct *start, int exit_code)
 {
        struct task_struct *t;
        int nr = 0;
 
        start->signal->flags = SIGNAL_GROUP_EXIT;
+       start->signal->group_exit_code = exit_code;
        start->signal->group_stop_count = 0;
 
        t = start;
@@ -1591,8 +1592,7 @@ static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
        spin_lock_irq(&tsk->sighand->siglock);
        if (!signal_group_exit(tsk->signal)) {
                mm->core_state = core_state;
-               tsk->signal->group_exit_code = exit_code;
-               nr = zap_process(tsk);
+               nr = zap_process(tsk, exit_code);
        }
        spin_unlock_irq(&tsk->sighand->siglock);
        if (unlikely(nr < 0))
@@ -1641,7 +1641,7 @@ static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
                        if (p->mm) {
                                if (unlikely(p->mm == mm)) {
                                        lock_task_sighand(p, &flags);
-                                       nr += zap_process(p);
+                                       nr += zap_process(p, exit_code);
                                        unlock_task_sighand(p, &flags);
                                }
                                break;