VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / kernel / exit.c
index 96d7394..8c5742e 100644 (file)
 #include <linux/profile.h>
 #include <linux/mount.h>
 #include <linux/proc_fs.h>
+#include <linux/mempolicy.h>
+#include <linux/vs_limit.h>
 
 #include <asm/uaccess.h>
+#include <asm/unistd.h>
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
 
 extern void sem_exit (void);
 extern struct task_struct *child_reaper;
 
-int getrusage(struct task_struct *, int, struct rusage *);
+int getrusage(struct task_struct *, int, struct rusage __user *);
 
 static void __unhash_process(struct task_struct *p)
 {
        nr_threads--;
+       /* tasklist_lock is held, is this sufficient? */
+       if (p->vx_info) {
+               atomic_dec(&p->vx_info->cacct.nr_threads);
+               atomic_dec(&p->vx_info->limit.rcur[RLIMIT_NPROC]);
+       }
        detach_pid(p, PIDTYPE_PID);
        detach_pid(p, PIDTYPE_TGID);
        if (thread_group_leader(p)) {
@@ -234,6 +242,7 @@ void reparent_to_init(void)
        ptrace_unlink(current);
        /* Reparent to init */
        REMOVE_LINKS(current);
+       /* FIXME handle vchild_reaper/initpid */
        current->parent = child_reaper;
        current->real_parent = child_reaper;
        SET_LINKS(current);
@@ -294,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);
@@ -378,6 +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);
                        }
                        i++;
                        set >>= 1;
@@ -592,11 +602,13 @@ 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;
 
+       /* FIXME handle vchild_reaper/initpid */
        reaper = father->group_leader;
        if (reaper == father)
                reaper = child_reaper;
@@ -610,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);
@@ -636,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)) {
@@ -671,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
@@ -734,6 +767,14 @@ static void exit_notify(struct task_struct *tsk)
        tsk->state = state;
        tsk->flags |= PF_DEAD;
 
+       /*
+        * Clear these here so that update_process_times() won't try to deliver
+        * itimer, profile or rlimit signals to this task while it is in late exit.
+        */
+       tsk->it_virt_value = 0;
+       tsk->it_prof_value = 0;
+       tsk->rlim[RLIMIT_CPU].rlim_cur = RLIM_INFINITY;
+
        /*
         * In the preemption case it must be impossible for the task
         * to get runnable again, so use "_raw_" unlock to keep
@@ -749,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);
@@ -800,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".  */
@@ -821,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)
@@ -931,7 +982,7 @@ static int eligible_child(pid_t pid, int options, task_t *p)
  * 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_zombie(task_t *p, unsigned int *stat_addr, struct rusage *ru)
+static int wait_task_zombie(task_t *p, unsigned int __user *stat_addr, struct rusage __user *ru)
 {
        unsigned long state;
        int retval;
@@ -976,20 +1027,17 @@ static int wait_task_zombie(task_t *p, unsigned int *stat_addr, struct rusage *r
                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);
@@ -1004,7 +1052,8 @@ static int wait_task_zombie(task_t *p, unsigned int *stat_addr, struct rusage *r
  * released the lock and the system call should return.
  */
 static int wait_task_stopped(task_t *p, int delayed_group_leader,
-                            unsigned int *stat_addr, struct rusage *ru)
+                            unsigned int __user *stat_addr,
+                            struct rusage __user *ru)
 {
        int retval, exit_code;
 
@@ -1074,7 +1123,7 @@ static int wait_task_stopped(task_t *p, int delayed_group_leader,
        return retval;
 }
 
-asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru)
+asmlinkage long sys_wait4(pid_t pid,unsigned int __user *stat_addr, int options, struct rusage __user *ru)
 {
        DECLARE_WAITQUEUE(wait, current);
        struct task_struct *tsk;
@@ -1157,14 +1206,13 @@ end_wait4:
        return retval;
 }
 
-#if !defined(__alpha__) && !defined(__ia64__) && \
-    !defined(__arm__) && !defined(__s390__)
+#ifdef __ARCH_WANT_SYS_WAITPID
 
 /*
  * sys_waitpid() remains for compatibility. waitpid() should be
  * implemented by calling sys_wait4() from libc.a.
  */
-asmlinkage long sys_waitpid(pid_t pid,unsigned int * stat_addr, int options)
+asmlinkage long sys_waitpid(pid_t pid, unsigned __user *stat_addr, int options)
 {
        return sys_wait4(pid, stat_addr, options, NULL);
 }