diff options
author | Oleg Nesterov <oleg@tv-sign.ru> | 2006-01-08 04:03:13 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-08 23:13:55 -0500 |
commit | bb6f6dbaa48c53525a7a4f9d4df719c3b0b582af (patch) | |
tree | d8214a72c61d49e3cb896e0390256f23e9f72eff | |
parent | 0811af28ce49fab963e3e6b8abcf8c460f971cd4 (diff) |
[PATCH] do_coredump() should reset group_stop_count earlier
__group_complete_signal() sets ->group_stop_count in sig_kernel_coredump()
path and marks the target thread as ->group_exit_task. So any thread
except group_exit_task will go to handle_group_stop()->finish_stop().
However, when group_exit_task actually starts do_coredump(), it sets
SIGNAL_GROUP_EXIT, but does not reset ->group_stop_count while killing
other threads. If we have not yet stopped threads in the same thread
group, they all will spin in kernel mode until group_exit_task sends them
SIGKILL, because ->group_stop_count > 0 means:
recalc_sigpending_tsk() never clears TIF_SIGPENDING
get_signal_to_deliver() goes to handle_group_stop()
handle_group_stop() returns when SIGNAL_GROUP_EXIT set
syscall_exit/resume_userspace notice TIF_SIGPENDING,
call get_signal_to_deliver() again.
So we are wasting cpu cycles, and if one of these threads is rt_task() this
may be a serious problem.
NOTE: do_coredump() holds ->mmap_sem, so not stopped threads can't escape
coredumping after clearing ->group_stop_count.
See also this thread: http://marc.theaimsgroup.com/?t=112739139900002
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | fs/exec.c | 2 |
1 files changed, 1 insertions, 1 deletions
@@ -1462,6 +1462,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
1462 | if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) { | 1462 | if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) { |
1463 | current->signal->flags = SIGNAL_GROUP_EXIT; | 1463 | current->signal->flags = SIGNAL_GROUP_EXIT; |
1464 | current->signal->group_exit_code = exit_code; | 1464 | current->signal->group_exit_code = exit_code; |
1465 | current->signal->group_stop_count = 0; | ||
1465 | retval = 0; | 1466 | retval = 0; |
1466 | } | 1467 | } |
1467 | spin_unlock_irq(¤t->sighand->siglock); | 1468 | spin_unlock_irq(¤t->sighand->siglock); |
@@ -1477,7 +1478,6 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
1477 | * Clear any false indication of pending signals that might | 1478 | * Clear any false indication of pending signals that might |
1478 | * be seen by the filesystem code called to write the core file. | 1479 | * be seen by the filesystem code called to write the core file. |
1479 | */ | 1480 | */ |
1480 | current->signal->group_stop_count = 0; | ||
1481 | clear_thread_flag(TIF_SIGPENDING); | 1481 | clear_thread_flag(TIF_SIGPENDING); |
1482 | 1482 | ||
1483 | if (current->signal->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump) | 1483 | if (current->signal->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump) |