Merge to Fedora kernel-2.6.7-1.492
[linux-2.6.git] / kernel / exit.c
index 979c5d4..8ec87d0 100644 (file)
@@ -109,7 +109,7 @@ repeat:
        sched_exit(p);
        write_unlock_irq(&tasklist_lock);
        spin_unlock(&p->proc_lock);
-       proc_pid_flush(proc_dentry);
+       dput(proc_dentry);
        release_thread(p);
        put_task_struct(p);
 
@@ -307,7 +307,7 @@ int allow_signal(int sig)
                   Let the signal code know it'll be handled, so
                   that they don't get converted to SIGKILL or
                   just silently dropped */
-               current->sighand->action[(sig)-1].sa.sa_handler = (void *)2;
+               current->sighand->action[(sig)-1].sa.sa_handler = (void __user *)2;
        }
        recalc_sigpending();
        spin_unlock_irq(&current->sighand->siglock);
@@ -389,9 +389,13 @@ static inline void close_files(struct files_struct * files)
                while (set) {
                        if (set & 1) {
                                struct file * file = xchg(&files->fd[i], NULL);
-                               if (file)
+                               if (file) {
                                        filp_close(file, files);
-                               vx_openfd_dec(fd);
+                                       vx_openfd_dec(fd);
+                                       cond_resched();
+                               } else {
+                                       vx_openfd_dec(fd);
+                               }
                        }
                        i++;
                        set >>= 1;
@@ -606,7 +610,8 @@ static inline void reparent_thread(task_t *p, task_t *father, int traced)
  * group, and if no such member exists, give it to
  * the global child reaper process (ie "init")
  */
-static inline void forget_original_parent(struct task_struct * father)
+static inline void forget_original_parent(struct task_struct * father,
+                                         struct list_head *to_release)
 {
        struct task_struct *p, *reaper = father;
        struct list_head *_p, *_n;
@@ -625,16 +630,34 @@ static inline void forget_original_parent(struct task_struct * father)
         * Search them and reparent children.
         */
        list_for_each_safe(_p, _n, &father->children) {
+               int ptrace;
                p = list_entry(_p,struct task_struct,sibling);
+
+               ptrace = p->ptrace;
+
+               /* if father isn't the real parent, then ptrace must be enabled */
+               BUG_ON(father != p->real_parent && !ptrace);
+
                if (father == p->real_parent) {
+                       /* reparent with a reaper, real father it's us */
                        choose_new_parent(p, reaper, child_reaper);
                        reparent_thread(p, father, 0);
                } else {
-                       ptrace_unlink (p);
+                       /* reparent ptraced task to its real parent */
+                       __ptrace_unlink (p);
                        if (p->state == TASK_ZOMBIE && p->exit_signal != -1 &&
                            thread_group_empty(p))
                                do_notify_parent(p, p->exit_signal);
                }
+
+               /*
+                * if the ptraced child is a zombie with exit_signal == -1
+                * we must collect it before we exit, or it will remain
+                * zombie forever since we prevented it from self-reap itself
+                * while it was being traced by us, to be able to see it in wait4.
+                */
+               if (unlikely(ptrace && p->state == TASK_ZOMBIE && p->exit_signal == -1))
+                       list_add(&p->ptrace_list, to_release);
        }
        list_for_each_safe(_p, _n, &father->ptrace_children) {
                p = list_entry(_p,struct task_struct,ptrace_list);
@@ -651,6 +674,7 @@ static void exit_notify(struct task_struct *tsk)
 {
        int state;
        struct task_struct *t;
+       struct list_head ptrace_dead, *_p, *_n;
 
        ckrm_cb_exit(tsk);
 
@@ -688,8 +712,10 @@ static void exit_notify(struct task_struct *tsk)
         *      jobs, send them a SIGHUP and then a SIGCONT.  (POSIX 3.2.2.2)
         */
 
-       forget_original_parent(tsk);
+       INIT_LIST_HEAD(&ptrace_dead);
+       forget_original_parent(tsk, &ptrace_dead);
        BUG_ON(!list_empty(&tsk->children));
+       BUG_ON(!list_empty(&tsk->ptrace_children));
 
        /*
         * Check to see if any process groups have become orphaned
@@ -774,6 +800,12 @@ static void exit_notify(struct task_struct *tsk)
        _raw_write_unlock(&tasklist_lock);
        local_irq_enable();
 
+       list_for_each_safe(_p, _n, &ptrace_dead) {
+               list_del_init(_p);
+               t = list_entry(_p,struct task_struct,ptrace_list);
+               release_task(t);
+       }
+
        /* If the process is dead, release it - nobody will wait for it */
        if (state == TASK_DEAD)
                release_task(tsk);
@@ -808,13 +840,6 @@ asmlinkage NORET_TYPE void do_exit(long code)
        }
 
        acct_process(code);
-       if (current->tux_info) {
-#ifdef CONFIG_TUX_DEBUG
-               printk("Possibly unexpected TUX-thread exit(%ld) at %p?\n",
-                       code, __builtin_return_address(0));
-#endif
-               current->tux_exit();
-       }
        __exit_mm(tsk);
 
        exit_sem(tsk);
@@ -822,9 +847,6 @@ asmlinkage NORET_TYPE void do_exit(long code)
        __exit_fs(tsk);
        exit_namespace(tsk);
        exit_thread();
-#ifdef CONFIG_NUMA
-       mpol_free(tsk->mempolicy);
-#endif
 
        if (tsk->signal->leader)
                disassociate_ctty(1);
@@ -838,6 +860,10 @@ asmlinkage NORET_TYPE void do_exit(long code)
        numtasks_put_ref(tsk->taskclass);
 #endif
        exit_notify(tsk);
+#ifdef CONFIG_NUMA
+       mpol_free(tsk->mempolicy);
+       tsk->mempolicy = NULL;
+#endif
        schedule();
        BUG();
        /* Avoid "noreturn function does return".  */