Commit 3547ff3aefbe092ca35506c60c02e2d17a4f2199

Authored by Oleg Nesterov
Committed by Linus Torvalds
1 parent 6e65acba7c

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

... ... @@ -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 }