Subject: [PATCH] Cleanup the pspace signal handling. From: Eric W. Biederman Date: 1130041663 -0600 --- include/linux/pid.h | 1 - include/linux/sched.h | 4 ++- kernel/exit.c | 2 +- kernel/fork.c | 1 + kernel/signal.c | 57 +++++++++++++++++++++++++------------------------ 5 files changed, 33 insertions(+), 32 deletions(-) bc95878a75e6cfb7723bd386b5c8eb69723ff299 diff --git a/include/linux/pid.h b/include/linux/pid.h index 8a75e6c..460fee8 100644 --- a/include/linux/pid.h +++ b/include/linux/pid.h @@ -8,7 +8,6 @@ enum pid_type PIDTYPE_TGID, PIDTYPE_PGID, PIDTYPE_SID, - PIDTYPE_PSPACE, PIDTYPE_MAX }; diff --git a/include/linux/sched.h b/include/linux/sched.h index 0b01c97..270e0b3 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1016,8 +1016,8 @@ extern int send_sig_info(int, struct sig extern int send_group_sig_info(int, struct siginfo *, struct task_struct *); extern int force_sigsegv(int, struct task_struct *); extern int force_sig_info(int, struct siginfo *, struct task_struct *); -extern int __kill_pspace_info(int sig, struct siginfo *info, pid_t pspaceid); -extern int kill_pspace_info(int sig, struct siginfo *info, pid_t pspaceid); +extern int __kill_pspace_info(int sig, struct siginfo *info, struct pspace *pspace); +extern int kill_pspace_info(int sig, struct siginfo *info, struct pspace *pspace); extern int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp); extern int kill_pg_info(int, struct siginfo *, pid_t); extern int kill_proc_info(int, struct siginfo *, pid_t); diff --git a/kernel/exit.c b/kernel/exit.c index aa349bf..19068c5 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -745,7 +745,7 @@ static void exit_notify(struct task_stru */ if (pspace_leader(tsk)) { tsk->sighand->action[SIGCHLD-1].sa.sa_handler = SIG_IGN; - __kill_pspace_info(SIGKILL, (void *)1, tsk->tgid); + __kill_pspace_info(SIGKILL, (void *)1, tsk->pspace); } /* Let father know we died diff --git a/kernel/fork.c b/kernel/fork.c index 156359a..97aef76 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1146,6 +1146,7 @@ static task_t *copy_process(unsigned lon p->signal->session = p->pid; p->signal->tty = NULL; p->signal->tty_old_pgrp = 0; + attach_pid(p, PIDTYPE_ALTPID, p->pid); } attach_pid(p, PIDTYPE_PID, p->pid); attach_pid(p, PIDTYPE_TGID, p->tgid); diff --git a/kernel/signal.c b/kernel/signal.c index 4842b9e..32fcb92 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1145,44 +1145,48 @@ int group_send_sig_info(int sig, struct } /* - * kill_pspace_info() sends a signal to all processes in a process id space. + * kill_pspace_info() sends a signal to all processes in a process space. * This is what kill(-1, sig) does. */ -int __kill_pspace_info(int sig, struct siginfo *info, pid_t pspaceid) +int __kill_pspace_info(int sig, struct siginfo *info, struct pspace *pspace) { struct task_struct *p = NULL; - struct pspace *pspace; - pid_t min, max; int retval = 0, count = 0; - p = find_task_by_pid_type(PIDTYPE_TGID, pspaceid); - if (!p || (p->tgid != (p->pspace->offset + 1))) - return -ESRCH; - - pspace = p->pspace; - min = pspace->offset; - max = pspace->offset + pspace->max; - for_each_process(p) { - if ((p != current->pspace->child_reaper) && (p->tgid != current->tgid) && - (p->pid > min) && (p->pid < max)) - { - int err = group_send_sig_info(sig, info, p); - ++count; - if (err != -EPERM) - retval = err; - } + struct pspace *test; + int err; + /* Skip init */ + if (pspace_leader(p)) + continue; + + /* Skip the sender of the signal */ + if (p->tgid == current->tgid) + continue; + + /* Skip processes outside the target process space */ + test = p->pspace; + while(test && (test != pspace)) + test = test->parent; + if (test != pspace) + continue; + + /* Finally it is a good process send the signal. */ + err = group_send_sig_info(sig, info, p); + ++count; + if (err != -EPERM) + retval = err; } return count ? retval : -ESRCH; } -int kill_pspace_info(int sig, struct siginfo *info, pid_t pspaceid) +int kill_pspace_info(int sig, struct siginfo *info, struct pspace *pspace) { int retval; read_lock(&tasklist_lock); - retval = __kill_pspace_info(sig, info, pspaceid); + retval = __kill_pspace_info(sig, info, pspace); read_unlock(&tasklist_lock); return retval; @@ -1258,11 +1262,11 @@ static int kill_something_info(int sig, pid = pid_from_user(-pid); read_lock(&tasklist_lock); - p = find_task_by_pid_type(PIDTYPE_TGID, pid); - if (likely(!p || (p->tgid != (p->pspace->offset + 1)))) + p = find_task_by_pid(pid); + if (!p || !pspace_leader(p)) retval = __kill_pg_info(sig, info, pid); else - retval = __kill_pspace_info(sig, info, pid); + retval = __kill_pspace_info(sig, info, p->pspace); read_unlock(&tasklist_lock); return retval; } else { @@ -1717,9 +1721,6 @@ finish_stop(int stop_count) goto out; read_lock(&tasklist_lock); - /* If init stops stop all of it's children */ - if (pspace_leader(current)) - __kill_pspace_info(SIGSTOP, (void *)1, current->tgid); do_notify_parent_cldstop(current, to_self, CLD_STOPPED); read_unlock(&tasklist_lock); -- 1.0.GIT