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);