Commit 3547ff3aefbe092ca35506c60c02e2d17a4f2199
Committed by
Linus Torvalds
1 parent
6e65acba7c
Exists in
master
and in
39 other branches
signals: do_tkill: don't use tasklist_lock
Convert do_tkill() to use rcu_read_lock() + lock_task_sighand() to avoid taking tasklist lock. Note that we don't return an error if lock_task_sighand() fails, we pretend the task dies after receiving the signal. Otherwise, we should fight with the nasty races with mt-exec without having any advantage. Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru> Cc: Roland McGrath <roland@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 1 changed file with 9 additions and 5 deletions Side-by-side Diff
kernel/signal.c
... | ... | @@ -2219,6 +2219,7 @@ |
2219 | 2219 | int error; |
2220 | 2220 | struct siginfo info; |
2221 | 2221 | struct task_struct *p; |
2222 | + unsigned long flags; | |
2222 | 2223 | |
2223 | 2224 | error = -ESRCH; |
2224 | 2225 | info.si_signo = sig; |
2225 | 2226 | |
2226 | 2227 | |
2227 | 2228 | |
2228 | 2229 | |
... | ... | @@ -2227,21 +2228,24 @@ |
2227 | 2228 | info.si_pid = task_tgid_vnr(current); |
2228 | 2229 | info.si_uid = current->uid; |
2229 | 2230 | |
2230 | - read_lock(&tasklist_lock); | |
2231 | + rcu_read_lock(); | |
2231 | 2232 | p = find_task_by_vpid(pid); |
2232 | 2233 | if (p && (tgid <= 0 || task_tgid_vnr(p) == tgid)) { |
2233 | 2234 | error = check_kill_permission(sig, &info, p); |
2234 | 2235 | /* |
2235 | 2236 | * The null signal is a permissions and process existence |
2236 | 2237 | * probe. No signal is actually delivered. |
2238 | + * | |
2239 | + * If lock_task_sighand() fails we pretend the task dies | |
2240 | + * after receiving the signal. The window is tiny, and the | |
2241 | + * signal is private anyway. | |
2237 | 2242 | */ |
2238 | - if (!error && sig && p->sighand) { | |
2239 | - spin_lock_irq(&p->sighand->siglock); | |
2243 | + if (!error && sig && lock_task_sighand(p, &flags)) { | |
2240 | 2244 | error = specific_send_sig_info(sig, &info, p); |
2241 | - spin_unlock_irq(&p->sighand->siglock); | |
2245 | + unlock_task_sighand(p, &flags); | |
2242 | 2246 | } |
2243 | 2247 | } |
2244 | - read_unlock(&tasklist_lock); | |
2248 | + rcu_read_unlock(); | |
2245 | 2249 | |
2246 | 2250 | return error; |
2247 | 2251 | } |