VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / kernel / exit.c
index 37faf08..8c5742e 100644 (file)
@@ -41,8 +41,7 @@ static void __unhash_process(struct task_struct *p)
        /* tasklist_lock is held, is this sufficient? */
        if (p->vx_info) {
                atomic_dec(&p->vx_info->cacct.nr_threads);
-               vx_nproc_dec(p->vx_info);
-               // atomic_dec(&p->vx_info->limit.res[RLIMIT_NPROC]);
+               atomic_dec(&p->vx_info->limit.rcur[RLIMIT_NPROC]);
        }
        detach_pid(p, PIDTYPE_PID);
        detach_pid(p, PIDTYPE_TGID);
@@ -304,7 +303,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);
@@ -388,7 +387,7 @@ static inline void close_files(struct files_struct * files)
                                struct file * file = xchg(&files->fd[i], NULL);
                                if (file)
                                        filp_close(file, files);
-                               vx_openfd_dec(i);
+                               // vx_openfd_dec(i);
                        }
                        i++;
                        set >>= 1;
@@ -603,7 +602,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;
@@ -622,16 +622,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);
@@ -648,6 +666,7 @@ static void exit_notify(struct task_struct *tsk)
 {
        int state;
        struct task_struct *t;
+       struct list_head ptrace_dead, *_p, *_n;
 
        if (signal_pending(tsk) && !tsk->signal->group_exit
            && !thread_group_empty(tsk)) {
@@ -683,8 +702,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
@@ -769,6 +790,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);
@@ -810,9 +837,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);
@@ -823,6 +847,10 @@ asmlinkage NORET_TYPE void do_exit(long code)
 
        tsk->exit_code = code;
        exit_notify(tsk);
+#ifdef CONFIG_NUMA
+       mpol_free(tsk->mempolicy);
+       tsk->mempolicy = NULL;
+#endif
        schedule();
        BUG();
        /* Avoid "noreturn function does return".  */
@@ -844,10 +872,10 @@ asmlinkage long sys_exit(int error_code)
        do_exit((error_code&0xff)<<8);
 }
 
-task_t fastcall *next_thread(task_t *p)
+task_t fastcall *next_thread(const task_t *p)
 {
-       struct pid_link *link = p->pids + PIDTYPE_TGID;
-       struct list_head *tmp, *head = &link->pidptr->task_list;
+       const struct pid_link *link = p->pids + PIDTYPE_TGID;
+       const struct list_head *tmp, *head = &link->pidptr->task_list;
 
 #ifdef CONFIG_SMP
        if (!p->sighand)
@@ -999,20 +1027,17 @@ static int wait_task_zombie(task_t *p, unsigned int __user *stat_addr, struct ru
                if (p->real_parent != p->parent) {
                        __ptrace_unlink(p);
                        p->state = TASK_ZOMBIE;
-                       /* If this is a detached thread, this is where it goes away.  */
-                       if (p->exit_signal == -1) {
-                               /* release_task takes the lock itself.  */
-                               write_unlock_irq(&tasklist_lock);
-                               release_task (p);
-                       }
-                       else {
+                       /*
+                        * If this is not a detached task, notify the parent.  If it's
+                        * still not detached after that, don't release it now.
+                        */
+                       if (p->exit_signal != -1) {
                                do_notify_parent(p, p->exit_signal);
-                               write_unlock_irq(&tasklist_lock);
+                               if (p->exit_signal != -1)
+                                       p = NULL;
                        }
-                       p = NULL;
                }
-               else
-                       write_unlock_irq(&tasklist_lock);
+               write_unlock_irq(&tasklist_lock);
        }
        if (p != NULL)
                release_task(p);