X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=kernel%2Fexit.c;h=29617024d245a36b90e0f1399366485e3594d74b;hb=refs%2Fheads%2Fvserver;hp=80530fbcf0c7856fb969a3b77e6440da21a8bc49;hpb=7172c64a7cee4dfa95864f49c914f7ea8cf497c8;p=linux-2.6.git diff --git a/kernel/exit.c b/kernel/exit.c index 80530fbcf..29617024d 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -13,15 +13,18 @@ #include #include #include -#include +#include #include #include #include #include +#include #include #include -#include +#include #include +#include +#include #include #include #include @@ -39,9 +42,12 @@ #include #include /* for audit_free() */ #include +#include #include #include #include +#include +#include #include #include @@ -49,7 +55,6 @@ #include extern void sem_exit (void); -extern struct task_struct *child_reaper; static void exit_mm(struct task_struct * tsk); @@ -129,6 +134,7 @@ static void __exit_signal(struct task_struct *tsk) flush_sigqueue(&tsk->pending); if (sig) { flush_sigqueue(&sig->shared_pending); + taskstats_tgid_free(sig); __cleanup_signal(sig); } } @@ -142,6 +148,7 @@ void release_task(struct task_struct * p) { struct task_struct *leader; int zap_leader; + int inhibited_leader; repeat: tracehook_release_task(p); atomic_dec(&p->user->processes); @@ -155,10 +162,14 @@ repeat: * group leader's parent process. (if it wants notification.) */ zap_leader = 0; + inhibited_leader = 0; leader = p->group_leader; if (leader != p && thread_group_empty(leader) && leader->exit_state == EXIT_ZOMBIE) { BUG_ON(leader->exit_signal == -1); - do_notify_parent(leader, leader->exit_signal); + if (tracehook_inhibit_wait_zombie(leader)) + inhibited_leader = 1; + else + do_notify_parent(leader, leader->exit_signal); /* * If we were the last child thread and the leader has * exited already, and the leader's parent ignores SIGCHLD, @@ -179,6 +190,13 @@ repeat: p = leader; if (unlikely(zap_leader)) goto repeat; + + /* + * If tracing usurps normal reaping of the leader, tracing needs + * to be notified it would normally be reapable now. + */ + if (unlikely(inhibited_leader)) + tracehook_report_delayed_group_leader(leader); } /* @@ -189,21 +207,18 @@ repeat: int session_of_pgrp(int pgrp) { struct task_struct *p; - int sid = -1; + int sid = 0; read_lock(&tasklist_lock); - do_each_task_pid(pgrp, PIDTYPE_PGID, p) { - if (p->signal->session > 0) { - sid = p->signal->session; - goto out; - } - } while_each_task_pid(pgrp, PIDTYPE_PGID, p); - p = find_task_by_pid(pgrp); - if (p) - sid = p->signal->session; -out: + + p = find_task_by_pid_type(PIDTYPE_PGID, pgrp); + if (p == NULL) + p = find_task_by_pid(pgrp); + if (p != NULL) + sid = process_session(p); + read_unlock(&tasklist_lock); - + return sid; } @@ -223,10 +238,10 @@ static int will_become_orphaned_pgrp(int pgrp, struct task_struct *ignored_task) do_each_task_pid(pgrp, PIDTYPE_PGID, p) { if (p == ignored_task || p->exit_state - || p->parent->pid == 1) + || is_init(p->parent)) continue; - if (process_group(p->parent) != pgrp - && p->parent->signal->session == p->signal->session) { + if (process_group(p->parent) != pgrp && + process_session(p->parent) == process_session(p)) { ret = 0; break; } @@ -253,7 +268,6 @@ static int has_stopped_jobs(int pgrp) do_each_task_pid(pgrp, PIDTYPE_PGID, p) { if (p->state != TASK_STOPPED) continue; - retval = 1; break; } while_each_task_pid(pgrp, PIDTYPE_PGID, p); @@ -261,7 +275,8 @@ static int has_stopped_jobs(int pgrp) } /** - * reparent_to_init - Reparent the calling kernel thread to the init task. + * reparent_to_init - Reparent the calling kernel thread to the init task + * of the pid space that the thread belongs to. * * If a kernel thread is launched as a result of a system call, or if * it ever exits, it should generally reparent itself to init so that @@ -278,15 +293,13 @@ static void reparent_to_init(void) /* Reparent to init */ remove_parent(current); - current->parent = child_reaper; + current->parent = child_reaper(current); add_parent(current); /* Set the exit signal to SIGCHLD so we signal init on exit */ current->exit_signal = SIGCHLD; - if ((current->policy == SCHED_NORMAL || - current->policy == SCHED_BATCH) - && (task_nice(current) < 0)) + if (!has_rt_policy(current) && (task_nice(current) < 0)) set_user_nice(current, 0); /* cpus_allowed? */ /* rt_priority? */ @@ -303,9 +316,9 @@ void __set_special_pids(pid_t session, pid_t pgrp) { struct task_struct *curr = current->group_leader; - if (curr->signal->session != session) { + if (process_session(curr) != session) { detach_pid(curr, PIDTYPE_SID); - curr->signal->session = session; + set_signal_session(curr->signal, session); attach_pid(curr, PIDTYPE_SID, session); } if (process_group(curr) != pgrp) { @@ -315,7 +328,7 @@ void __set_special_pids(pid_t session, pid_t pgrp) } } -void set_special_pids(pid_t session, pid_t pgrp) +static void set_special_pids(pid_t session, pid_t pgrp) { write_lock_irq(&tasklist_lock); __set_special_pids(session, pgrp); @@ -398,9 +411,11 @@ void daemonize(const char *name, ...) fs = init_task.fs; current->fs = fs; atomic_inc(&fs->count); - exit_namespace(current); - current->namespace = init_task.namespace; - get_namespace(current->namespace); + + exit_task_namespaces(current); + current->nsproxy = init_task.nsproxy; + get_task_namespaces(current); + exit_files(current); current->files = init_task.files; atomic_inc(¤t->files->count); @@ -426,7 +441,7 @@ static void close_files(struct files_struct * files) for (;;) { unsigned long set; i = j * __NFDBITS; - if (i >= fdt->max_fdset || i >= fdt->max_fds) + if (i >= fdt->max_fds) break; set = fdt->open_fds->fds_bits[j++]; while (set) { @@ -469,9 +484,7 @@ void fastcall put_files_struct(struct files_struct *files) * you can free files immediately. */ fdt = files_fdtable(files); - if (fdt == &files->fdtab) - fdt->free_files = files; - else + if (fdt != &files->fdtab) kmem_cache_free(files_cachep, files); free_fdtable(fdt); } @@ -479,6 +492,18 @@ void fastcall put_files_struct(struct files_struct *files) EXPORT_SYMBOL(put_files_struct); +void reset_files_struct(struct task_struct *tsk, struct files_struct *files) +{ + struct files_struct *old; + + old = tsk->files; + task_lock(tsk); + tsk->files = files; + task_unlock(tsk); + put_files_struct(old); +} +EXPORT_SYMBOL(reset_files_struct); + static inline void __exit_files(struct task_struct *tsk) { struct files_struct * files = tsk->files; @@ -508,6 +533,7 @@ static inline void __put_fs_struct(struct fs_struct *fs) dput(fs->altroot); mntput(fs->altrootmnt); } + atomic_dec(&vs_global_fs); kmem_cache_free(fs_cachep, fs); } } @@ -580,10 +606,13 @@ static inline void choose_new_parent(struct task_struct *p, struct task_struct *reaper) { /* check for reaper context */ - vxwprintk((p->xid != reaper->xid) && (reaper != child_reaper), + vxwprintk((p->xid != reaper->xid) && (reaper != child_reaper(p)), "rogue reaper: %p[%d,#%u] <> %p[%d,#%u]", p, p->pid, p->xid, reaper, reaper->pid, reaper->xid); + if (p == reaper) + reaper = vx_child_reaper(p); + /* * Make sure we're not reparenting to ourselves and that * the parent is not a zombie. @@ -595,10 +624,6 @@ choose_new_parent(struct task_struct *p, struct task_struct *reaper) static void reparent_thread(struct task_struct *p, struct task_struct *father) { - /* We don't want people slaying init. */ - if (p->exit_signal != -1) - p->exit_signal = SIGCHLD; - if (p->pdeath_signal) /* We already hold the tasklist_lock here. */ group_send_sig_info(p->pdeath_signal, SEND_SIG_NOINFO, p); @@ -606,11 +631,22 @@ reparent_thread(struct task_struct *p, struct task_struct *father) /* Move the child from its dying parent to the new one. */ list_move_tail(&p->sibling, &p->parent->children); + /* If this is a threaded reparent there is no need to + * notify anyone anything has happened. + */ + if (p->parent->group_leader == father->group_leader) + return; + + /* We don't want people slaying init. */ + if (p->exit_signal != -1) + p->exit_signal = SIGCHLD; + /* If we'd notified the old parent about this child's death, * also notify the new parent. */ - if (p->exit_state == EXIT_ZOMBIE && p->exit_signal != -1 && - thread_group_empty(p)) + if (!tracehook_inhibit_wait_zombie(p) && + p->exit_state == EXIT_ZOMBIE && + p->exit_signal != -1 && thread_group_empty(p)) do_notify_parent(p, p->exit_signal); /* @@ -620,10 +656,11 @@ reparent_thread(struct task_struct *p, struct task_struct *father) * outside, so the child pgrp is now orphaned. */ if ((process_group(p) != process_group(father)) && - (p->signal->session == father->signal->session)) { + (process_session(p) == process_session(father))) { int pgrp = process_group(p); - if (will_become_orphaned_pgrp(pgrp, NULL) && has_stopped_jobs(pgrp)) { + if (will_become_orphaned_pgrp(pgrp, NULL) && + has_stopped_jobs(pgrp)) { __kill_pg_info(SIGHUP, SEND_SIG_PRIV, pgrp); __kill_pg_info(SIGCONT, SEND_SIG_PRIV, pgrp); } @@ -634,7 +671,8 @@ reparent_thread(struct task_struct *p, struct task_struct *father) * When we die, we re-parent all our children. * Try to give them to another thread in our thread * group, and if no such member exists, give it to - * the global child reaper process (ie "init") + * the child reaper process (ie "init") in our pid + * space. */ static void forget_original_parent(struct task_struct *father) @@ -645,6 +683,7 @@ forget_original_parent(struct task_struct *father) do { reaper = next_thread(reaper); if (reaper == father) { + // reaper = child_reaper(father); reaper = vx_child_reaper(father); break; } @@ -652,7 +691,7 @@ forget_original_parent(struct task_struct *father) list_for_each_safe(_p, _n, &father->children) { p = list_entry(_p, struct task_struct, sibling); - choose_new_parent(p, vx_child_reaper(p)); + choose_new_parent(p, reaper); reparent_thread(p, father); } } @@ -718,7 +757,7 @@ static void exit_notify(struct task_struct *tsk) t = tsk->parent; if ((process_group(t) != process_group(tsk)) && - (t->signal->session == tsk->signal->session) && + (process_session(t) == process_session(tsk)) && will_become_orphaned_pgrp(process_group(tsk), tsk) && has_stopped_jobs(process_group(tsk))) { __kill_pg_info(SIGHUP, SEND_SIG_PRIV, process_group(tsk)); @@ -768,9 +807,7 @@ static void exit_notify(struct task_struct *tsk) fastcall NORET_TYPE void do_exit(long code) { struct task_struct *tsk = current; - struct taskstats *tidstats; int group_dead; - unsigned int mycpu; profile_task_exit(tsk); @@ -780,8 +817,13 @@ 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)) - panic("Attempted to kill init!"); + 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!"); + } + tracehook_report_exit(&code); @@ -807,8 +849,6 @@ fastcall NORET_TYPE void do_exit(long code) current->comm, current->pid, preempt_count()); - taskstats_exit_alloc(&tidstats, &mycpu); - acct_update_integrals(tsk); if (tsk->mm) { update_hiwater_rss(tsk->mm); @@ -819,15 +859,6 @@ fastcall NORET_TYPE void do_exit(long code) hrtimer_cancel(&tsk->signal->real_timer); exit_itimers(tsk->signal); } - - 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(); - } - acct_collect(code, group_dead); if (unlikely(tsk->robust_list)) exit_robust_list(tsk); @@ -837,8 +868,8 @@ fastcall NORET_TYPE void do_exit(long code) #endif if (unlikely(tsk->audit_context)) audit_free(tsk); - taskstats_exit_send(tsk, tidstats, group_dead, mycpu); - taskstats_exit_free(tidstats); + + taskstats_exit(tsk, group_dead); exit_mm(tsk); @@ -847,7 +878,6 @@ fastcall NORET_TYPE void do_exit(long code) exit_sem(tsk); __exit_files(tsk); __exit_fs(tsk); - exit_namespace(tsk); exit_thread(); cpuset_exit(tsk); exit_keys(tsk); @@ -861,9 +891,12 @@ fastcall NORET_TYPE void do_exit(long code) tsk->exit_code = code; proc_exit_connector(tsk); + exit_task_namespaces(tsk); + // ns = exit_task_namespaces_early(tsk); /* needs to stay before exit_notify() */ exit_vx_info_early(tsk, code); exit_notify(tsk); + // exit_task_namespaces(tsk, ns); #ifdef CONFIG_NUMA mpol_free(tsk->mempolicy); tsk->mempolicy = NULL; @@ -891,15 +924,15 @@ fastcall NORET_TYPE void do_exit(long code) exit_vx_info(tsk, code); exit_nx_info(tsk); - /* PF_DEAD causes final put_task_struct after we schedule. */ preempt_disable(); - BUG_ON(tsk->flags & PF_DEAD); - tsk->flags |= PF_DEAD; + /* causes final put_task_struct in finish_task_switch(). */ + tsk->state = TASK_DEAD; schedule(); BUG(); /* Avoid "noreturn function does return". */ - for (;;) ; + for (;;) + cpu_relax(); /* For when BUG is null */ } EXPORT_SYMBOL_GPL(do_exit); @@ -908,7 +941,7 @@ NORET_TYPE void complete_and_exit(struct completion *comp, long code) { if (comp) complete(comp); - + do_exit(code); }