[PATCH 2/2] makedumpfile: make the incomplete vmcore generated by ENOSPC error analyzable
Petr Tesarik
ptesarik at suse.cz
Tue Sep 16 23:47:29 PDT 2014
On Tue, 16 Sep 2014 17:48:49 +0800
"Wang, Xiao/Wang Xiao" <wangx.fnst at cn.fujitsu.com> wrote:
> Since the incomplete vmcore generated by ENOSPC error can't be anylyzed by
> crash utility, but sometimes this file may contain important information
Hello 王萧,
first of all, I like your patch. It has always annoyed me that any
incomplete dump was utterly useless. Just one small question: why is
this limited to ENOSPC? Why not e.g. EIO? EFBIG?
I think writing the (incomplete) bitmap should always be attempted.
Petr Tesarik
> and the panic problem won't be reproduced, then we came up with an idea to
> modify the exist data of the incomplete vmcore file to make it analyzable
> by crash utility. As there are two formats of the vmcore file, different
> methods are needed to deal with each of them,
>
> elf:
> Modify the value of the PT_LOAD program header to reflect the actual size
> of the incomplete vmcore file. This method can't be used to modify the
> vmcore written in flattened mode.
>
> kdump-compressed:
> Dump the bitmap before any page header and page data.
>
> Signed-of-by: Wang Xiao <wangx.fnst at cn.fujitsu.com>
> ---
> makedumpfile.c | 150
> +++++++++++++++++++++++++++++++++++++++++++++++++++++---
> 1 files changed, 143 insertions(+), 7 deletions(-)
>
> diff --git a/makedumpfile.c b/makedumpfile.c
> index ce4a866..debc15b 100644
> --- a/makedumpfile.c
> +++ b/makedumpfile.c
> @@ -3621,6 +3621,128 @@ write_cache(struct cache_data *cd, void *buf,
> size_t size)
> }
>
> int
> +reserve_diskspace(int fd, off_t start_offset, off_t end_offset, char
> *file_name)
> +{
> + size_t buf_size;
> + char *buf = NULL;
> +
> + int ret = FALSE;
> +
> + if (start_offset >= end_offset) {
> + ERRMSG("The start offset of diskspace to be reserved must smaller than "
> + "the end offset.\n");
> + return FALSE;
> + }
> +
> + buf_size = end_offset - start_offset;
> +
> + if ((buf = malloc(buf_size)) == NULL) {
> + ERRMSG("Can't allocate memory for the size of reserved diskspace. %s\n",
> + strerror(errno));
> + return FALSE;
> + }
> +
> + memset(buf, 0, buf_size);
> + if (!write_buffer(fd, start_offset, buf, buf_size, file_name))
> + goto out;
> +
> + ret = TRUE;
> +out:
> + if (buf != NULL) {
> + free(buf);
> + }
> +
> + return ret;
> +}
> +
> +int
> +check_and_modify_elf_header() {
> + int i, phnum;
> + off_t file_end, offset, end_offset;
> + Elf64_Ehdr ehdr64;
> + Elf32_Ehdr ehdr32;
> + Elf64_Phdr phdr64;
> + Elf32_Phdr phdr32;
> +
> + /*
> + * the is_elf64_memory() function still can be used.
> + */
> + if (is_elf64_memory()) { /* ELF64 */
> + if (!get_elf64_ehdr(info->fd_dumpfile, info->name_dumpfile, &ehdr64)) {
> + ERRMSG("Can't get ehdr64.\n");
> + return FALSE;
> + }
> + phnum = ehdr64.e_phnum;
> + } else { /* ELF32 */
> + if (!get_elf32_ehdr(info->fd_dumpfile, info->name_dumpfile, &ehdr32)) {
> + ERRMSG("Can't get ehdr32.\n");
> + return FALSE;
> + }
> + phnum = ehdr32.e_phnum;
> + }
> +
> + file_end = lseek(info->fd_dumpfile, 0, SEEK_END);
> + if (file_end < 0) {
> + ERRMSG("Can't detect the size of %s. %s\n",
> + info->name_dumpfile,
> + strerror(errno));
> + return FALSE;
> + }
> +
> + for (i = 0; i < phnum; i++) {
> + if (is_elf64_memory()) {
> + if (!get_elf64_phdr(info->fd_dumpfile,
> + info->name_dumpfile,
> + i, &phdr64)) {
> + ERRMSG("Can't find Phdr %d.\n", i);
> + return FALSE;
> + }
> +
> + offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) * i;
> + end_offset = phdr64.p_offset + phdr64.p_filesz;
> +
> + /*
> + * Check the program header and modify its value according
> + * to the actual written size.
> + */
> + if (file_end >= end_offset)
> + continue;
> + else if (file_end >= phdr64.p_offset && file_end < end_offset)
> + phdr64.p_filesz = file_end - phdr64.p_offset;
> + else if (file_end < phdr64.p_offset)
> + memset(&phdr64, 0, sizeof(Elf64_Phdr));
> +
> + if (!write_buffer(info->fd_dumpfile, offset, &phdr64,
> + sizeof(Elf64_Phdr), info->name_dumpfile))
> + return FALSE;
> + } else {
> + if (!get_elf32_phdr(info->fd_dumpfile,
> + info->name_dumpfile,
> + i, &phdr32)) {
> + ERRMSG("Can't find Phdr %d.\n", i);
> + return FALSE;
> + }
> +
> + offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * i;
> + end_offset = phdr32.p_offset + phdr32.p_filesz;
> +
> + if (file_end >= end_offset)
> + continue;
> + else if (file_end >= phdr32.p_offset && file_end < end_offset)
> + phdr32.p_filesz = file_end - phdr32.p_offset;
> + else if (file_end < phdr32.p_offset)
> + memset(&phdr32, 0, sizeof(Elf32_Phdr));
> +
> + if (!write_buffer(info->fd_dumpfile, offset, &phdr32,
> + sizeof(Elf32_Phdr), info->name_dumpfile))
> + return FALSE;
> + }
> + }
> +
> + return TRUE;
> +}
> +
> +int
> write_cache_bufsz(struct cache_data *cd)
> {
> if (!cd->buf_size)
> @@ -5432,6 +5554,13 @@ write_elf_header(struct cache_data *cd_header)
> size_note = note.p_filesz;
>
> /*
> + * Reserve a space to store the whole program headers.
> + */
> + if (!reserve_diskspace(cd_header->fd, cd_header->offset,
> + offset_note_dumpfile, cd_header->file_name))
> + goto out;
> +
> + /*
> * Modify the note size in PT_NOTE header to accomodate eraseinfo data.
> * Eraseinfo will be written later.
> */
> @@ -6956,11 +7085,11 @@ write_kdump_pages_and_bitmap_cyclic(struct
> cache_data *cd_header, struct cache_d
> if (!exclude_unnecessary_pages_cyclic(&cycle))
> return FALSE;
>
> - if (!write_kdump_pages_cyclic(cd_header, cd_page, &pd_zero,
> - &offset_data, &cycle))
> + if (!write_kdump_bitmap2_cyclic(&cycle))
> return FALSE;
>
> - if (!write_kdump_bitmap2_cyclic(&cycle))
> + if (!write_kdump_pages_cyclic(cd_header, cd_page, &pd_zero,
> + &offset_data, &cycle))
> return FALSE;
> }
>
> @@ -7906,10 +8035,10 @@ writeout_dumpfile(void)
> goto out;
> if (info->flag_cyclic) {
> if (!write_elf_pages_cyclic(&cd_header, &cd_page))
> - goto out;
> + goto chk_enospc;
> } else {
> if (!write_elf_pages(&cd_header, &cd_page))
> - goto out;
> + goto chk_enospc;
> }
> if (!write_elf_eraseinfo(&cd_header))
> goto out;
> @@ -7923,12 +8052,12 @@ writeout_dumpfile(void)
> } else {
> if (!write_kdump_header())
> goto out;
> + if (!write_kdump_bitmap())
> + goto out;
> if (!write_kdump_pages(&cd_header, &cd_page))
> goto out;
> if (!write_kdump_eraseinfo(&cd_page))
> goto out;
> - if (!write_kdump_bitmap())
> - goto out;
> }
> if (info->flag_flatten) {
> if (!write_end_flat_header())
> @@ -7936,6 +8065,13 @@ writeout_dumpfile(void)
> }
>
> ret = TRUE;
> +chk_enospc:
> + if ((ret == FALSE) && info->flag_nospace && !info->flag_flatten) {
> + if (!write_cache_bufsz(&cd_header))
> + goto out;
> + if (!check_and_modify_elf_header())
> + ERRMSG("Can't modify the elf header.\n");
> + }
> out:
> free_cache_data(&cd_header);
> free_cache_data(&cd_page);
More information about the kexec
mailing list