static int will_become_orphaned_pgrp(struct pid *pgrp, struct task_struct *ignored_task)
{
struct task_struct *p;
- int ret = 1;
do_each_pid_task(pgrp, PIDTYPE_PGID, p) {
- if (p == ignored_task
- || p->exit_state
- || is_global_init(p->real_parent))
+ if ((p == ignored_task) ||
+ (p->exit_state && thread_group_empty(p)) ||
+ is_global_init(p->real_parent))
continue;
+
if (task_pgrp(p->real_parent) != pgrp &&
- task_session(p->real_parent) == task_session(p)) {
- ret = 0;
- break;
- }
+ task_session(p->real_parent) == task_session(p))
+ return 0;
} while_each_pid_task(pgrp, PIDTYPE_PGID, p);
- return ret; /* (sighing) "Often!" */
+
+ return 1;
}
int is_current_pgrp_orphaned(void)
return retval;
}
+/*
+ * Check to see if any process groups have become orphaned as
+ * a result of our exiting, and if they have any stopped jobs,
+ * send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2)
+ */
+static void
+kill_orphaned_pgrp(struct task_struct *tsk, struct task_struct *parent)
+{
+ struct pid *pgrp = task_pgrp(tsk);
+ struct task_struct *ignored_task = tsk;
+
+ if (!parent)
+ /* exit: our father is in a different pgrp than
+ * we are and we were the only connection outside.
+ */
+ parent = tsk->real_parent;
+ else
+ /* reparent: our child is in a different pgrp than
+ * we are, and it was the only connection outside.
+ */
+ ignored_task = NULL;
+
+ if (task_pgrp(parent) != pgrp &&
+ task_session(parent) == task_session(tsk) &&
+ will_become_orphaned_pgrp(pgrp, ignored_task) &&
+ has_stopped_jobs(pgrp)) {
+ __kill_pgrp_info(SIGHUP, SEND_SIG_PRIV, pgrp);
+ __kill_pgrp_info(SIGCONT, SEND_SIG_PRIV, pgrp);
+ }
+}
+
/**
* reparent_to_kthreadd - Reparent the calling kernel thread to kthreadd
*
switch_uid(INIT_USER);
}
-void __set_special_pids(pid_t session, pid_t pgrp)
+void __set_special_pids(struct pid *pid)
{
struct task_struct *curr = current->group_leader;
+ pid_t nr = pid_nr(pid);
- if (task_session_nr(curr) != session) {
+ if (task_session(curr) != pid) {
detach_pid(curr, PIDTYPE_SID);
- set_task_session(curr, session);
- attach_pid(curr, PIDTYPE_SID, find_pid(session));
+ attach_pid(curr, PIDTYPE_SID, pid);
+ set_task_session(curr, nr);
}
- if (task_pgrp_nr(curr) != pgrp) {
+ if (task_pgrp(curr) != pid) {
detach_pid(curr, PIDTYPE_PGID);
- set_task_pgrp(curr, pgrp);
- attach_pid(curr, PIDTYPE_PGID, find_pid(pgrp));
+ attach_pid(curr, PIDTYPE_PGID, pid);
+ set_task_pgrp(curr, nr);
}
}
-static void set_special_pids(pid_t session, pid_t pgrp)
+static void set_special_pids(struct pid *pid)
{
write_lock_irq(&tasklist_lock);
- __set_special_pids(session, pgrp);
+ __set_special_pids(pid);
write_unlock_irq(&tasklist_lock);
}
*/
current->flags |= PF_NOFREEZE;
- set_special_pids(1, 1);
+ if (current->nsproxy != &init_nsproxy) {
+ get_nsproxy(&init_nsproxy);
+ switch_task_namespaces(current, &init_nsproxy);
+ }
+ set_special_pids(&init_struct_pid);
proc_clear_tty(current);
/* Block and flush all signals */
current->fs = fs;
atomic_inc(&fs->count);
- if (current->nsproxy != init_task.nsproxy) {
- get_nsproxy(init_task.nsproxy);
- switch_task_namespaces(current, init_task.nsproxy);
- }
-
exit_files(current);
current->files = init_task.files;
atomic_inc(¤t->files->count);
return files;
}
-void fastcall put_files_struct(struct files_struct *files)
+void put_files_struct(struct files_struct *files)
{
struct fdtable *fdt;
{
/* No need to hold fs->lock if we are killing it */
if (atomic_dec_and_test(&fs->count)) {
- dput(fs->root);
- mntput(fs->rootmnt);
- dput(fs->pwd);
- mntput(fs->pwdmnt);
- if (fs->altroot) {
- dput(fs->altroot);
- mntput(fs->altrootmnt);
- }
+ path_put(&fs->root);
+ path_put(&fs->pwd);
+ if (fs->altroot.dentry)
+ path_put(&fs->altroot);
kmem_cache_free(fs_cachep, fs);
}
}
p->exit_signal != -1 && thread_group_empty(p))
do_notify_parent(p, p->exit_signal);
- /*
- * process group orphan check
- * Case ii: Our child is in a different pgrp
- * than we are, and it was the only connection
- * outside, so the child pgrp is now orphaned.
- */
- if ((task_pgrp(p) != task_pgrp(father)) &&
- (task_session(p) == task_session(father))) {
- struct pid *pgrp = task_pgrp(p);
-
- if (will_become_orphaned_pgrp(pgrp, NULL) &&
- has_stopped_jobs(pgrp)) {
- __kill_pgrp_info(SIGHUP, SEND_SIG_PRIV, pgrp);
- __kill_pgrp_info(SIGCONT, SEND_SIG_PRIV, pgrp);
- }
- }
+ kill_orphaned_pgrp(p, father);
}
/*
* Send signals to all our closest relatives so that they know
* to properly mourn us..
*/
-static void exit_notify(struct task_struct *tsk)
+static void exit_notify(struct task_struct *tsk, int group_dead)
{
int state;
- struct task_struct *t;
- struct pid *pgrp;
-
- if (signal_pending(tsk) && !(tsk->signal->flags & SIGNAL_GROUP_EXIT)
- && !thread_group_empty(tsk)) {
- /*
- * This occurs when there was a race between our exit
- * syscall and a group signal choosing us as the one to
- * wake up. It could be that we are the only thread
- * alerted to check for pending signals, but another thread
- * should be woken now to take the signal since we will not.
- * Now we'll wake all the threads in the group just to make
- * sure someone gets all the pending signals.
- */
- spin_lock_irq(&tsk->sighand->siglock);
- for (t = next_thread(tsk); t != tsk; t = next_thread(t))
- if (!signal_pending(t) && !(t->flags & PF_EXITING))
- recalc_sigpending_and_wake(t);
- spin_unlock_irq(&tsk->sighand->siglock);
- }
/*
* This does two things:
exit_task_namespaces(tsk);
write_lock_irq(&tasklist_lock);
- /*
- * Check to see if any process groups have become orphaned
- * as a result of our exiting, and if they have any stopped
- * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2)
- *
- * Case i: Our father is in a different pgrp than we are
- * and we were the only connection outside, so our pgrp
- * is about to become orphaned.
- */
- t = tsk->real_parent;
-
- pgrp = task_pgrp(tsk);
- if ((task_pgrp(t) != pgrp) &&
- (task_session(t) == task_session(tsk)) &&
- will_become_orphaned_pgrp(pgrp, tsk) &&
- has_stopped_jobs(pgrp)) {
- __kill_pgrp_info(SIGHUP, SEND_SIG_PRIV, pgrp);
- __kill_pgrp_info(SIGCONT, SEND_SIG_PRIV, pgrp);
- }
+ if (group_dead)
+ kill_orphaned_pgrp(tsk->group_leader, NULL);
/* Let father know we died
*
* the same after a fork.
*/
if (tsk->exit_signal != SIGCHLD && tsk->exit_signal != -1 &&
- ( tsk->parent_exec_id != t->self_exec_id ||
- tsk->self_exec_id != tsk->parent_exec_id)
+ (tsk->parent_exec_id != tsk->real_parent->self_exec_id ||
+ tsk->self_exec_id != tsk->parent_exec_id)
&& !capable(CAP_KILL))
tsk->exit_signal = SIGCHLD;
zap_pid_ns_processes(tsk->nsproxy->pid_ns);
}
-fastcall NORET_TYPE void do_exit(long code)
+NORET_TYPE void do_exit(long code)
{
struct task_struct *tsk = current;
int group_dead;
schedule();
}
- tsk->flags |= PF_EXITING;
+ exit_signals(tsk); /* sets PF_EXITING */
/*
* tsk->flags are checked in the futex code to protect against
* an exiting task cleaning up the robust pi futexes.
module_put(tsk->binfmt->module);
proc_exit_connector(tsk);
- exit_notify(tsk);
+ exit_notify(tsk, group_dead);
#ifdef CONFIG_NUMA
mpol_free(tsk->mempolicy);
tsk->mempolicy = NULL;
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;
}
if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
&& !(options & __WALL))
return 0;
- /*
- * Do not consider thread group leaders that are
- * in a non-empty thread group:
- */
- if (delay_group_leader(p))
- return 2;
err = security_task_wait(p);
- if (err)
- return err;
+ if (likely(!err))
+ return 1;
- return 1;
+ if (type != PIDTYPE_PID)
+ return 0;
+ /* This child was explicitly requested, abort */
+ read_unlock(&tasklist_lock);
+ return err;
}
static int wait_noreap_copyout(struct task_struct *p, pid_t pid, uid_t uid,
{
unsigned long state;
int retval, status, traced;
- struct pid_namespace *ns;
-
- ns = current->nsproxy->pid_ns;
+ pid_t pid = task_pid_vnr(p);
if (unlikely(noreap)) {
- pid_t pid = task_pid_nr_ns(p, ns);
uid_t uid = p->uid;
int exit_code = p->exit_code;
int why, status;
- if (unlikely(p->exit_state != EXIT_ZOMBIE))
- return 0;
- if (unlikely(p->exit_signal == -1 && p->ptrace == 0))
- return 0;
get_task_struct(p);
read_unlock(&tasklist_lock);
if ((exit_code & 0x7f) == 0) {
retval = put_user(status, &infop->si_status);
}
if (!retval && infop)
- retval = put_user(task_pid_nr_ns(p, ns), &infop->si_pid);
+ retval = put_user(pid, &infop->si_pid);
if (!retval && infop)
retval = put_user(p->uid, &infop->si_uid);
if (!retval)
- retval = task_pid_nr_ns(p, ns);
+ retval = pid;
if (traced) {
write_lock_irq(&tasklist_lock);
* the lock and this task is uninteresting. If we return nonzero, we have
* released the lock and the system call should return.
*/
-static int wait_task_stopped(struct task_struct *p, int delayed_group_leader,
+static int wait_task_stopped(struct task_struct *p,
int noreap, struct siginfo __user *infop,
int __user *stat_addr, struct rusage __user *ru)
{
- int retval, exit_code;
+ int retval, exit_code, why;
+ uid_t uid = 0; /* unneeded, required by compiler */
pid_t pid;
- if (!p->exit_code)
- return 0;
- if (delayed_group_leader && !(p->ptrace & PT_PTRACED) &&
- p->signal->group_stop_count > 0)
+ exit_code = 0;
+ spin_lock_irq(&p->sighand->siglock);
+
+ if (unlikely(!task_is_stopped_or_traced(p)))
+ goto unlock_sig;
+
+ if (!(p->ptrace & PT_PTRACED) && p->signal->group_stop_count > 0)
/*
* A group stop is in progress and this is the group leader.
* We won't report until all threads have stopped.
*/
+ goto unlock_sig;
+
+ exit_code = p->exit_code;
+ if (!exit_code)
+ goto unlock_sig;
+
+ if (!noreap)
+ p->exit_code = 0;
+
+ uid = p->uid;
+unlock_sig:
+ spin_unlock_irq(&p->sighand->siglock);
+ if (!exit_code)
return 0;
/*
* keep holding onto the tasklist_lock while we call getrusage and
* possibly take page faults for user memory.
*/
- pid = task_pid_nr_ns(p, current->nsproxy->pid_ns);
get_task_struct(p);
+ pid = task_pid_vnr(p);
+ why = (p->ptrace & PT_PTRACED) ? CLD_TRAPPED : CLD_STOPPED;
read_unlock(&tasklist_lock);
- if (unlikely(noreap)) {
- uid_t uid = p->uid;
- int why = (p->ptrace & PT_PTRACED) ? CLD_TRAPPED : CLD_STOPPED;
-
- exit_code = p->exit_code;
- if (unlikely(!exit_code) || unlikely(p->exit_state))
- goto bail_ref;
+ if (unlikely(noreap))
return wait_noreap_copyout(p, pid, uid,
why, exit_code,
infop, ru);
- }
-
- write_lock_irq(&tasklist_lock);
-
- /*
- * This uses xchg to be atomic with the thread resuming and setting
- * it. It must also be done with the write lock held to prevent a
- * race with the EXIT_ZOMBIE case.
- */
- exit_code = xchg(&p->exit_code, 0);
- if (unlikely(p->exit_state)) {
- /*
- * The task resumed and then died. Let the next iteration
- * catch it in EXIT_ZOMBIE. Note that exit_code might
- * already be zero here if it resumed and did _exit(0).
- * The task itself is dead and won't touch exit_code again;
- * other processors in this function are locked out.
- */
- p->exit_code = exit_code;
- exit_code = 0;
- }
- if (unlikely(exit_code == 0)) {
- /*
- * Another thread in this function got to it first, or it
- * resumed, or it resumed and then died.
- */
- write_unlock_irq(&tasklist_lock);
-bail_ref:
- put_task_struct(p);
- /*
- * We are returning to the wait loop without having successfully
- * removed the process and having released the lock. We cannot
- * continue, since the "p" task pointer is potentially stale.
- *
- * Return -EAGAIN, and do_wait() will restart the loop from the
- * beginning. Do _not_ re-acquire the lock.
- */
- return -EAGAIN;
- }
-
- /* move to end of parent's list to avoid starvation */
- remove_parent(p);
- add_parent(p);
-
- write_unlock_irq(&tasklist_lock);
retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0;
if (!retval && stat_addr)
if (!retval && infop)
retval = put_user(0, &infop->si_errno);
if (!retval && infop)
- retval = put_user((short)((p->ptrace & PT_PTRACED)
- ? CLD_TRAPPED : CLD_STOPPED),
- &infop->si_code);
+ retval = put_user((short)why, &infop->si_code);
if (!retval && infop)
retval = put_user(exit_code, &infop->si_status);
if (!retval && infop)
retval = put_user(pid, &infop->si_pid);
if (!retval && infop)
- retval = put_user(p->uid, &infop->si_uid);
+ retval = put_user(uid, &infop->si_uid);
if (!retval)
retval = pid;
put_task_struct(p);
int retval;
pid_t pid;
uid_t uid;
- struct pid_namespace *ns;
if (!(p->signal->flags & SIGNAL_STOP_CONTINUED))
return 0;
p->signal->flags &= ~SIGNAL_STOP_CONTINUED;
spin_unlock_irq(&p->sighand->siglock);
- ns = current->nsproxy->pid_ns;
- pid = task_pid_nr_ns(p, ns);
+ pid = task_pid_vnr(p);
uid = p->uid;
get_task_struct(p);
read_unlock(&tasklist_lock);
if (!retval && stat_addr)
retval = put_user(0xffff, stat_addr);
if (!retval)
- retval = task_pid_nr_ns(p, ns);
+ retval = pid;
} else {
retval = wait_noreap_copyout(p, pid, uid,
CLD_CONTINUED, SIGCONT,
return retval;
}
-
-static inline int my_ptrace_child(struct task_struct *p)
-{
- if (!(p->ptrace & PT_PTRACED))
- return 0;
- if (!(p->ptrace & PT_ATTACHED))
- return 1;
- /*
- * This child was PTRACE_ATTACH'd. We should be seeing it only if
- * we are the attacher. If we are the real parent, this is a race
- * inside ptrace_attach. It is waiting for the tasklist_lock,
- * which we have to switch the parent links, but has already set
- * the flags in p->ptrace.
- */
- return (p->parent != p->real_parent);
-}
-
-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;
int flag, retval;
- int allowed, denied;
add_wait_queue(¤t->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.
*/
- flag = 0;
- allowed = denied = 0;
+ flag = retval = 0;
current->state = TASK_INTERRUPTIBLE;
read_lock(&tasklist_lock);
tsk = current;
do {
struct task_struct *p;
- int ret;
list_for_each_entry(p, &tsk->children, sibling) {
- ret = eligible_child(pid, options, p);
+ int ret = eligible_child(type, pid, options, p);
if (!ret)
continue;
if (unlikely(ret < 0)) {
- denied = ret;
- continue;
- }
- allowed = 1;
-
- if (task_is_stopped_or_traced(p)) {
+ retval = ret;
+ } else if (task_is_stopped_or_traced(p)) {
/*
* It's stopped now, so it might later
* continue, exit, or stop again.
- *
- * When we hit the race with PTRACE_ATTACH, we
- * will not report this child. But the race
- * means it has not yet been moved to our
- * ptrace_children list, so we need to set the
- * flag here to avoid a spurious ECHILD when
- * the race happens with the only child.
*/
flag = 1;
+ if (!(p->ptrace & PT_PTRACED) &&
+ !(options & WUNTRACED))
+ continue;
- if (!my_ptrace_child(p)) {
- if (task_is_traced(p))
- continue;
- if (!(options & WUNTRACED))
- continue;
- }
-
- retval = wait_task_stopped(p, ret == 2,
+ retval = wait_task_stopped(p,
(options & WNOWAIT), infop,
stat_addr, ru);
- if (retval == -EAGAIN)
- goto repeat;
- if (retval != 0) /* He released the lock. */
- goto end;
- } else if (p->exit_state == EXIT_ZOMBIE) {
+ } else if (p->exit_state == EXIT_ZOMBIE &&
+ !delay_group_leader(p)) {
/*
- * Eligible but we cannot release it yet:
+ * We don't reap group leaders with subthreads.
*/
- if (ret == 2)
- goto check_continued;
if (!likely(options & WEXITED))
continue;
retval = wait_task_zombie(p,
(options & WNOWAIT), infop,
stat_addr, ru);
- /* He released the lock. */
- if (retval != 0)
- goto end;
} else if (p->exit_state != EXIT_DEAD) {
-check_continued:
/*
* It's running now, so it might later
* exit, stop, or stop and then continue.
retval = wait_task_continued(p,
(options & WNOWAIT), infop,
stat_addr, ru);
- if (retval != 0) /* He released the lock. */
- goto end;
}
+ if (retval != 0) /* tasklist_lock released */
+ goto end;
}
if (!flag) {
list_for_each_entry(p, &tsk->ptrace_children,
- ptrace_list) {
- if (!eligible_child(pid, options, p))
+ ptrace_list) {
+ flag = eligible_child(type, pid, options, p);
+ if (!flag)
continue;
- flag = 1;
- break;
+ if (likely(flag > 0))
+ break;
+ retval = flag;
+ goto end;
}
}
if (options & __WNOTHREAD)
tsk = next_thread(tsk);
BUG_ON(tsk->signal != current->signal);
} while (tsk != current);
-
read_unlock(&tasklist_lock);
+
if (flag) {
- retval = 0;
if (options & WNOHANG)
goto end;
retval = -ERESTARTSYS;
goto repeat;
}
retval = -ECHILD;
- if (unlikely(denied) && !allowed)
- retval = denied;
end:
current->state = TASK_RUNNING;
remove_wait_queue(¤t->signal->wait_chldexit,&wait);
if (infop) {
if (retval > 0)
- retval = 0;
+ retval = 0;
else {
/*
* For a WNOHANG return, clear out all the fields
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))
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);