Commit bb6f6dba authored by Oleg Nesterov's avatar Oleg Nesterov Committed by Linus Torvalds

[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=112739139900002Signed-off-by: default avatarOleg Nesterov <oleg@tv-sign.ru>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 0811af28
...@@ -1462,6 +1462,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) ...@@ -1462,6 +1462,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) { if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) {
current->signal->flags = SIGNAL_GROUP_EXIT; current->signal->flags = SIGNAL_GROUP_EXIT;
current->signal->group_exit_code = exit_code; current->signal->group_exit_code = exit_code;
current->signal->group_stop_count = 0;
retval = 0; retval = 0;
} }
spin_unlock_irq(&current->sighand->siglock); spin_unlock_irq(&current->sighand->siglock);
...@@ -1477,7 +1478,6 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) ...@@ -1477,7 +1478,6 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
* Clear any false indication of pending signals that might * Clear any false indication of pending signals that might
* be seen by the filesystem code called to write the core file. * be seen by the filesystem code called to write the core file.
*/ */
current->signal->group_stop_count = 0;
clear_thread_flag(TIF_SIGPENDING); clear_thread_flag(TIF_SIGPENDING);
if (current->signal->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump) if (current->signal->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump)
......
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