On Tue, 16 Sep 2014 17:48:49 +0800
"Wang, Xiao/Wang Xiao" <[email protected]> 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 <[email protected]>
> ---
>   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);


_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

Reply via email to