From: "Paul E. McKenney" Additional RCU signal fixes to cover a race with exec() and to add some rcu_dereference()s from earlier patches. Signed-off-by: "Paul E. McKenney" Signed-off-by: Andrew Morton --- kernel/signal.c | 28 +++++++++++++++------------- 1 files changed, 15 insertions(+), 13 deletions(-) diff -puN kernel/signal.c~additional-catchup-rcu-signal-fixes-for-mm kernel/signal.c --- devel/kernel/signal.c~additional-catchup-rcu-signal-fixes-for-mm 2005-11-22 22:30:40.000000000 -0800 +++ devel-akpm/kernel/signal.c 2005-11-22 22:30:40.000000000 -0800 @@ -337,7 +337,7 @@ void exit_sighand(struct task_struct *ts write_lock_irq(&tasklist_lock); rcu_read_lock(); if (tsk->sighand != NULL) { - struct sighand_struct *sighand = tsk->sighand; + struct sighand_struct *sighand = rcu_dereference(tsk->sighand); spin_lock(&sighand->siglock); __exit_sighand(tsk); spin_unlock(&sighand->siglock); @@ -352,13 +352,14 @@ void exit_sighand(struct task_struct *ts void __exit_signal(struct task_struct *tsk) { struct signal_struct * sig = tsk->signal; - struct sighand_struct * sighand = tsk->sighand; + struct sighand_struct * sighand; if (!sig) BUG(); if (!atomic_read(&sig->count)) BUG(); rcu_read_lock(); + sighand = rcu_dereference(tsk->sighand); spin_lock(&sighand->siglock); posix_cpu_timers_exit(tsk); if (atomic_dec_and_test(&sig->count)) { @@ -1091,7 +1092,7 @@ void zap_other_threads(struct task_struc } /* - * Must be called with the tasklist_lock held for reading! + * Must be called under rcu_read_lock() or with tasklist_lock read-held. */ int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) { @@ -1384,7 +1385,7 @@ send_sigqueue(int sig, struct sigqueue * { unsigned long flags; int ret = 0; - struct sighand_struct *sh = p->sighand; + struct sighand_struct *sh; BUG_ON(!(q->flags & SIGQUEUE_PREALLOC)); @@ -1403,7 +1404,15 @@ send_sigqueue(int sig, struct sigqueue * goto out_err; } +retry: + sh = rcu_dereference(p->sighand); + spin_lock_irqsave(&sh->siglock, flags); + if (p->sighand != sh) { + /* We raced with exec() in a multithreaded process... */ + spin_unlock_irqrestore(&sh->siglock, flags); + goto retry; + } /* * We do the check here again to handle the following scenario: @@ -1462,15 +1471,8 @@ send_group_sigqueue(int sig, struct sigq BUG_ON(!(q->flags & SIGQUEUE_PREALLOC)); - while (!read_trylock(&tasklist_lock)) { - if (!p->sighand) - return -1; - cpu_relax(); - } - if (unlikely(!p->sighand)) { - ret = -1; - goto out_err; - } + read_lock(&tasklist_lock); + /* Since it_lock is held, p->sighand cannot be NULL. */ spin_lock_irqsave(&p->sighand->siglock, flags); handle_stop_signal(sig, p); _