summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kernel/exit.c80
1 files changed, 56 insertions, 24 deletions
diff --git a/kernel/exit.c b/kernel/exit.c
index 2b332d170327..2567de3487bd 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -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 @@ repeat:
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 @@ repeat:
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 @@ end:
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);