Commit 2abf6861 authored by Ingo Molnar's avatar Ingo Molnar Committed by Linus Torvalds

[PATCH] permit sleeping in release_task()

release_task() calls proc_pid_flush() call dput(), which can sleep.  But
that's a late-in-exit no-preempt path with CONFIG_PREEMPT.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent d513047b
...@@ -56,8 +56,6 @@ void release_task(struct task_struct * p) ...@@ -56,8 +56,6 @@ void release_task(struct task_struct * p)
struct dentry *proc_dentry; struct dentry *proc_dentry;
repeat: repeat:
BUG_ON(p->state < TASK_ZOMBIE);
atomic_dec(&p->user->processes); atomic_dec(&p->user->processes);
spin_lock(&p->proc_lock); spin_lock(&p->proc_lock);
proc_dentry = proc_pid_unhash(p); proc_dentry = proc_pid_unhash(p);
...@@ -755,9 +753,8 @@ static void exit_notify(struct task_struct *tsk) ...@@ -755,9 +753,8 @@ static void exit_notify(struct task_struct *tsk)
state = TASK_ZOMBIE; state = TASK_ZOMBIE;
if (tsk->exit_signal == -1 && tsk->ptrace == 0) if (tsk->exit_signal == -1 && tsk->ptrace == 0)
state = TASK_DEAD; state = TASK_DEAD;
else
tsk->state = state; tsk->state = state;
tsk->flags |= PF_DEAD;
/* /*
* Clear these here so that update_process_times() won't try to deliver * Clear these here so that update_process_times() won't try to deliver
* itimer, profile or rlimit signals to this task while it is in late exit. * itimer, profile or rlimit signals to this task while it is in late exit.
...@@ -767,19 +764,14 @@ static void exit_notify(struct task_struct *tsk) ...@@ -767,19 +764,14 @@ static void exit_notify(struct task_struct *tsk)
tsk->rlim[RLIMIT_CPU].rlim_cur = RLIM_INFINITY; tsk->rlim[RLIMIT_CPU].rlim_cur = RLIM_INFINITY;
/* /*
* In the preemption case it must be impossible for the task * Get a reference to it so that we can set the state
* to get runnable again, so use "_raw_" unlock to keep * as the last step. The state-setting only matters if the
* preempt_count elevated until we schedule(). * current task is releasing itself, to trigger the final
* * put_task_struct() in finish_task_switch(). (thread self-reap)
* 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); get_task_struct(tsk);
local_irq_enable();
write_unlock_irq(&tasklist_lock);
list_for_each_safe(_p, _n, &ptrace_dead) { list_for_each_safe(_p, _n, &ptrace_dead) {
list_del_init(_p); list_del_init(_p);
...@@ -788,9 +780,17 @@ static void exit_notify(struct task_struct *tsk) ...@@ -788,9 +780,17 @@ static void exit_notify(struct task_struct *tsk)
} }
/* If the process is dead, release it - nobody will wait for it */ /* If the process is dead, release it - nobody will wait for it */
if (state == TASK_DEAD) if (state == TASK_DEAD) {
release_task(tsk); release_task(tsk);
write_lock_irq(&tasklist_lock);
tsk->state = state;
_raw_write_unlock(&tasklist_lock);
local_irq_enable();
} else
preempt_disable();
tsk->flags |= PF_DEAD;
put_task_struct(tsk);
} }
asmlinkage NORET_TYPE void do_exit(long code) asmlinkage NORET_TYPE void do_exit(long code)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment