X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=kernel%2Fexit.c;h=549c0558ba68273c7586b26f6579d12c27d0f79d;hb=5cd17569fd0eeca510735e63a6061291e3971bf6;hp=993369ee94d1ebb8d4c7675a821e90abf8a1737e;hpb=b160292cc216a50fd0cd386b0bda2cd48352c73b;p=linux-2.6 diff --git a/kernel/exit.c b/kernel/exit.c index 993369ee94..549c0558ba 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include @@ -44,7 +44,6 @@ #include #include #include -#include #include #include @@ -93,10 +92,9 @@ static void __exit_signal(struct task_struct *tsk) * If there is any task waiting for the group exit * then notify it: */ - if (sig->group_exit_task && atomic_read(&sig->count) == sig->notify_count) { + if (sig->group_exit_task && atomic_read(&sig->count) == sig->notify_count) wake_up_process(sig->group_exit_task); - sig->group_exit_task = NULL; - } + if (tsk == sig->curr_target) sig->curr_target = next_thread(tsk); /* @@ -111,6 +109,7 @@ static void __exit_signal(struct task_struct *tsk) */ sig->utime = cputime_add(sig->utime, tsk->utime); sig->stime = cputime_add(sig->stime, tsk->stime); + sig->gtime = cputime_add(sig->gtime, tsk->gtime); sig->min_flt += tsk->min_flt; sig->maj_flt += tsk->maj_flt; sig->nvcsw += tsk->nvcsw; @@ -149,6 +148,7 @@ void release_task(struct task_struct * p) int zap_leader; repeat: atomic_dec(&p->user->processes); + proc_flush_task(p); write_lock_irq(&tasklist_lock); ptrace_unlink(p); BUG_ON(!list_empty(&p->ptrace_list) || !list_empty(&p->ptrace_children)); @@ -176,7 +176,6 @@ repeat: } write_unlock_irq(&tasklist_lock); - proc_flush_task(p); release_thread(p); call_rcu(&p->rcu, delayed_put_task_struct); @@ -222,7 +221,7 @@ static int will_become_orphaned_pgrp(struct pid *pgrp, struct task_struct *ignor do_each_pid_task(pgrp, PIDTYPE_PGID, p) { if (p == ignored_task || p->exit_state - || is_init(p->real_parent)) + || is_global_init(p->real_parent)) continue; if (task_pgrp(p->real_parent) != pgrp && task_session(p->real_parent) == task_session(p)) { @@ -300,14 +299,14 @@ void __set_special_pids(pid_t session, pid_t pgrp) { struct task_struct *curr = current->group_leader; - if (process_session(curr) != session) { + if (task_session_nr(curr) != session) { detach_pid(curr, PIDTYPE_SID); - set_signal_session(curr->signal, session); + set_task_session(curr, session); attach_pid(curr, PIDTYPE_SID, find_pid(session)); } - if (process_group(curr) != pgrp) { + if (task_pgrp_nr(curr) != pgrp) { detach_pid(curr, PIDTYPE_PGID); - curr->signal->pgrp = pgrp; + set_task_pgrp(curr, pgrp); attach_pid(curr, PIDTYPE_PGID, find_pid(pgrp)); } } @@ -401,11 +400,12 @@ void daemonize(const char *name, ...) current->fs = fs; atomic_inc(&fs->count); - exit_task_namespaces(current); - current->nsproxy = init_task.nsproxy; - get_task_namespaces(current); + if (current->nsproxy != init_task.nsproxy) { + get_nsproxy(init_task.nsproxy); + switch_task_namespaces(current, init_task.nsproxy); + } - exit_files(current); + exit_files(current); current->files = init_task.files; atomic_inc(¤t->files->count); @@ -493,7 +493,7 @@ void reset_files_struct(struct task_struct *tsk, struct files_struct *files) } EXPORT_SYMBOL(reset_files_struct); -static inline void __exit_files(struct task_struct *tsk) +static void __exit_files(struct task_struct *tsk) { struct files_struct * files = tsk->files; @@ -510,7 +510,7 @@ void exit_files(struct task_struct *tsk) __exit_files(tsk); } -static inline void __put_fs_struct(struct fs_struct *fs) +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)) { @@ -531,7 +531,7 @@ void put_fs_struct(struct fs_struct *fs) __put_fs_struct(fs); } -static inline void __exit_fs(struct task_struct *tsk) +static void __exit_fs(struct task_struct *tsk) { struct fs_struct * fs = tsk->fs; @@ -592,17 +592,6 @@ static void exit_mm(struct task_struct * tsk) mmput(mm); } -static inline void -choose_new_parent(struct task_struct *p, struct task_struct *reaper) -{ - /* - * Make sure we're not reparenting to ourselves and that - * the parent is not a zombie. - */ - BUG_ON(p == reaper || reaper->exit_state); - p->real_parent = reaper; -} - static void reparent_thread(struct task_struct *p, struct task_struct *father, int traced) { @@ -677,19 +666,22 @@ reparent_thread(struct task_struct *p, struct task_struct *father, int traced) * the child reaper process (ie "init") in our pid * space. */ -static void -forget_original_parent(struct task_struct *father, struct list_head *to_release) +static void forget_original_parent(struct task_struct *father) { - struct task_struct *p, *reaper = father; - struct list_head *_p, *_n; + struct task_struct *p, *n, *reaper = father; + struct list_head ptrace_dead; + + INIT_LIST_HEAD(&ptrace_dead); + + write_lock_irq(&tasklist_lock); do { reaper = next_thread(reaper); if (reaper == father) { - reaper = child_reaper(father); + reaper = task_child_reaper(father); break; } - } while (reaper->exit_state); + } while (reaper->flags & PF_EXITING); /* * There are only two places where our children can be: @@ -699,9 +691,8 @@ forget_original_parent(struct task_struct *father, struct list_head *to_release) * * Search them and reparent children. */ - list_for_each_safe(_p, _n, &father->children) { + list_for_each_entry_safe(p, n, &father->children, sibling) { int ptrace; - p = list_entry(_p, struct task_struct, sibling); ptrace = p->ptrace; @@ -710,7 +701,7 @@ forget_original_parent(struct task_struct *father, struct list_head *to_release) if (father == p->real_parent) { /* reparent with a reaper, real father it's us */ - choose_new_parent(p, reaper); + p->real_parent = reaper; reparent_thread(p, father, 0); } else { /* reparent ptraced task to its real parent */ @@ -727,13 +718,23 @@ forget_original_parent(struct task_struct *father, struct list_head *to_release) * while it was being traced by us, to be able to see it in wait4. */ if (unlikely(ptrace && p->exit_state == EXIT_ZOMBIE && p->exit_signal == -1)) - list_add(&p->ptrace_list, to_release); + list_add(&p->ptrace_list, &ptrace_dead); } - list_for_each_safe(_p, _n, &father->ptrace_children) { - p = list_entry(_p, struct task_struct, ptrace_list); - choose_new_parent(p, reaper); + + list_for_each_entry_safe(p, n, &father->ptrace_children, ptrace_list) { + p->real_parent = reaper; reparent_thread(p, father, 1); } + + write_unlock_irq(&tasklist_lock); + BUG_ON(!list_empty(&father->children)); + BUG_ON(!list_empty(&father->ptrace_children)); + + list_for_each_entry_safe(p, n, &ptrace_dead, ptrace_list) { + list_del_init(&p->ptrace_list); + release_task(p); + } + } /* @@ -744,7 +745,6 @@ static void exit_notify(struct task_struct *tsk) { int state; struct task_struct *t; - struct list_head ptrace_dead, *_p, *_n; struct pid *pgrp; if (signal_pending(tsk) && !(tsk->signal->flags & SIGNAL_GROUP_EXIT) @@ -758,17 +758,13 @@ static void exit_notify(struct task_struct *tsk) * Now we'll wake all the threads in the group just to make * sure someone gets all the pending signals. */ - read_lock(&tasklist_lock); 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); - read_unlock(&tasklist_lock); } - write_lock_irq(&tasklist_lock); - /* * This does two things: * @@ -777,12 +773,10 @@ static void exit_notify(struct task_struct *tsk) * 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) */ + forget_original_parent(tsk); + exit_task_namespaces(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)); - + 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 @@ -792,9 +786,8 @@ static void exit_notify(struct task_struct *tsk) * 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)) && @@ -807,7 +800,7 @@ static void exit_notify(struct task_struct *tsk) /* Let father know we died * * Thread signals are configurable, but you aren't going to use - * that to send signals to arbitary processes. + * that to send signals to arbitary processes. * That stops right now. * * If the parent exec id doesn't match the exec id we saved @@ -841,13 +834,12 @@ static void exit_notify(struct task_struct *tsk) state = EXIT_DEAD; tsk->exit_state = state; - write_unlock_irq(&tasklist_lock); + if (thread_group_leader(tsk) && + tsk->signal->notify_count < 0 && + tsk->signal->group_exit_task) + wake_up_process(tsk->signal->group_exit_task); - list_for_each_safe(_p, _n, &ptrace_dead) { - list_del_init(_p); - t = list_entry(_p, struct task_struct, ptrace_list); - release_task(t); - } + write_unlock_irq(&tasklist_lock); /* If the process is dead, release it - nobody will wait for it */ if (state == EXIT_DEAD) @@ -882,6 +874,39 @@ static void check_stack_usage(void) static inline void check_stack_usage(void) {} #endif +static inline void exit_child_reaper(struct task_struct *tsk) +{ + if (likely(tsk->group_leader != task_child_reaper(tsk))) + return; + + if (tsk->nsproxy->pid_ns == &init_pid_ns) + panic("Attempted to kill init!"); + + /* + * @tsk is the last thread in the 'cgroup-init' and is exiting. + * Terminate all remaining processes in the namespace and reap them + * before exiting @tsk. + * + * Note that @tsk (last thread of cgroup-init) may not necessarily + * be the child-reaper (i.e main thread of cgroup-init) of the + * namespace i.e the child_reaper may have already exited. + * + * Even after a child_reaper exits, we let it inherit orphaned children, + * because, pid_ns->child_reaper remains valid as long as there is + * at least one living sub-thread in the cgroup init. + + * This living sub-thread of the cgroup-init will be notified when + * a child inherited by the 'child-reaper' exits (do_notify_parent() + * uses __group_send_sig_info()). Further, when reaping child processes, + * do_wait() iterates over children of all living sub threads. + + * i.e even though 'child_reaper' thread is listed as the parent of the + * orphaned children, any living sub-thread in the cgroup-init can + * perform the role of the child_reaper. + */ + zap_pid_ns_processes(tsk->nsproxy->pid_ns); +} + fastcall NORET_TYPE void do_exit(long code) { struct task_struct *tsk = current; @@ -895,13 +920,6 @@ fastcall NORET_TYPE void do_exit(long code) panic("Aiee, killing interrupt handler!"); if (unlikely(!tsk->pid)) panic("Attempted to kill the idle task!"); - if (unlikely(tsk == child_reaper(tsk))) { - if (tsk->nsproxy->pid_ns != &init_pid_ns) - tsk->nsproxy->pid_ns->child_reaper = init_pid_ns.child_reaper; - else - panic("Attempted to kill init!"); - } - if (unlikely(current->ptrace & PT_TRACE_EXIT)) { current->ptrace_message = code; @@ -931,17 +949,17 @@ fastcall NORET_TYPE void do_exit(long code) schedule(); } + tsk->flags |= PF_EXITING; /* * tsk->flags are checked in the futex code to protect against * an exiting task cleaning up the robust pi futexes. */ - spin_lock_irq(&tsk->pi_lock); - tsk->flags |= PF_EXITING; - spin_unlock_irq(&tsk->pi_lock); + smp_mb(); + spin_unlock_wait(&tsk->pi_lock); if (unlikely(in_atomic())) printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n", - current->comm, current->pid, + current->comm, task_pid_nr(current), preempt_count()); acct_update_integrals(tsk); @@ -951,15 +969,18 @@ fastcall NORET_TYPE void do_exit(long code) } group_dead = atomic_dec_and_test(&tsk->signal->live); if (group_dead) { + exit_child_reaper(tsk); hrtimer_cancel(&tsk->signal->real_timer); exit_itimers(tsk->signal); } acct_collect(code, group_dead); +#ifdef CONFIG_FUTEX if (unlikely(tsk->robust_list)) exit_robust_list(tsk); -#if defined(CONFIG_FUTEX) && defined(CONFIG_COMPAT) +#ifdef CONFIG_COMPAT if (unlikely(tsk->compat_robust_list)) compat_exit_robust_list(tsk); +#endif #endif if (group_dead) tty_audit_exit(); @@ -978,7 +999,7 @@ fastcall NORET_TYPE void do_exit(long code) __exit_fs(tsk); check_stack_usage(); exit_thread(); - cpuset_exit(tsk); + cgroup_exit(tsk, 1); exit_keys(tsk); if (group_dead && tsk->signal->leader) @@ -989,12 +1010,12 @@ fastcall NORET_TYPE void do_exit(long code) module_put(tsk->binfmt->module); proc_exit_connector(tsk); - exit_task_namespaces(tsk); exit_notify(tsk); #ifdef CONFIG_NUMA mpol_free(tsk->mempolicy); tsk->mempolicy = NULL; #endif +#ifdef CONFIG_FUTEX /* * This must happen late, after the PID is not * hashed anymore: @@ -1003,6 +1024,7 @@ fastcall NORET_TYPE void do_exit(long code) exit_pi_state_list(tsk); if (unlikely(current->pi_state_cache)) kfree(current->pi_state_cache); +#endif /* * Make sure we are holding no locks: */ @@ -1090,15 +1112,17 @@ asmlinkage void sys_exit_group(int error_code) static int eligible_child(pid_t pid, int options, struct task_struct *p) { int err; + struct pid_namespace *ns; + ns = current->nsproxy->pid_ns; if (pid > 0) { - if (p->pid != pid) + if (task_pid_nr_ns(p, ns) != pid) return 0; } else if (!pid) { - if (process_group(p) != process_group(current)) + if (task_pgrp_nr_ns(p, ns) != task_pgrp_vnr(current)) return 0; } else if (pid != -1) { - if (process_group(p) != -pid) + if (task_pgrp_nr_ns(p, ns) != -pid) return 0; } @@ -1167,11 +1191,13 @@ static int wait_task_zombie(struct task_struct *p, int noreap, int __user *stat_addr, struct rusage __user *ru) { unsigned long state; - int retval; - int status; + int retval, status, traced; + struct pid_namespace *ns; + + ns = current->nsproxy->pid_ns; if (unlikely(noreap)) { - pid_t pid = p->pid; + pid_t pid = task_pid_nr_ns(p, ns); uid_t uid = p->uid; int exit_code = p->exit_code; int why, status; @@ -1202,15 +1228,11 @@ static int wait_task_zombie(struct task_struct *p, int noreap, BUG_ON(state != EXIT_DEAD); return 0; } - if (unlikely(p->exit_signal == -1 && p->ptrace == 0)) { - /* - * This can only happen in a race with a ptraced thread - * dying on another processor. - */ - return 0; - } - if (likely(p->real_parent == p->parent) && likely(p->signal)) { + /* traced means p->ptrace, but not vice versa */ + traced = (p->real_parent != p->parent); + + if (likely(!traced)) { struct signal_struct *psig; struct signal_struct *sig; @@ -1242,6 +1264,11 @@ static int wait_task_zombie(struct task_struct *p, int noreap, cputime_add(p->stime, cputime_add(sig->stime, sig->cstime))); + psig->cgtime = + cputime_add(psig->cgtime, + cputime_add(p->gtime, + cputime_add(sig->gtime, + sig->cgtime))); psig->cmin_flt += p->min_flt + sig->min_flt + sig->cmin_flt; psig->cmaj_flt += @@ -1289,38 +1316,33 @@ static int wait_task_zombie(struct task_struct *p, int noreap, retval = put_user(status, &infop->si_status); } if (!retval && infop) - retval = put_user(p->pid, &infop->si_pid); + retval = put_user(task_pid_nr_ns(p, ns), &infop->si_pid); if (!retval && infop) retval = put_user(p->uid, &infop->si_uid); - if (retval) { - // TODO: is this safe? - p->exit_state = EXIT_ZOMBIE; - return retval; - } - retval = p->pid; - if (p->real_parent != p->parent) { + if (!retval) + retval = task_pid_nr_ns(p, ns); + + if (traced) { write_lock_irq(&tasklist_lock); - /* Double-check with lock held. */ - if (p->real_parent != p->parent) { - __ptrace_unlink(p); - // TODO: is this safe? - p->exit_state = EXIT_ZOMBIE; - /* - * If this is not a detached task, notify the parent. - * If it's still not detached after that, don't release - * it now. - */ + /* We dropped tasklist, ptracer could die and untrace */ + ptrace_unlink(p); + /* + * 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); if (p->exit_signal != -1) { - do_notify_parent(p, p->exit_signal); - if (p->exit_signal != -1) - p = NULL; + p->exit_state = EXIT_ZOMBIE; + p = NULL; } } write_unlock_irq(&tasklist_lock); } if (p != NULL) release_task(p); - BUG_ON(!retval); + return retval; } @@ -1335,11 +1357,12 @@ static int wait_task_stopped(struct task_struct *p, int delayed_group_leader, int __user *stat_addr, struct rusage __user *ru) { int retval, exit_code; + pid_t pid; if (!p->exit_code) return 0; if (delayed_group_leader && !(p->ptrace & PT_PTRACED) && - p->signal && p->signal->group_stop_count > 0) + p->signal->group_stop_count > 0) /* * A group stop is in progress and this is the group leader. * We won't report until all threads have stopped. @@ -1353,20 +1376,19 @@ static int wait_task_stopped(struct task_struct *p, int delayed_group_leader, * keep holding onto the tasklist_lock while we call getrusage and * possibly take page faults for user memory. */ + pid = task_pid_nr_ns(p, current->nsproxy->pid_ns); get_task_struct(p); read_unlock(&tasklist_lock); if (unlikely(noreap)) { - pid_t pid = p->pid; uid_t uid = p->uid; int why = (p->ptrace & PT_PTRACED) ? CLD_TRAPPED : CLD_STOPPED; exit_code = p->exit_code; - if (unlikely(!exit_code) || - unlikely(p->state & TASK_TRACED)) + if (unlikely(!exit_code) || unlikely(p->exit_state)) goto bail_ref; return wait_noreap_copyout(p, pid, uid, - why, (exit_code << 8) | 0x7f, + why, exit_code, infop, ru); } @@ -1428,11 +1450,11 @@ bail_ref: if (!retval && infop) retval = put_user(exit_code, &infop->si_status); if (!retval && infop) - retval = put_user(p->pid, &infop->si_pid); + retval = put_user(pid, &infop->si_pid); if (!retval && infop) retval = put_user(p->uid, &infop->si_uid); if (!retval) - retval = p->pid; + retval = pid; put_task_struct(p); BUG_ON(!retval); @@ -1452,9 +1474,7 @@ static int wait_task_continued(struct task_struct *p, int noreap, int retval; pid_t pid; uid_t uid; - - if (unlikely(!p->signal)) - return 0; + struct pid_namespace *ns; if (!(p->signal->flags & SIGNAL_STOP_CONTINUED)) return 0; @@ -1469,7 +1489,8 @@ static int wait_task_continued(struct task_struct *p, int noreap, p->signal->flags &= ~SIGNAL_STOP_CONTINUED; spin_unlock_irq(&p->sighand->siglock); - pid = p->pid; + ns = current->nsproxy->pid_ns; + pid = task_pid_nr_ns(p, ns); uid = p->uid; get_task_struct(p); read_unlock(&tasklist_lock); @@ -1480,7 +1501,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 = p->pid; + retval = task_pid_nr_ns(p, ns); } else { retval = wait_noreap_copyout(p, pid, uid, CLD_CONTINUED, SIGCONT, @@ -1529,12 +1550,9 @@ repeat: tsk = current; do { struct task_struct *p; - struct list_head *_p; int ret; - list_for_each(_p,&tsk->children) { - p = list_entry(_p, struct task_struct, sibling); - + list_for_each_entry(p, &tsk->children, sibling) { ret = eligible_child(pid, options, p); if (!ret) continue; @@ -1616,9 +1634,8 @@ check_continued: } } if (!flag) { - list_for_each(_p, &tsk->ptrace_children) { - p = list_entry(_p, struct task_struct, - ptrace_list); + list_for_each_entry(p, &tsk->ptrace_children, + ptrace_list) { if (!eligible_child(pid, options, p)) continue; flag = 1;