diff options
Diffstat (limited to 'kernel/exit.c')
| -rw-r--r-- | kernel/exit.c | 53 |
1 files changed, 20 insertions, 33 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index ad933bb29ec7..6cdf60712bd2 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
| @@ -46,6 +46,7 @@ | |||
| 46 | #include <linux/resource.h> | 46 | #include <linux/resource.h> |
| 47 | #include <linux/blkdev.h> | 47 | #include <linux/blkdev.h> |
| 48 | #include <linux/task_io_accounting_ops.h> | 48 | #include <linux/task_io_accounting_ops.h> |
| 49 | #include <linux/tracehook.h> | ||
| 49 | 50 | ||
| 50 | #include <asm/uaccess.h> | 51 | #include <asm/uaccess.h> |
| 51 | #include <asm/unistd.h> | 52 | #include <asm/unistd.h> |
| @@ -162,27 +163,17 @@ static void delayed_put_task_struct(struct rcu_head *rhp) | |||
| 162 | put_task_struct(container_of(rhp, struct task_struct, rcu)); | 163 | put_task_struct(container_of(rhp, struct task_struct, rcu)); |
| 163 | } | 164 | } |
| 164 | 165 | ||
| 165 | /* | ||
| 166 | * Do final ptrace-related cleanup of a zombie being reaped. | ||
| 167 | * | ||
| 168 | * Called with write_lock(&tasklist_lock) held. | ||
| 169 | */ | ||
| 170 | static void ptrace_release_task(struct task_struct *p) | ||
| 171 | { | ||
| 172 | BUG_ON(!list_empty(&p->ptraced)); | ||
| 173 | ptrace_unlink(p); | ||
| 174 | BUG_ON(!list_empty(&p->ptrace_entry)); | ||
| 175 | } | ||
| 176 | 166 | ||
| 177 | void release_task(struct task_struct * p) | 167 | void release_task(struct task_struct * p) |
| 178 | { | 168 | { |
| 179 | struct task_struct *leader; | 169 | struct task_struct *leader; |
| 180 | int zap_leader; | 170 | int zap_leader; |
| 181 | repeat: | 171 | repeat: |
| 172 | tracehook_prepare_release_task(p); | ||
| 182 | atomic_dec(&p->user->processes); | 173 | atomic_dec(&p->user->processes); |
| 183 | proc_flush_task(p); | 174 | proc_flush_task(p); |
| 184 | write_lock_irq(&tasklist_lock); | 175 | write_lock_irq(&tasklist_lock); |
| 185 | ptrace_release_task(p); | 176 | tracehook_finish_release_task(p); |
| 186 | __exit_signal(p); | 177 | __exit_signal(p); |
| 187 | 178 | ||
| 188 | /* | 179 | /* |
| @@ -204,6 +195,13 @@ repeat: | |||
| 204 | * that case. | 195 | * that case. |
| 205 | */ | 196 | */ |
| 206 | zap_leader = task_detached(leader); | 197 | zap_leader = task_detached(leader); |
| 198 | |||
| 199 | /* | ||
| 200 | * This maintains the invariant that release_task() | ||
| 201 | * only runs on a task in EXIT_DEAD, just for sanity. | ||
| 202 | */ | ||
| 203 | if (zap_leader) | ||
| 204 | leader->exit_state = EXIT_DEAD; | ||
| 207 | } | 205 | } |
| 208 | 206 | ||
| 209 | write_unlock_irq(&tasklist_lock); | 207 | write_unlock_irq(&tasklist_lock); |
| @@ -887,7 +885,8 @@ static void forget_original_parent(struct task_struct *father) | |||
| 887 | */ | 885 | */ |
| 888 | static void exit_notify(struct task_struct *tsk, int group_dead) | 886 | static void exit_notify(struct task_struct *tsk, int group_dead) |
| 889 | { | 887 | { |
| 890 | int state; | 888 | int signal; |
| 889 | void *cookie; | ||
| 891 | 890 | ||
| 892 | /* | 891 | /* |
| 893 | * This does two things: | 892 | * This does two things: |
| @@ -924,22 +923,11 @@ static void exit_notify(struct task_struct *tsk, int group_dead) | |||
| 924 | !capable(CAP_KILL)) | 923 | !capable(CAP_KILL)) |
| 925 | tsk->exit_signal = SIGCHLD; | 924 | tsk->exit_signal = SIGCHLD; |
| 926 | 925 | ||
| 927 | /* If something other than our normal parent is ptracing us, then | 926 | signal = tracehook_notify_death(tsk, &cookie, group_dead); |
| 928 | * send it a SIGCHLD instead of honoring exit_signal. exit_signal | 927 | if (signal > 0) |
| 929 | * only has special meaning to our real parent. | 928 | signal = do_notify_parent(tsk, signal); |
| 930 | */ | ||
| 931 | if (!task_detached(tsk) && thread_group_empty(tsk)) { | ||
| 932 | int signal = ptrace_reparented(tsk) ? | ||
| 933 | SIGCHLD : tsk->exit_signal; | ||
| 934 | do_notify_parent(tsk, signal); | ||
| 935 | } else if (tsk->ptrace) { | ||
| 936 | do_notify_parent(tsk, SIGCHLD); | ||
| 937 | } | ||
| 938 | 929 | ||
| 939 | state = EXIT_ZOMBIE; | 930 | tsk->exit_state = signal < 0 ? EXIT_DEAD : EXIT_ZOMBIE; |
| 940 | if (task_detached(tsk) && likely(!tsk->ptrace)) | ||
| 941 | state = EXIT_DEAD; | ||
| 942 | tsk->exit_state = state; | ||
| 943 | 931 | ||
| 944 | /* mt-exec, de_thread() is waiting for us */ | 932 | /* mt-exec, de_thread() is waiting for us */ |
| 945 | if (thread_group_leader(tsk) && | 933 | if (thread_group_leader(tsk) && |
| @@ -949,8 +937,10 @@ static void exit_notify(struct task_struct *tsk, int group_dead) | |||
| 949 | 937 | ||
| 950 | write_unlock_irq(&tasklist_lock); | 938 | write_unlock_irq(&tasklist_lock); |
| 951 | 939 | ||
| 940 | tracehook_report_death(tsk, signal, cookie, group_dead); | ||
| 941 | |||
| 952 | /* If the process is dead, release it - nobody will wait for it */ | 942 | /* If the process is dead, release it - nobody will wait for it */ |
| 953 | if (state == EXIT_DEAD) | 943 | if (signal < 0) |
| 954 | release_task(tsk); | 944 | release_task(tsk); |
| 955 | } | 945 | } |
| 956 | 946 | ||
| @@ -1029,10 +1019,7 @@ NORET_TYPE void do_exit(long code) | |||
| 1029 | if (unlikely(!tsk->pid)) | 1019 | if (unlikely(!tsk->pid)) |
| 1030 | panic("Attempted to kill the idle task!"); | 1020 | panic("Attempted to kill the idle task!"); |
| 1031 | 1021 | ||
| 1032 | if (unlikely(current->ptrace & PT_TRACE_EXIT)) { | 1022 | tracehook_report_exit(&code); |
| 1033 | current->ptrace_message = code; | ||
| 1034 | ptrace_notify((PTRACE_EVENT_EXIT << 8) | SIGTRAP); | ||
| 1035 | } | ||
| 1036 | 1023 | ||
| 1037 | /* | 1024 | /* |
| 1038 | * We're taking recursive faults here in do_exit. Safest is to just | 1025 | * We're taking recursive faults here in do_exit. Safest is to just |
