X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=kernel%2Fexit.c;h=8c5742ebb904679546b825b47c74bba1ac92a769;hb=9bf4aaab3e101692164d49b7ca357651eb691cb6;hp=9b652d8628da5a9899c38d7a6091a0c96a8f060f;hpb=a8e794ca871505c8ea96cc102f4ad555c5231d7f;p=linux-2.6.git diff --git a/kernel/exit.c b/kernel/exit.c index 9b652d862..8c5742ebb 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -22,15 +22,18 @@ #include #include #include +#include +#include #include +#include #include #include 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) { @@ -38,7 +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); - 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); @@ -300,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(¤t->sighand->siglock); @@ -384,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(fd); + // vx_openfd_dec(i); } i++; set >>= 1; @@ -599,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; @@ -618,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); @@ -644,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)) { @@ -679,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 @@ -742,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 @@ -757,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); @@ -808,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". */ @@ -829,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) @@ -939,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; @@ -984,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); @@ -1012,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; @@ -1082,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; @@ -1165,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); }