[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