diff options
Diffstat (limited to 'kernel/exit.c')
-rw-r--r-- | kernel/exit.c | 103 |
1 files changed, 90 insertions, 13 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index a75b6a7f458a..2dbaa5c86b73 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -579,10 +579,6 @@ static struct task_struct *find_child_reaper(struct task_struct *father, } write_unlock_irq(&tasklist_lock); - if (unlikely(pid_ns == &init_pid_ns)) { - panic("Attempted to kill init! exitcode=0x%08x\n", - father->signal->group_exit_code ?: father->exit_code); - } list_for_each_entry_safe(p, n, dead, ptrace_entry) { list_del_init(&p->ptrace_entry); @@ -772,13 +768,79 @@ static void check_stack_usage(void) static inline void check_stack_usage(void) {} #endif +#ifdef CONFIG_MRVL_OCTEONTX_EL0_INTR +struct task_cleanup_handler { + void (*handler)(struct task_struct *); + struct list_head list; +}; + +static DEFINE_MUTEX(task_cleanup_handlers_mutex); +static LIST_HEAD(task_cleanup_handlers); + +int task_cleanup_handler_add(void (*handler)(struct task_struct *)) +{ + struct task_cleanup_handler *newhandler; + + newhandler = (struct task_cleanup_handler *) + kmalloc(sizeof(struct task_cleanup_handler), GFP_KERNEL); + if (newhandler == NULL) + return -1; + newhandler->handler = handler; + mutex_lock(&task_cleanup_handlers_mutex); + list_add(&newhandler->list, &task_cleanup_handlers); + mutex_unlock(&task_cleanup_handlers_mutex); + return 0; +} +EXPORT_SYMBOL(task_cleanup_handler_add); + +int task_cleanup_handler_remove(void (*handler)(struct task_struct *)) +{ + struct list_head *pos, *tmppos; + struct task_cleanup_handler *curr_task_cleanup_handler; + int retval = -1; + + mutex_lock(&task_cleanup_handlers_mutex); + list_for_each_safe(pos, tmppos, &task_cleanup_handlers) { + curr_task_cleanup_handler + = list_entry(pos, struct task_cleanup_handler, list); + if (curr_task_cleanup_handler->handler == handler) { + list_del(pos); + kfree(curr_task_cleanup_handler); + retval = 0; + } + } + mutex_unlock(&task_cleanup_handlers_mutex); + return retval; +} +EXPORT_SYMBOL(task_cleanup_handler_remove); + +static void task_cleanup_handlers_call(struct task_struct *task) +{ + struct list_head *pos; + struct task_cleanup_handler *curr_task_cleanup_handler; + + mutex_lock(&task_cleanup_handlers_mutex); + list_for_each(pos, &task_cleanup_handlers) { + curr_task_cleanup_handler = + list_entry(pos, struct task_cleanup_handler, list); + if (curr_task_cleanup_handler->handler != NULL) + curr_task_cleanup_handler->handler(task); + } + mutex_unlock(&task_cleanup_handlers_mutex); +} +#endif + void __noreturn do_exit(long code) { struct task_struct *tsk = current; int group_dead; - profile_task_exit(tsk); - kcov_task_exit(tsk); + /* + * We can get here from a kernel oops, sometimes with preemption off. + * Start by checking for critical errors. + * Then fix up important state like USER_DS and preemption. + * Then do everything else. + */ WARN_ON(blk_needs_flush_plug(tsk)); @@ -796,6 +858,16 @@ void __noreturn do_exit(long code) */ set_fs(USER_DS); + if (unlikely(in_atomic())) { + pr_info("note: %s[%d] exited with preempt_count %d\n", + current->comm, task_pid_nr(current), + preempt_count()); + preempt_count_set(PREEMPT_ENABLED); + } + + profile_task_exit(tsk); + kcov_task_exit(tsk); + ptrace_event(PTRACE_EVENT_EXIT, code); validate_creds_for_do_exit(tsk); @@ -833,19 +905,20 @@ void __noreturn do_exit(long code) raw_spin_lock_irq(&tsk->pi_lock); raw_spin_unlock_irq(&tsk->pi_lock); - if (unlikely(in_atomic())) { - pr_info("note: %s[%d] exited with preempt_count %d\n", - current->comm, task_pid_nr(current), - preempt_count()); - preempt_count_set(PREEMPT_ENABLED); - } - /* sync mm's RSS info before statistics gathering */ if (tsk->mm) sync_mm_rss(tsk->mm); acct_update_integrals(tsk); group_dead = atomic_dec_and_test(&tsk->signal->live); if (group_dead) { + /* + * If the last thread of global init has exited, panic + * immediately to get a useable coredump. + */ + if (unlikely(is_global_init(tsk))) + panic("Attempted to kill init! exitcode=0x%08x\n", + tsk->signal->group_exit_code ?: (int)code); + #ifdef CONFIG_POSIX_TIMERS hrtimer_cancel(&tsk->signal->real_timer); exit_itimers(tsk->signal); @@ -861,6 +934,10 @@ void __noreturn do_exit(long code) tsk->exit_code = code; taskstats_exit(tsk, group_dead); +#ifdef CONFIG_MRVL_OCTEONTX_EL0_INTR + task_cleanup_handlers_call(tsk); +#endif + exit_mm(); if (group_dead) |