diff options
author | Alexander Nyberg <alexn@telia.com> | 2005-09-14 12:54:06 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-14 13:26:34 -0400 |
commit | fb085cf1d4294824571815d487daccc0609543f0 (patch) | |
tree | e3a704026e65bf6fea0c7747f0fb75a506f54127 | |
parent | 32a3658533c6f4c6bf370dd730213e802464ef9b (diff) |
[PATCH] Fix fs/exec.c:788 (de_thread()) BUG_ON
It turns out that the BUG_ON() in fs/exec.c: de_thread() is unreliable
and can trigger due to the test itself being racy.
de_thread() does
while (atomic_read(&sig->count) > count) {
}
.....
.....
BUG_ON(!thread_group_empty(current));
but release_task does
write_lock_irq(&tasklist_lock)
__exit_signal
(this is where atomic_dec(&sig->count) is run)
__exit_sighand
__unhash_process
takes write lock on tasklist_lock
remove itself out of PIDTYPE_TGID list
write_unlock_irq(&tasklist_lock)
so there's a clear (although small) window between the
atomic_dec(&sig->count) and the actual PIDTYPE_TGID unhashing of the
thread.
And actually there is no need for all threads to have exited at this
point, so we simply kill the BUG_ON.
Big thanks to Marc Lehmann who provided the test-case.
Fixes Bug 5170 (http://bugme.osdl.org/show_bug.cgi?id=5170)
Signed-off-by: Alexander Nyberg <alexn@telia.com>
Cc: Roland McGrath <roland@redhat.com>
Cc: Andrew Morton <akpm@osdl.org>
Cc: Ingo Molnar <mingo@elte.hu>
Acked-by: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | fs/exec.c | 5 |
1 files changed, 2 insertions, 3 deletions
@@ -745,8 +745,8 @@ static inline int de_thread(struct task_struct *tsk) | |||
745 | } | 745 | } |
746 | 746 | ||
747 | /* | 747 | /* |
748 | * Now there are really no other threads at all, | 748 | * There may be one thread left which is just exiting, |
749 | * so it's safe to stop telling them to kill themselves. | 749 | * but it's safe to stop telling the group to kill themselves. |
750 | */ | 750 | */ |
751 | sig->flags = 0; | 751 | sig->flags = 0; |
752 | 752 | ||
@@ -785,7 +785,6 @@ no_thread_group: | |||
785 | kmem_cache_free(sighand_cachep, oldsighand); | 785 | kmem_cache_free(sighand_cachep, oldsighand); |
786 | } | 786 | } |
787 | 787 | ||
788 | BUG_ON(!thread_group_empty(current)); | ||
789 | BUG_ON(!thread_group_leader(current)); | 788 | BUG_ON(!thread_group_leader(current)); |
790 | return 0; | 789 | return 0; |
791 | } | 790 | } |