Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
[sfrench/cifs-2.6.git] / kernel / exit.c
index ee607720ae587490d0987ce27b62161b26c71226..53872bf993fa79d46b6e252db4f393c6a3e6828f 100644 (file)
@@ -214,20 +214,19 @@ struct pid *session_of_pgrp(struct pid *pgrp)
 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)
@@ -255,6 +254,37 @@ static int has_stopped_jobs(struct pid *pgrp)
        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
  *
@@ -293,26 +323,27 @@ static void reparent_to_kthreadd(void)
        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);
 }
 
@@ -383,7 +414,11 @@ void daemonize(const char *name, ...)
         */
        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 */
@@ -398,11 +433,6 @@ void daemonize(const char *name, ...)
        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(&current->files->count);
@@ -458,7 +488,7 @@ struct files_struct *get_files_struct(struct task_struct *task)
        return files;
 }
 
-void fastcall put_files_struct(struct files_struct *files)
+void put_files_struct(struct files_struct *files)
 {
        struct fdtable *fdt;
 
@@ -512,14 +542,10 @@ static void __put_fs_struct(struct fs_struct *fs)
 {
        /* 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);
        }
 }
@@ -639,22 +665,7 @@ reparent_thread(struct task_struct *p, struct task_struct *father, int traced)
            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);
 }
 
 /*
@@ -739,29 +750,9 @@ static void forget_original_parent(struct task_struct *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:
@@ -775,25 +766,8 @@ static void exit_notify(struct task_struct *tsk)
        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
         *
@@ -810,8 +784,8 @@ static void exit_notify(struct task_struct *tsk)
         * 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;
 
@@ -905,7 +879,7 @@ static inline void exit_child_reaper(struct task_struct *tsk)
        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;
@@ -947,7 +921,7 @@ fastcall NORET_TYPE void do_exit(long code)
                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.
@@ -1008,7 +982,7 @@ fastcall NORET_TYPE void do_exit(long code)
                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;
@@ -1108,20 +1082,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;
        }
 
@@ -1145,7 +1122,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);
@@ -1189,20 +1166,13 @@ static int wait_task_zombie(struct task_struct *p, int noreap,
 {
        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) {
@@ -1313,11 +1283,11 @@ static int wait_task_zombie(struct task_struct *p, int noreap,
                        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);
@@ -1391,7 +1361,7 @@ unlock_sig:
         * possibly take page faults for user memory.
         */
        get_task_struct(p);
-       pid = task_pid_nr_ns(p, current->nsproxy->pid_ns);
+       pid = task_pid_vnr(p);
        why = (p->ptrace & PT_PTRACED) ? CLD_TRAPPED : CLD_STOPPED;
        read_unlock(&tasklist_lock);
 
@@ -1408,7 +1378,7 @@ unlock_sig:
        if (!retval && infop)
                retval = put_user(0, &infop->si_errno);
        if (!retval && infop)
-               retval = put_user(why, &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)
@@ -1436,7 +1406,6 @@ static int wait_task_continued(struct task_struct *p, int noreap,
        int retval;
        pid_t pid;
        uid_t uid;
-       struct pid_namespace *ns;
 
        if (!(p->signal->flags & SIGNAL_STOP_CONTINUED))
                return 0;
@@ -1451,8 +1420,7 @@ static int wait_task_continued(struct task_struct *p, int noreap,
                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);
@@ -1463,7 +1431,7 @@ static int wait_task_continued(struct task_struct *p, int noreap,
                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,
@@ -1474,8 +1442,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;
@@ -1483,6 +1452,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.
@@ -1495,7 +1469,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;
 
@@ -1542,7 +1516,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))
@@ -1597,10 +1571,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))
@@ -1610,37 +1586,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);