aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2013-04-30 18:28:15 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-04-30 20:04:06 -0400
commit528f827ee0bb508af5c9466562f474675540473e (patch)
tree9c13212aa45b8e08fc3b8016407c6ee0f8603604
parentacdedd99b0f3bff9b4bb2103a6b1268c03d1f963 (diff)
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: Oleg Nesterov <oleg@redhat.com> Acked-by: Mandeep 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: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/coredump.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/fs/coredump.c b/fs/coredump.c
index acc4448c28e7..aa8ac69a548f 100644
--- a/fs/coredump.c
+++ b/fs/coredump.c
@@ -418,6 +418,17 @@ static void coredump_finish(struct mm_struct *mm, bool core_dumped)
418 mm->core_state = NULL; 418 mm->core_state = NULL;
419} 419}
420 420
421static bool dump_interrupted(void)
422{
423 /*
424 * SIGKILL or freezing() interrupt the coredumping. Perhaps we
425 * can do try_to_freeze() and check __fatal_signal_pending(),
426 * but then we need to teach dump_write() to restart and clear
427 * TIF_SIGPENDING.
428 */
429 return signal_pending(current);
430}
431
421static void wait_for_dump_helpers(struct file *file) 432static void wait_for_dump_helpers(struct file *file)
422{ 433{
423 struct pipe_inode_info *pipe; 434 struct pipe_inode_info *pipe;
@@ -641,7 +652,7 @@ void do_coredump(siginfo_t *siginfo)
641 goto close_fail; 652 goto close_fail;
642 if (displaced) 653 if (displaced)
643 put_files_struct(displaced); 654 put_files_struct(displaced);
644 core_dumped = binfmt->core_dump(&cprm); 655 core_dumped = !dump_interrupted() && binfmt->core_dump(&cprm);
645 656
646 if (ispipe && core_pipe_limit) 657 if (ispipe && core_pipe_limit)
647 wait_for_dump_helpers(cprm.file); 658 wait_for_dump_helpers(cprm.file);
@@ -669,7 +680,9 @@ fail:
669 */ 680 */
670int dump_write(struct file *file, const void *addr, int nr) 681int dump_write(struct file *file, const void *addr, int nr)
671{ 682{
672 return access_ok(VERIFY_READ, addr, nr) && file->f_op->write(file, addr, nr, &file->f_pos) == nr; 683 return !dump_interrupted() &&
684 access_ok(VERIFY_READ, addr, nr) &&
685 file->f_op->write(file, addr, nr, &file->f_pos) == nr;
673} 686}
674EXPORT_SYMBOL(dump_write); 687EXPORT_SYMBOL(dump_write);
675 688
@@ -678,7 +691,8 @@ int dump_seek(struct file *file, loff_t off)
678 int ret = 1; 691 int ret = 1;
679 692
680 if (file->f_op->llseek && file->f_op->llseek != no_llseek) { 693 if (file->f_op->llseek && file->f_op->llseek != no_llseek) {
681 if (file->f_op->llseek(file, off, SEEK_CUR) < 0) 694 if (dump_interrupted() ||
695 file->f_op->llseek(file, off, SEEK_CUR) < 0)
682 return 0; 696 return 0;
683 } else { 697 } else {
684 char *buf = (char *)get_zeroed_page(GFP_KERNEL); 698 char *buf = (char *)get_zeroed_page(GFP_KERNEL);