diff options
Diffstat (limited to 'kernel/exit.c')
-rw-r--r-- | kernel/exit.c | 43 |
1 files changed, 17 insertions, 26 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 7f2683a10ac4..ceffc67b564a 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -55,15 +55,14 @@ | |||
55 | #include <asm/unistd.h> | 55 | #include <asm/unistd.h> |
56 | #include <asm/pgtable.h> | 56 | #include <asm/pgtable.h> |
57 | #include <asm/mmu_context.h> | 57 | #include <asm/mmu_context.h> |
58 | #include "cred-internals.h" | ||
59 | 58 | ||
60 | static void exit_mm(struct task_struct * tsk); | 59 | static void exit_mm(struct task_struct * tsk); |
61 | 60 | ||
62 | static void __unhash_process(struct task_struct *p) | 61 | static void __unhash_process(struct task_struct *p, bool group_dead) |
63 | { | 62 | { |
64 | nr_threads--; | 63 | nr_threads--; |
65 | detach_pid(p, PIDTYPE_PID); | 64 | detach_pid(p, PIDTYPE_PID); |
66 | if (thread_group_leader(p)) { | 65 | if (group_dead) { |
67 | detach_pid(p, PIDTYPE_PGID); | 66 | detach_pid(p, PIDTYPE_PGID); |
68 | detach_pid(p, PIDTYPE_SID); | 67 | detach_pid(p, PIDTYPE_SID); |
69 | 68 | ||
@@ -80,10 +79,9 @@ static void __unhash_process(struct task_struct *p) | |||
80 | static void __exit_signal(struct task_struct *tsk) | 79 | static void __exit_signal(struct task_struct *tsk) |
81 | { | 80 | { |
82 | struct signal_struct *sig = tsk->signal; | 81 | struct signal_struct *sig = tsk->signal; |
82 | bool group_dead = thread_group_leader(tsk); | ||
83 | struct sighand_struct *sighand; | 83 | struct sighand_struct *sighand; |
84 | 84 | struct tty_struct *uninitialized_var(tty); | |
85 | BUG_ON(!sig); | ||
86 | BUG_ON(!atomic_read(&sig->count)); | ||
87 | 85 | ||
88 | sighand = rcu_dereference_check(tsk->sighand, | 86 | sighand = rcu_dereference_check(tsk->sighand, |
89 | rcu_read_lock_held() || | 87 | rcu_read_lock_held() || |
@@ -91,14 +89,16 @@ static void __exit_signal(struct task_struct *tsk) | |||
91 | spin_lock(&sighand->siglock); | 89 | spin_lock(&sighand->siglock); |
92 | 90 | ||
93 | posix_cpu_timers_exit(tsk); | 91 | posix_cpu_timers_exit(tsk); |
94 | if (atomic_dec_and_test(&sig->count)) | 92 | if (group_dead) { |
95 | posix_cpu_timers_exit_group(tsk); | 93 | posix_cpu_timers_exit_group(tsk); |
96 | else { | 94 | tty = sig->tty; |
95 | sig->tty = NULL; | ||
96 | } else { | ||
97 | /* | 97 | /* |
98 | * If there is any task waiting for the group exit | 98 | * If there is any task waiting for the group exit |
99 | * then notify it: | 99 | * then notify it: |
100 | */ | 100 | */ |
101 | if (sig->group_exit_task && atomic_read(&sig->count) == sig->notify_count) | 101 | if (sig->notify_count > 0 && !--sig->notify_count) |
102 | wake_up_process(sig->group_exit_task); | 102 | wake_up_process(sig->group_exit_task); |
103 | 103 | ||
104 | if (tsk == sig->curr_target) | 104 | if (tsk == sig->curr_target) |
@@ -124,32 +124,24 @@ static void __exit_signal(struct task_struct *tsk) | |||
124 | sig->oublock += task_io_get_oublock(tsk); | 124 | sig->oublock += task_io_get_oublock(tsk); |
125 | task_io_accounting_add(&sig->ioac, &tsk->ioac); | 125 | task_io_accounting_add(&sig->ioac, &tsk->ioac); |
126 | sig->sum_sched_runtime += tsk->se.sum_exec_runtime; | 126 | sig->sum_sched_runtime += tsk->se.sum_exec_runtime; |
127 | sig = NULL; /* Marker for below. */ | ||
128 | } | 127 | } |
129 | 128 | ||
130 | __unhash_process(tsk); | 129 | sig->nr_threads--; |
130 | __unhash_process(tsk, group_dead); | ||
131 | 131 | ||
132 | /* | 132 | /* |
133 | * Do this under ->siglock, we can race with another thread | 133 | * Do this under ->siglock, we can race with another thread |
134 | * doing sigqueue_free() if we have SIGQUEUE_PREALLOC signals. | 134 | * doing sigqueue_free() if we have SIGQUEUE_PREALLOC signals. |
135 | */ | 135 | */ |
136 | flush_sigqueue(&tsk->pending); | 136 | flush_sigqueue(&tsk->pending); |
137 | |||
138 | tsk->signal = NULL; | ||
139 | tsk->sighand = NULL; | 137 | tsk->sighand = NULL; |
140 | spin_unlock(&sighand->siglock); | 138 | spin_unlock(&sighand->siglock); |
141 | 139 | ||
142 | __cleanup_sighand(sighand); | 140 | __cleanup_sighand(sighand); |
143 | clear_tsk_thread_flag(tsk,TIF_SIGPENDING); | 141 | clear_tsk_thread_flag(tsk,TIF_SIGPENDING); |
144 | if (sig) { | 142 | if (group_dead) { |
145 | flush_sigqueue(&sig->shared_pending); | 143 | flush_sigqueue(&sig->shared_pending); |
146 | taskstats_tgid_free(sig); | 144 | tty_kref_put(tty); |
147 | /* | ||
148 | * Make sure ->signal can't go away under rq->lock, | ||
149 | * see account_group_exec_runtime(). | ||
150 | */ | ||
151 | task_rq_unlock_wait(tsk); | ||
152 | __cleanup_signal(sig); | ||
153 | } | 145 | } |
154 | } | 146 | } |
155 | 147 | ||
@@ -857,12 +849,9 @@ static void exit_notify(struct task_struct *tsk, int group_dead) | |||
857 | 849 | ||
858 | tsk->exit_state = signal == DEATH_REAP ? EXIT_DEAD : EXIT_ZOMBIE; | 850 | tsk->exit_state = signal == DEATH_REAP ? EXIT_DEAD : EXIT_ZOMBIE; |
859 | 851 | ||
860 | /* mt-exec, de_thread() is waiting for us */ | 852 | /* mt-exec, de_thread() is waiting for group leader */ |
861 | if (thread_group_leader(tsk) && | 853 | if (unlikely(tsk->signal->notify_count < 0)) |
862 | tsk->signal->group_exit_task && | ||
863 | tsk->signal->notify_count < 0) | ||
864 | wake_up_process(tsk->signal->group_exit_task); | 854 | wake_up_process(tsk->signal->group_exit_task); |
865 | |||
866 | write_unlock_irq(&tasklist_lock); | 855 | write_unlock_irq(&tasklist_lock); |
867 | 856 | ||
868 | tracehook_report_death(tsk, signal, cookie, group_dead); | 857 | tracehook_report_death(tsk, signal, cookie, group_dead); |
@@ -1003,8 +992,10 @@ NORET_TYPE void do_exit(long code) | |||
1003 | 992 | ||
1004 | exit_notify(tsk, group_dead); | 993 | exit_notify(tsk, group_dead); |
1005 | #ifdef CONFIG_NUMA | 994 | #ifdef CONFIG_NUMA |
995 | task_lock(tsk); | ||
1006 | mpol_put(tsk->mempolicy); | 996 | mpol_put(tsk->mempolicy); |
1007 | tsk->mempolicy = NULL; | 997 | tsk->mempolicy = NULL; |
998 | task_unlock(tsk); | ||
1008 | #endif | 999 | #endif |
1009 | #ifdef CONFIG_FUTEX | 1000 | #ifdef CONFIG_FUTEX |
1010 | if (unlikely(current->pi_state_cache)) | 1001 | if (unlikely(current->pi_state_cache)) |