mirror of
https://github.com/adulau/aha.git
synced 2024-12-29 12:16:20 +00:00
pid: sys_wait... fixes
This modifies do_wait and eligible child to take a pair of enum pid_type and struct pid *pid to precisely specify what set of processes are eligible to be waited for, instead of the raw pid_t value from sys_wait4. This fixes a bug in sys_waitid where you could not wait for children in just process group 1. This fixes a pid namespace crossing case in eligible_child. Allowing us to wait for a processes in our current process group even if our current process group == 0. This allows the no child with this pid case to be optimized. This allows us to optimize the pid membership test in eligible child to be optimized. This even closes a theoretical pid wraparound race where in a threaded parent if two threads are waiting for the same child and one thread picks up the child and the pid numbers wrap around and generate another child with that same pid before the other thread is scheduled (teribly insanely unlikely) we could end up waiting on the second child with the same pid# and not discover that the specific child we were waiting for has exited. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Cc: Oleg Nesterov <oleg@tv-sign.ru> Cc: Pavel Emelyanov <xemul@openvz.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
5dee1707df
commit
161550d74c
1 changed files with 56 additions and 24 deletions
|
@ -1090,20 +1090,23 @@ asmlinkage void sys_exit_group(int error_code)
|
||||||
do_group_exit((error_code & 0xff) << 8);
|
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;
|
int err;
|
||||||
struct pid_namespace *ns;
|
|
||||||
|
|
||||||
ns = current->nsproxy->pid_ns;
|
if (type < PIDTYPE_MAX) {
|
||||||
if (pid > 0) {
|
if (task_pid_type(p, type) != pid)
|
||||||
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)
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1127,7 +1130,7 @@ static int eligible_child(pid_t pid, int options, struct task_struct *p)
|
||||||
if (likely(!err))
|
if (likely(!err))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (pid <= 0)
|
if (type != PIDTYPE_PID)
|
||||||
return 0;
|
return 0;
|
||||||
/* This child was explicitly requested, abort */
|
/* This child was explicitly requested, abort */
|
||||||
read_unlock(&tasklist_lock);
|
read_unlock(&tasklist_lock);
|
||||||
|
@ -1447,8 +1450,9 @@ static int wait_task_continued(struct task_struct *p, int noreap,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long do_wait(pid_t pid, int options, struct siginfo __user *infop,
|
static long do_wait(enum pid_type type, struct pid *pid, int options,
|
||||||
int __user *stat_addr, struct rusage __user *ru)
|
struct siginfo __user *infop, int __user *stat_addr,
|
||||||
|
struct rusage __user *ru)
|
||||||
{
|
{
|
||||||
DECLARE_WAITQUEUE(wait, current);
|
DECLARE_WAITQUEUE(wait, current);
|
||||||
struct task_struct *tsk;
|
struct task_struct *tsk;
|
||||||
|
@ -1456,6 +1460,11 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop,
|
||||||
|
|
||||||
add_wait_queue(¤t->signal->wait_chldexit,&wait);
|
add_wait_queue(¤t->signal->wait_chldexit,&wait);
|
||||||
repeat:
|
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
|
* 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.
|
* match our criteria, even if we are not able to reap it yet.
|
||||||
|
@ -1468,7 +1477,7 @@ repeat:
|
||||||
struct task_struct *p;
|
struct task_struct *p;
|
||||||
|
|
||||||
list_for_each_entry(p, &tsk->children, sibling) {
|
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)
|
if (!ret)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -1515,7 +1524,7 @@ repeat:
|
||||||
if (!flag) {
|
if (!flag) {
|
||||||
list_for_each_entry(p, &tsk->ptrace_children,
|
list_for_each_entry(p, &tsk->ptrace_children,
|
||||||
ptrace_list) {
|
ptrace_list) {
|
||||||
flag = eligible_child(pid, options, p);
|
flag = eligible_child(type, pid, options, p);
|
||||||
if (!flag)
|
if (!flag)
|
||||||
continue;
|
continue;
|
||||||
if (likely(flag > 0))
|
if (likely(flag > 0))
|
||||||
|
@ -1570,10 +1579,12 @@ end:
|
||||||
return retval;
|
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 siginfo __user *infop, int options,
|
||||||
struct rusage __user *ru)
|
struct rusage __user *ru)
|
||||||
{
|
{
|
||||||
|
struct pid *pid = NULL;
|
||||||
|
enum pid_type type;
|
||||||
long ret;
|
long ret;
|
||||||
|
|
||||||
if (options & ~(WNOHANG|WNOWAIT|WEXITED|WSTOPPED|WCONTINUED))
|
if (options & ~(WNOHANG|WNOWAIT|WEXITED|WSTOPPED|WCONTINUED))
|
||||||
|
@ -1583,37 +1594,58 @@ asmlinkage long sys_waitid(int which, pid_t pid,
|
||||||
|
|
||||||
switch (which) {
|
switch (which) {
|
||||||
case P_ALL:
|
case P_ALL:
|
||||||
pid = -1;
|
type = PIDTYPE_MAX;
|
||||||
break;
|
break;
|
||||||
case P_PID:
|
case P_PID:
|
||||||
if (pid <= 0)
|
type = PIDTYPE_PID;
|
||||||
|
if (upid <= 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
break;
|
break;
|
||||||
case P_PGID:
|
case P_PGID:
|
||||||
if (pid <= 0)
|
type = PIDTYPE_PGID;
|
||||||
|
if (upid <= 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
pid = -pid;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
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: */
|
/* avoid REGPARM breakage on x86: */
|
||||||
prevent_tail_call(ret);
|
prevent_tail_call(ret);
|
||||||
return 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)
|
int options, struct rusage __user *ru)
|
||||||
{
|
{
|
||||||
|
struct pid *pid = NULL;
|
||||||
|
enum pid_type type;
|
||||||
long ret;
|
long ret;
|
||||||
|
|
||||||
if (options & ~(WNOHANG|WUNTRACED|WCONTINUED|
|
if (options & ~(WNOHANG|WUNTRACED|WCONTINUED|
|
||||||
__WNOTHREAD|__WCLONE|__WALL))
|
__WNOTHREAD|__WCLONE|__WALL))
|
||||||
return -EINVAL;
|
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: */
|
/* avoid REGPARM breakage on x86: */
|
||||||
prevent_tail_call(ret);
|
prevent_tail_call(ret);
|
||||||
|
|
Loading…
Reference in a new issue