Commit 528f827e authored by Oleg Nesterov's avatar Oleg Nesterov Committed by Linus Torvalds

coredump: introduce dump_interrupted()

By discussion with Mandeep.

Change dump_write(), dump_seek() and do_coredump() to check
signal_pending() and abort if it is true.  dump_seek() does this only
before f_op->llseek(), otherwise it relies on dump_write().

We need this change to ensure that the coredump won't delay suspend, and
to ensure it reacts to SIGKILL "quickly enough", a core dump can take a
lot of time.  In particular this can help oom-killer.

We add the new trivial helper, dump_interrupted() to add the comments and
to simplify the potential freezer changes.  Perhaps it will have more
callers.

Ideally it should do try_to_freeze() but then we need the unpleasant
changes in dump_write() and wait_for_dump_helpers().  It is not trivial to
change dump_write() to restart if f_op->write() fails because of
freezing().  We need to handle the short writes, we need to clear
TIF_SIGPENDING (and we can't rely on recalc_sigpending() unless we change
it to check PF_DUMPCORE).  And if the buggy f_op->write() sets
TIF_SIGPENDING we can not distinguish this case from the race with
freeze_task() + __thaw_task().

So we simply accept the fact that the freezer can truncate a core-dump but
at least you can reliably suspend.  Hopefully we can tolerate this
unlikely case and the necessary complications doesn't worth a trouble.
But if we decide to make the coredumping freezable later we can do this on
top of this change.
Signed-off-by: default avatarOleg Nesterov <oleg@redhat.com>
Acked-by: default avatarMandeep Singh Baines <msb@chromium.org>
Cc: Neil Horman <nhorman@redhat.com>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
Cc: Tejun Heo <tj@kernel.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent acdedd99
...@@ -418,6 +418,17 @@ static void coredump_finish(struct mm_struct *mm, bool core_dumped) ...@@ -418,6 +418,17 @@ static void coredump_finish(struct mm_struct *mm, bool core_dumped)
mm->core_state = NULL; mm->core_state = NULL;
} }
static bool dump_interrupted(void)
{
/*
* SIGKILL or freezing() interrupt the coredumping. Perhaps we
* can do try_to_freeze() and check __fatal_signal_pending(),
* but then we need to teach dump_write() to restart and clear
* TIF_SIGPENDING.
*/
return signal_pending(current);
}
static void wait_for_dump_helpers(struct file *file) static void wait_for_dump_helpers(struct file *file)
{ {
struct pipe_inode_info *pipe; struct pipe_inode_info *pipe;
...@@ -641,7 +652,7 @@ void do_coredump(siginfo_t *siginfo) ...@@ -641,7 +652,7 @@ void do_coredump(siginfo_t *siginfo)
goto close_fail; goto close_fail;
if (displaced) if (displaced)
put_files_struct(displaced); put_files_struct(displaced);
core_dumped = binfmt->core_dump(&cprm); core_dumped = !dump_interrupted() && binfmt->core_dump(&cprm);
if (ispipe && core_pipe_limit) if (ispipe && core_pipe_limit)
wait_for_dump_helpers(cprm.file); wait_for_dump_helpers(cprm.file);
...@@ -669,7 +680,9 @@ void do_coredump(siginfo_t *siginfo) ...@@ -669,7 +680,9 @@ void do_coredump(siginfo_t *siginfo)
*/ */
int dump_write(struct file *file, const void *addr, int nr) int dump_write(struct file *file, const void *addr, int nr)
{ {
return access_ok(VERIFY_READ, addr, nr) && file->f_op->write(file, addr, nr, &file->f_pos) == nr; return !dump_interrupted() &&
access_ok(VERIFY_READ, addr, nr) &&
file->f_op->write(file, addr, nr, &file->f_pos) == nr;
} }
EXPORT_SYMBOL(dump_write); EXPORT_SYMBOL(dump_write);
...@@ -678,7 +691,8 @@ int dump_seek(struct file *file, loff_t off) ...@@ -678,7 +691,8 @@ int dump_seek(struct file *file, loff_t off)
int ret = 1; int ret = 1;
if (file->f_op->llseek && file->f_op->llseek != no_llseek) { if (file->f_op->llseek && file->f_op->llseek != no_llseek) {
if (file->f_op->llseek(file, off, SEEK_CUR) < 0) if (dump_interrupted() ||
file->f_op->llseek(file, off, SEEK_CUR) < 0)
return 0; return 0;
} else { } else {
char *buf = (char *)get_zeroed_page(GFP_KERNEL); char *buf = (char *)get_zeroed_page(GFP_KERNEL);
......
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