From 776969f04b4a372e9eea8f7ddf683907613765bf Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 19 Feb 2003 21:19:00 -0800 Subject: [PATCH] Keep interrupts enabled in exit path We are leaving local interrupts disabled coming out of exit_notify(). But we are about to call wait_task_inactive() which spins, waiting for another CPU to end a task. If that CPU has issued smp_call_function() to this CPU, deadlock. So the patch enables interrupts again before returning from exit_notify(). Also, exit_notify() returns with preemption disabled, so there is no need to perform another preempt_disable() in do_exit(). --- kernel/exit.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'kernel') diff --git a/kernel/exit.c b/kernel/exit.c index c45159219e83..224cb7adc73f 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -674,13 +674,19 @@ static void exit_notify(struct task_struct *tsk) tsk->state = TASK_ZOMBIE; /* - * No need to unlock IRQs, we'll schedule() immediately - * anyway. In the preemption case this also makes it - * impossible for the task to get runnable again (thus - * the "_raw_" unlock - to make sure we don't try to - * preempt here). + * In the preemption case it must be impossible for the task + * to get runnable again, so use "_raw_" unlock to keep + * preempt_count elevated until we schedule(). + * + * To avoid deadlock on SMP, interrupts must be unmasked. If we + * don't, subsequently called functions (e.g, wait_task_inactive() + * via release_task()) will spin, with interrupt flags + * unwittingly blocked, until the other task sleeps. That task + * may itself be waiting for smp_call_function() to answer and + * complete, and with interrupts blocked that will never happen. */ _raw_write_unlock(&tasklist_lock); + local_irq_enable(); } NORET_TYPE void do_exit(long code) @@ -727,7 +733,6 @@ NORET_TYPE void do_exit(long code) tsk->exit_code = code; exit_notify(tsk); - preempt_disable(); if (tsk->exit_signal == -1) release_task(tsk); -- cgit v1.2.3