---
fs/binfmt_elf.c | 12 +++++++-----
fs/binfmt_elf_fdpic.c | 12 +++++++-----
fs/coredump.c | 31 +++++++++++++++++--------------
include/linux/binfmts.h | 3 ++-
include/linux/coredump.h | 12 ++++++++++++
5 files changed, 45 insertions(+), 25 deletions(-)
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 16a56b6b3f6c..f85b2137bdb9 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -74,7 +74,7 @@ static int load_elf_binary(struct linux_binprm *bprm);
* don't even try.
*/
#ifdef CONFIG_ELF_CORE
-static int elf_core_dump(struct coredump_params *cprm);
+static bool elf_core_dump(struct coredump_params *cprm);
#else
#define elf_core_dump NULL
#endif
@@ -1990,9 +1990,9 @@ static void fill_extnum_info(struct elfhdr *elf, struct
elf_shdr *shdr4extnum,
* and then they are actually written out. If we run out of core limit
* we just truncate.
*/
-static int elf_core_dump(struct coredump_params *cprm)
+static bool elf_core_dump(struct coredump_params *cprm)
{
- int has_dumped = 0;
+ bool ret = false;
int segs, i;
struct elfhdr elf;
loff_t offset = 0, dataoff;
@@ -2023,7 +2023,7 @@ static int elf_core_dump(struct coredump_params *cprm)
if (!fill_note_info(&elf, e_phnum, &info, cprm))
goto end_coredump;
- has_dumped = 1;
+ cprm->state |= COREDUMP_STATE_STARTED;
offset += sizeof(elf); /* ELF header */
offset += segs * sizeof(struct elf_phdr); /* Program headers */
@@ -2118,11 +2118,13 @@ static int elf_core_dump(struct coredump_params *cprm)
goto end_coredump;
}
+ ret = true;
+
end_coredump:
free_note_info(&info);
kfree(shdr4extnum);
kfree(phdr4note);
- return has_dumped;
+ return ret;
}
#endif /* CONFIG_ELF_CORE */
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index fe0b5c5ed2bc..252eb155965b 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -75,7 +75,7 @@ static int elf_fdpic_map_file_by_direct_mmap(struct
elf_fdpic_params *,
struct file *, struct mm_struct *);
#ifdef CONFIG_ELF_CORE
-static int elf_fdpic_core_dump(struct coredump_params *cprm);
+static bool elf_fdpic_core_dump(struct coredump_params *cprm);
#endif
static struct linux_binfmt elf_fdpic_format = {
@@ -1476,9 +1476,9 @@ static bool elf_fdpic_dump_segments(struct
coredump_params *cprm,
* and then they are actually written out. If we run out of core limit
* we just truncate.
*/
-static int elf_fdpic_core_dump(struct coredump_params *cprm)
+static bool elf_fdpic_core_dump(struct coredump_params *cprm)
{
- int has_dumped = 0;
+ bool ret = false;
int segs;
int i;
struct elfhdr *elf = NULL;
@@ -1535,7 +1535,7 @@ static int elf_fdpic_core_dump(struct coredump_params
*cprm)
/* Set up header */
fill_elf_fdpic_header(elf, e_phnum);
- has_dumped = 1;
+ cprm->state |= COREDUMP_STATE_STARTED;
/*
* Set up the notes in similar form to SVR4 core dumps made
* with info from their /proc.
@@ -1655,6 +1655,8 @@ static int elf_fdpic_core_dump(struct coredump_params
*cprm)
cprm->file->f_pos, offset);
}
+ ret = true;
+
end_coredump:
while (thread_list) {
tmp = thread_list;
@@ -1665,7 +1667,7 @@ static int elf_fdpic_core_dump(struct coredump_params
*cprm)
kfree(elf);
kfree(psinfo);
kfree(shdr4extnum);
- return has_dumped;
+ return ret;
}
#endif /* CONFIG_ELF_CORE */
diff --git a/fs/coredump.c b/fs/coredump.c
index d61f36239f91..6af3ff0e19a6 100644
--- a/fs/coredump.c
+++ b/fs/coredump.c
@@ -98,7 +98,6 @@ struct core_name {
char *corename __counted_by_ptr(size);
int used, size;
unsigned int core_pipe_limit;
- bool core_dumped;
enum coredump_type_t core_type;
};
@@ -250,7 +249,6 @@ static bool coredump_parse(struct core_name *cn, struct coredump_params *cprm,
cn->used = 0;
cn->corename = NULL;
cn->core_pipe_limit = 0;
- cn->core_dumped = false;
if (*pat_ptr == '|')
cn->core_type = COREDUMP_PIPE;
else if (*pat_ptr == '@')
@@ -549,13 +547,13 @@ static int coredump_wait(int exit_code, struct core_state
*core_state)
return core_waiters;
}
-static void coredump_finish(bool core_dumped)
+static void coredump_finish(enum coredump_state state)
{
struct core_thread *curr, *next;
struct task_struct *task;
spin_lock_irq(¤t->sighand->siglock);
- if (core_dumped && !__fatal_signal_pending(current))
+ if ((state & COREDUMP_STATE_STARTED) &&
!__fatal_signal_pending(current))
current->signal->group_exit_code |= 0x80;
next = current->signal->core_state->dumper.next;
current->signal->core_state = NULL;
@@ -1045,19 +1043,23 @@ static bool coredump_pipe(struct core_name *cn, struct
coredump_params *cprm,
return true;
}
-static bool coredump_write(struct core_name *cn,
- struct coredump_params *cprm,
- const struct linux_binfmt *binfmt)
+static bool coredump_write(struct coredump_params *cprm,
+ const struct linux_binfmt *binfmt)
{
- if (dump_interrupted())
+ if (dump_interrupted()) {
+ cprm->state |= COREDUMP_STATE_TRUNCATED;
return true;
+ }
- if (!dump_vma_snapshot(cprm))
+ if (!dump_vma_snapshot(cprm)) {
+ cprm->state |= COREDUMP_STATE_TRUNCATED;
return false;
+ }
file_start_write(cprm->file);
- cn->core_dumped = binfmt->core_dump(cprm);
+ if (!binfmt->core_dump(cprm))
+ cprm->state |= COREDUMP_STATE_TRUNCATED;
/*
* Ensures that file size is big enough to contain the current
* file postion. This prevents gdb from complaining about
@@ -1066,7 +1068,8 @@ static bool coredump_write(struct core_name *cn,
*/
if (cprm->to_skip) {
cprm->to_skip--;
- dump_emit(cprm, "", 1);
+ if (!dump_emit(cprm, "", 1))
+ cprm->state |= COREDUMP_STATE_TRUNCATED;
}
file_end_write(cprm->file);
free_vma_snapshot(cprm);
@@ -1082,7 +1085,7 @@ static void coredump_cleanup(struct core_name *cn, struct
coredump_params *cprm)
atomic_dec(&core_pipe_count);
}
kfree(cn->corename);
- coredump_finish(cn->core_dumped);
+ coredump_finish(cprm->state);
}
static inline bool coredump_skip(const struct coredump_params *cprm,
@@ -1136,14 +1139,14 @@ static void do_coredump(struct core_name *cn, struct
coredump_params *cprm,
if (unshare_files())
return;
- if ((cprm->mask & COREDUMP_KERNEL) && !coredump_write(cn, cprm, binfmt))
+ if ((cprm->mask & COREDUMP_KERNEL) && !coredump_write(cprm, binfmt))
return;
coredump_sock_shutdown(cprm->file);
/* Let the parent know that a coredump was generated. */
if (cprm->mask & COREDUMP_USERSPACE)
- cn->core_dumped = true;
+ cprm->state |= COREDUMP_STATE_STARTED;
/*
* When core_pipe_limit is set we wait for the coredump server
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index 2c77e383e737..64f82fb642bf 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -94,7 +94,8 @@ struct linux_binfmt {
struct module *module;
int (*load_binary)(struct linux_binprm *);
#ifdef CONFIG_COREDUMP
- int (*core_dump)(struct coredump_params *cprm);
+ /* Returns true if the whole coredump was written. */
+ bool (*core_dump)(struct coredump_params *cprm);
unsigned long min_coredump; /* minimal dump size */
#endif
} __randomize_layout;
diff --git a/include/linux/coredump.h b/include/linux/coredump.h
index 943bddfb22bf..709388dd5659 100644
--- a/include/linux/coredump.h
+++ b/include/linux/coredump.h
@@ -9,6 +9,16 @@
#include <asm/siginfo.h>
#ifdef CONFIG_COREDUMP
+/**
+ * enum coredump_state - what happened while the coredump was written
+ * @COREDUMP_STATE_STARTED: the dumper committed to writing a coredump
+ * @COREDUMP_STATE_TRUNCATED: the dumper stopped before it had written all of
it
+ */
+enum coredump_state {
+ COREDUMP_STATE_STARTED = (1U << 0),
+ COREDUMP_STATE_TRUNCATED = (1U << 1),
+};
+
struct core_vma_metadata {
unsigned long start, end;
vm_flags_t flags;
@@ -28,6 +38,8 @@ struct coredump_params {
int cpu;
/* COREDUMP_* options negotiated with the coredump server. */
u64 mask;
+ /* COREDUMP_STATE_* raised while the coredump is written. */
+ enum coredump_state state;
loff_t written;
loff_t pos;
loff_t to_skip;