Make the code more maintainable by performing more of the signal
related work in send_sigqueue.

A quick inspection of do_timer_create will show that this code path
does not lookup a thread group by a thread's pid.  Making it safe
to find the task pointed to by it_pid with "pid_task(it_pid, type)";

This supports the changes needed in fork to tell if a signal was sent
to a single process or a group of processes.

Having the pid to task transition in signal.c will also make it easier
to sort out races with de_thread and and the thread group leader
exiting when it comes time to address that.

Signed-off-by: "Eric W. Biederman" <ebied...@xmission.com>
---
 include/linux/sched/signal.h |  2 +-
 kernel/signal.c              | 14 +++++++++-----
 kernel/time/posix-timers.c   | 13 ++++---------
 3 files changed, 14 insertions(+), 15 deletions(-)

diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
index ee30a5ba475f..94558ffa82ab 100644
--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -330,7 +330,7 @@ extern int send_sig(int, struct task_struct *, int);
 extern int zap_other_threads(struct task_struct *p);
 extern struct sigqueue *sigqueue_alloc(void);
 extern void sigqueue_free(struct sigqueue *);
-extern int send_sigqueue(struct sigqueue *,  struct task_struct *, int group);
+extern int send_sigqueue(struct sigqueue *, struct pid *, enum pid_type);
 extern int do_sigaction(int, struct k_sigaction *, struct k_sigaction *);
 
 static inline int restart_syscall(void)
diff --git a/kernel/signal.c b/kernel/signal.c
index 8d8a940422a8..40feb14e276d 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1664,17 +1664,20 @@ void sigqueue_free(struct sigqueue *q)
                __sigqueue_free(q);
 }
 
-int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group)
+int send_sigqueue(struct sigqueue *q, struct pid *pid, enum pid_type type)
 {
        int sig = q->info.si_signo;
        struct sigpending *pending;
+       struct task_struct *t;
        unsigned long flags;
        int ret, result;
 
        BUG_ON(!(q->flags & SIGQUEUE_PREALLOC));
 
        ret = -1;
-       if (!likely(lock_task_sighand(t, &flags)))
+       rcu_read_lock();
+       t = pid_task(pid, type);
+       if (!t || !likely(lock_task_sighand(t, &flags)))
                goto ret;
 
        ret = 1; /* the signal is ignored */
@@ -1696,15 +1699,16 @@ int send_sigqueue(struct sigqueue *q, struct 
task_struct *t, int group)
        q->info.si_overrun = 0;
 
        signalfd_notify(t, sig);
-       pending = group ? &t->signal->shared_pending : &t->pending;
+       pending = (type != PIDTYPE_PID) ? &t->signal->shared_pending : 
&t->pending;
        list_add_tail(&q->list, &pending->list);
        sigaddset(&pending->signal, sig);
-       complete_signal(sig, t, group);
+       complete_signal(sig, t, type != PIDTYPE_PID);
        result = TRACE_SIGNAL_DELIVERED;
 out:
-       trace_signal_generate(sig, &q->info, t, group, result);
+       trace_signal_generate(sig, &q->info, t, type != PIDTYPE_PID, result);
        unlock_task_sighand(t, &flags);
 ret:
+       rcu_read_unlock();
        return ret;
 }
 
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
index 2bdf08a2bae9..2d2e739fbc57 100644
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -332,8 +332,8 @@ void posixtimer_rearm(struct siginfo *info)
 
 int posix_timer_event(struct k_itimer *timr, int si_private)
 {
-       struct task_struct *task;
-       int shared, ret = -1;
+       enum pid_type type;
+       int ret = -1;
        /*
         * FIXME: if ->sigq is queued we can race with
         * dequeue_signal()->posixtimer_rearm().
@@ -347,13 +347,8 @@ int posix_timer_event(struct k_itimer *timr, int 
si_private)
         */
        timr->sigq->info.si_sys_private = si_private;
 
-       rcu_read_lock();
-       task = pid_task(timr->it_pid, PIDTYPE_PID);
-       if (task) {
-               shared = !(timr->it_sigev_notify & SIGEV_THREAD_ID);
-               ret = send_sigqueue(timr->sigq, task, shared);
-       }
-       rcu_read_unlock();
+       type = !(timr->it_sigev_notify & SIGEV_THREAD_ID) ? PIDTYPE_TGID : 
PIDTYPE_PID;
+       ret = send_sigqueue(timr->sigq, timr->it_pid, type);
        /* If we failed to send the signal the timer stops. */
        return ret > 0;
 }
-- 
2.17.1

Reply via email to