Commit 3547ff3a authored by Oleg Nesterov's avatar Oleg Nesterov Committed by Linus Torvalds

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: default avatarOleg Nesterov <oleg@tv-sign.ru>
Cc: Roland McGrath <roland@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 6e65acba
...@@ -2219,6 +2219,7 @@ static int do_tkill(int tgid, int pid, int sig) ...@@ -2219,6 +2219,7 @@ static int do_tkill(int tgid, int pid, int sig)
int error; int error;
struct siginfo info; struct siginfo info;
struct task_struct *p; struct task_struct *p;
unsigned long flags;
error = -ESRCH; error = -ESRCH;
info.si_signo = sig; info.si_signo = sig;
...@@ -2227,21 +2228,24 @@ static int do_tkill(int tgid, int pid, int sig) ...@@ -2227,21 +2228,24 @@ static int do_tkill(int tgid, int pid, int sig)
info.si_pid = task_tgid_vnr(current); info.si_pid = task_tgid_vnr(current);
info.si_uid = current->uid; info.si_uid = current->uid;
read_lock(&tasklist_lock); rcu_read_lock();
p = find_task_by_vpid(pid); p = find_task_by_vpid(pid);
if (p && (tgid <= 0 || task_tgid_vnr(p) == tgid)) { if (p && (tgid <= 0 || task_tgid_vnr(p) == tgid)) {
error = check_kill_permission(sig, &info, p); error = check_kill_permission(sig, &info, p);
/* /*
* The null signal is a permissions and process existence * The null signal is a permissions and process existence
* probe. No signal is actually delivered. * probe. No signal is actually delivered.
*
* If lock_task_sighand() fails we pretend the task dies
* after receiving the signal. The window is tiny, and the
* signal is private anyway.
*/ */
if (!error && sig && p->sighand) { if (!error && sig && lock_task_sighand(p, &flags)) {
spin_lock_irq(&p->sighand->siglock);
error = specific_send_sig_info(sig, &info, p); error = specific_send_sig_info(sig, &info, p);
spin_unlock_irq(&p->sighand->siglock); unlock_task_sighand(p, &flags);
} }
} }
read_unlock(&tasklist_lock); rcu_read_unlock();
return error; return error;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment