#include <linux/completion.h>
#include <linux/personality.h>
#include <linux/tty.h>
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include <linux/key.h>
#include <linux/security.h>
#include <linux/cpu.h>
#include <linux/acct.h>
+#include <linux/tsacct_kern.h>
#include <linux/file.h>
#include <linux/binfmts.h>
-#include <linux/ptrace.h>
+#include <linux/nsproxy.h>
#include <linux/tracehook.h>
+#include <linux/pid_namespace.h>
+#include <linux/ptrace.h>
#include <linux/profile.h>
#include <linux/mount.h>
#include <linux/proc_fs.h>
#include <linux/pipe_fs_i.h>
#include <linux/audit.h> /* for audit_free() */
#include <linux/resource.h>
+#include <linux/blkdev.h>
#include <linux/vs_limit.h>
#include <linux/vs_context.h>
#include <linux/vs_network.h>
+#include <linux/vs_pid.h>
+#include <linux/vserver/global.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <asm/mmu_context.h>
extern void sem_exit (void);
-extern struct task_struct *child_reaper;
static void exit_mm(struct task_struct * tsk);
flush_sigqueue(&tsk->pending);
if (sig) {
flush_sigqueue(&sig->shared_pending);
+ taskstats_tgid_free(sig);
__cleanup_signal(sig);
}
}
{
struct task_struct *leader;
int zap_leader;
+ int inhibited_leader;
repeat:
tracehook_release_task(p);
atomic_dec(&p->user->processes);
* 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,
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);
}
/*
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;
}
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;
}
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);
}
/**
- * 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
/* 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? */
{
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) {
}
}
-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);
exit_mm(current);
set_special_pids(1, 1);
- mutex_lock(&tty_mutex);
- current->signal->tty = NULL;
- mutex_unlock(&tty_mutex);
+ proc_clear_tty(current);
/* Block and flush all signals */
sigfillset(&blocked);
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);
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) {
* 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);
}
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;
dput(fs->altroot);
mntput(fs->altrootmnt);
}
+ atomic_dec(&vs_global_fs);
kmem_cache_free(fs_cachep, fs);
}
}
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.
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);
/* 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);
/*
* 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);
}
* 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)
do {
reaper = next_thread(reaper);
if (reaper == father) {
+ // reaper = child_reaper(father);
reaper = vx_child_reaper(father);
break;
}
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);
}
}
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));
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);
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);
current->comm, current->pid,
preempt_count());
- taskstats_exit_alloc(&tidstats, &mycpu);
-
acct_update_integrals(tsk);
if (tsk->mm) {
update_hiwater_rss(tsk->mm);
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);
#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);
exit_sem(tsk);
__exit_files(tsk);
__exit_fs(tsk);
- exit_namespace(tsk);
exit_thread();
cpuset_exit(tsk);
exit_keys(tsk);
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;
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);
{
if (comp)
complete(comp);
-
+
do_exit(code);
}