aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/exit.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/exit.c')
-rw-r--r--kernel/exit.c103
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)