diff options
| author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-11-08 01:12:54 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-11-08 01:12:54 -0800 |
| commit | 56b4c820f228c92c74335a2bfb8b1476fd203164 (patch) | |
| tree | 1cfb251a5ce52e00d1b9c9482e45bfbd3a681fe2 /kernel | |
| parent | 73d7a5fae092095759362231ea3f0e78abe1c47f (diff) | |
wait_task_stopped() must not just return 0 when it has
released the tasklist_lock.
Since it released the lock, the process lists may not
be valid any more, and we must repeat the loop rather than
continue with the next parent.
Use -EAGAIN to show this condition (separate from the
normal -EFAULT that may happen if rusage information could
not be copied to user space).
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/exit.c | 13 |
1 files changed, 11 insertions, 2 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index a2e154dba284..4f22175f601b 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -1201,8 +1201,15 @@ static int wait_task_stopped(task_t *p, int delayed_group_leader, int noreap, write_unlock_irq(&tasklist_lock); bail_ref: put_task_struct(p); - read_lock(&tasklist_lock); - return 0; + /* + * We are returning to the wait loop without having successfully + * removed the process and having released the lock. We cannot + * continue, since the "p" task pointer is potentially stale. + * + * Return -EAGAIN, and do_wait() will restart the loop from the + * beginning. Do _not_ re-acquire the lock. + */ + return -EAGAIN; } /* move to end of parent's list to avoid starvation */ @@ -1343,6 +1350,8 @@ repeat: (options & WNOWAIT), infop, stat_addr, ru); + if (retval == -EAGAIN) + goto repeat; if (retval != 0) /* He released the lock. */ goto end; break; |
