]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - kernel/exit.c
pid: sys_wait... fixes
[linux.git] / kernel / exit.c
index 2b332d170327763c8833da485dc93d9bec0a6b90..2567de3487bd29e6c16a717058be11f1d3926a0e 100644 (file)
@@ -1090,20 +1090,23 @@ asmlinkage void sys_exit_group(int error_code)
        do_group_exit((error_code & 0xff) << 8);
 }
 
-static int eligible_child(pid_t pid, int options, struct task_struct *p)
+static struct pid *task_pid_type(struct task_struct *task, enum pid_type type)
+{
+       struct pid *pid = NULL;
+       if (type == PIDTYPE_PID)
+               pid = task->pids[type].pid;
+       else if (type < PIDTYPE_MAX)
+               pid = task->group_leader->pids[type].pid;
+       return pid;
+}
+
+static int eligible_child(enum pid_type type, struct pid *pid, int options,
+                         struct task_struct *p)
 {
        int err;
-       struct pid_namespace *ns;
 
-       ns = current->nsproxy->pid_ns;
-       if (pid > 0) {
-               if (task_pid_nr_ns(p, ns) != pid)
-                       return 0;
-       } else if (!pid) {
-               if (task_pgrp_nr_ns(p, ns) != task_pgrp_vnr(current))
-                       return 0;
-       } else if (pid != -1) {
-               if (task_pgrp_nr_ns(p, ns) != -pid)
+       if (type < PIDTYPE_MAX) {
+               if (task_pid_type(p, type) != pid)
                        return 0;
        }
 
@@ -1127,7 +1130,7 @@ static int eligible_child(pid_t pid, int options, struct task_struct *p)
        if (likely(!err))
                return 1;
 
-       if (pid <= 0)
+       if (type != PIDTYPE_PID)
                return 0;
        /* This child was explicitly requested, abort */
        read_unlock(&tasklist_lock);
@@ -1447,8 +1450,9 @@ static int wait_task_continued(struct task_struct *p, int noreap,
        return retval;
 }
 
-static long do_wait(pid_t pid, int options, struct siginfo __user *infop,
-                   int __user *stat_addr, struct rusage __user *ru)
+static long do_wait(enum pid_type type, struct pid *pid, int options,
+                   struct siginfo __user *infop, int __user *stat_addr,
+                   struct rusage __user *ru)
 {
        DECLARE_WAITQUEUE(wait, current);
        struct task_struct *tsk;
@@ -1456,6 +1460,11 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop,
 
        add_wait_queue(&current->signal->wait_chldexit,&wait);
 repeat:
+       /* If there is nothing that can match our critier just get out */
+       retval = -ECHILD;
+       if ((type < PIDTYPE_MAX) && (!pid || hlist_empty(&pid->tasks[type])))
+               goto end;
+
        /*
         * We will set this flag if we see any child that might later
         * match our criteria, even if we are not able to reap it yet.
@@ -1468,7 +1477,7 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop,
                struct task_struct *p;
 
                list_for_each_entry(p, &tsk->children, sibling) {
-                       int ret = eligible_child(pid, options, p);
+                       int ret = eligible_child(type, pid, options, p);
                        if (!ret)
                                continue;
 
@@ -1515,7 +1524,7 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop,
                if (!flag) {
                        list_for_each_entry(p, &tsk->ptrace_children,
                                                                ptrace_list) {
-                               flag = eligible_child(pid, options, p);
+                               flag = eligible_child(type, pid, options, p);
                                if (!flag)
                                        continue;
                                if (likely(flag > 0))
@@ -1570,10 +1579,12 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop,
        return retval;
 }
 
-asmlinkage long sys_waitid(int which, pid_t pid,
+asmlinkage long sys_waitid(int which, pid_t upid,
                           struct siginfo __user *infop, int options,
                           struct rusage __user *ru)
 {
+       struct pid *pid = NULL;
+       enum pid_type type;
        long ret;
 
        if (options & ~(WNOHANG|WNOWAIT|WEXITED|WSTOPPED|WCONTINUED))
@@ -1583,37 +1594,58 @@ asmlinkage long sys_waitid(int which, pid_t pid,
 
        switch (which) {
        case P_ALL:
-               pid = -1;
+               type = PIDTYPE_MAX;
                break;
        case P_PID:
-               if (pid <= 0)
+               type = PIDTYPE_PID;
+               if (upid <= 0)
                        return -EINVAL;
                break;
        case P_PGID:
-               if (pid <= 0)
+               type = PIDTYPE_PGID;
+               if (upid <= 0)
                        return -EINVAL;
-               pid = -pid;
                break;
        default:
                return -EINVAL;
        }
 
-       ret = do_wait(pid, options, infop, NULL, ru);
+       if (type < PIDTYPE_MAX)
+               pid = find_get_pid(upid);
+       ret = do_wait(type, pid, options, infop, NULL, ru);
+       put_pid(pid);
 
        /* avoid REGPARM breakage on x86: */
        prevent_tail_call(ret);
        return ret;
 }
 
-asmlinkage long sys_wait4(pid_t pid, int __user *stat_addr,
+asmlinkage long sys_wait4(pid_t upid, int __user *stat_addr,
                          int options, struct rusage __user *ru)
 {
+       struct pid *pid = NULL;
+       enum pid_type type;
        long ret;
 
        if (options & ~(WNOHANG|WUNTRACED|WCONTINUED|
                        __WNOTHREAD|__WCLONE|__WALL))
                return -EINVAL;
-       ret = do_wait(pid, options | WEXITED, NULL, stat_addr, ru);
+
+       if (upid == -1)
+               type = PIDTYPE_MAX;
+       else if (upid < 0) {
+               type = PIDTYPE_PGID;
+               pid = find_get_pid(-upid);
+       } else if (upid == 0) {
+               type = PIDTYPE_PGID;
+               pid = get_pid(task_pgrp(current));
+       } else /* upid > 0 */ {
+               type = PIDTYPE_PID;
+               pid = find_get_pid(upid);
+       }
+
+       ret = do_wait(type, pid, options | WEXITED, NULL, stat_addr, ru);
+       put_pid(pid);
 
        /* avoid REGPARM breakage on x86: */
        prevent_tail_call(ret);