mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-13 15:53:56 +08:00
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>
This commit is contained in:
parent
6e65acba7c
commit
3547ff3aef
@ -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)
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user