aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/signal.c
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@tv-sign.ru>2008-04-30 03:52:51 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-30 11:29:35 -0400
commit3547ff3aefbe092ca35506c60c02e2d17a4f2199 (patch)
tree722222124ae06ef45947fae20913bbd71e179c49 /kernel/signal.c
parent6e65acba7ca8169e38ab55d62d52f29a75fb141f (diff)
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>
Diffstat (limited to 'kernel/signal.c')
-rw-r--r--kernel/signal.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index b3dedf1f932..13371d17358 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2219,6 +2219,7 @@ static int do_tkill(int tgid, int pid, int sig)
2219 int error; 2219 int error;
2220 struct siginfo info; 2220 struct siginfo info;
2221 struct task_struct *p; 2221 struct task_struct *p;
2222 unsigned long flags;
2222 2223
2223 error = -ESRCH; 2224 error = -ESRCH;
2224 info.si_signo = sig; 2225 info.si_signo = sig;
@@ -2227,21 +2228,24 @@ static int do_tkill(int tgid, int pid, int sig)
2227 info.si_pid = task_tgid_vnr(current); 2228 info.si_pid = task_tgid_vnr(current);
2228 info.si_uid = current->uid; 2229 info.si_uid = current->uid;
2229 2230
2230 read_lock(&tasklist_lock); 2231 rcu_read_lock();
2231 p = find_task_by_vpid(pid); 2232 p = find_task_by_vpid(pid);
2232 if (p && (tgid <= 0 || task_tgid_vnr(p) == tgid)) { 2233 if (p && (tgid <= 0 || task_tgid_vnr(p) == tgid)) {
2233 error = check_kill_permission(sig, &info, p); 2234 error = check_kill_permission(sig, &info, p);
2234 /* 2235 /*
2235 * The null signal is a permissions and process existence 2236 * The null signal is a permissions and process existence
2236 * probe. No signal is actually delivered. 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) { 2243 if (!error && sig && lock_task_sighand(p, &flags)) {
2239 spin_lock_irq(&p->sighand->siglock);
2240 error = specific_send_sig_info(sig, &info, p); 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 return error; 2250 return error;
2247} 2251}