[PATCH] Makedumpfile: vmcore size estimate

Baoquan He bhe at redhat.com
Wed Jun 11 06:57:01 PDT 2014


Forget to mention only x86-64 is processed in this patch.

On 06/11/14 at 08:39pm, Baoquan He wrote:
> User want to get a rough estimate of vmcore size, then they can decide
> how much storage space is reserved for vmcore dumping. This can help them
> to deploy their machines better, possibly hundreds of machines.
> 
> In this draft patch, a new configuration option is added,
>     "--vmcore-estimate"
> User can execute below command to get a dumped kcore. Since kcore is a
> elf file to map the whole memory of current kernel, it's  equal to the
> memory of crash kernel though it's not exact. Content of kcore is dynamic
> though /proc/vmcore is fixed once crash happened. But for vmcore size
> estimate, it is better enough.
> 
> sudo makedumpfile -E -d 31 --vmcore-estimate /proc/kcore /var/crash/kcore-dump
> 
> Questions:
> 1. Or we can get the dumpable page numbers only, then calculate the estimated
> vmcore size by a predifined factor if it's kdump compressed dumping. E.g if
> lzo dump, we assume the compression ratio is 45%, then the estimate size is
> equal to: (dumpable page numbers) * 4096* 45%.
> 
> This is easier but too rough, does anybody like this better compared with the
> real dumping implemented in this draft patch.
> 
> 2. If dump the /proc/kcore, there's still a bug I can't fixed. When elf dump,
> in function write_elf_header()  it will pre-calculate a num_loads_dumpfile which
> is the number of program segment which will be dumped. However during dumping,
> the content of /proc/kcore is dynamic, the final num_loads_dumpfile may change
> when call write_elf_pages_cyclic/write_elf_pages(). This will cause the final
> dumped elf file has a bad file format. When you execute
> "readelf -a /var/crash/kcore-dump", you will be a little surprised.
> 
> 3. This is not a formal patch, if the final solution is decided, I will post a
> patch, maybe a patchset. If you have suggestions about the code or implementation,
> please post your comment.
> 
> Signed-off-by: Baoquan He <bhe at redhat.com>
> ---
>  elf_info.c     | 136 ++++++++++++++++--
>  elf_info.h     |  17 +++
>  makedumpfile.c | 438 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
>  makedumpfile.h |   5 +
>  4 files changed, 560 insertions(+), 36 deletions(-)
> 
> diff --git a/elf_info.c b/elf_info.c
> index b277f69..1b05ad1 100644
> --- a/elf_info.c
> +++ b/elf_info.c
> @@ -36,16 +36,9 @@
>  
>  #define XEN_ELFNOTE_CRASH_INFO	(0x1000001)
>  
> -struct pt_load_segment {
> -	off_t			file_offset;
> -	unsigned long long	phys_start;
> -	unsigned long long	phys_end;
> -	unsigned long long	virt_start;
> -	unsigned long long	virt_end;
> -};
>  
>  static int			nr_cpus;             /* number of cpu */
> -static off_t			max_file_offset;
> +off_t			max_file_offset;
>  
>  /*
>   * File information about /proc/vmcore:
> @@ -60,9 +53,9 @@ static int			flags_memory;
>  /*
>   * PT_LOAD information about /proc/vmcore:
>   */
> -static unsigned int		num_pt_loads;
> -static struct pt_load_segment	*pt_loads;
> -static off_t			offset_pt_load_memory;
> +unsigned int		num_pt_loads;
> +struct pt_load_segment	*pt_loads;
> +off_t			offset_pt_load_memory;
>  
>  /*
>   * PT_NOTE information about /proc/vmcore:
> @@ -395,7 +388,49 @@ get_pt_note_info(void)
>  	return TRUE;
>  }
>  
> +#define UNINITIALIZED  ((ulong)(-1))
>  
> +#define SEEK_ERROR       (-1)
> +#define READ_ERROR       (-2)
> +int set_kcore_vmcoreinfo(uint64_t vmcoreinfo_addr, uint64_t vmcoreinfo_len)
> +{
> +	int i;
> +	ulong kvaddr;
> +	Elf64_Nhdr *note64;
> +	off_t offset;
> +	char note[MAX_SIZE_NHDR];
> +	int size_desc;
> +	off_t offset_desc;
> +
> +	offset = UNINITIALIZED;
> +	kvaddr = (ulong)vmcoreinfo_addr | PAGE_OFFSET;
> +
> +	for (i = 0; i < num_pt_loads; ++i) {
> +		struct pt_load_segment *p = &pt_loads[i];
> +		if ((kvaddr >= p->virt_start) && (kvaddr < p->virt_end)) {
> +			offset = (off_t)(kvaddr - p->virt_start) +
> +			(off_t)p->file_offset;
> +			break;
> +		}
> +	}
> +
> +	if (offset == UNINITIALIZED)
> +		return SEEK_ERROR;
> +
> +        if (lseek(fd_memory, offset, SEEK_SET) != offset)
> +		perror("lseek");
> +
> +	if (read(fd_memory, note, MAX_SIZE_NHDR) != MAX_SIZE_NHDR)
> +		return READ_ERROR;
> +
> +	note64 = (Elf64_Nhdr *)note;
> +	size_desc   = note_descsz(note);
> +	offset_desc = offset + offset_note_desc(note);
> +
> +	set_vmcoreinfo(offset_desc, size_desc);
> +
> +	return 0;
> +}
>  /*
>   * External functions.
>   */
> @@ -681,6 +716,55 @@ get_elf32_ehdr(int fd, char *filename, Elf32_Ehdr *ehdr)
>  	return TRUE;
>  }
>  
> +int
> +get_elf_loads(int fd, char *filename)
> +{
> +	int i, j, phnum, elf_format;
> +	Elf64_Phdr phdr;
> +
> +	/*
> +	 * Check ELF64 or ELF32.
> +	 */
> +	elf_format = check_elf_format(fd, filename, &phnum, &num_pt_loads);
> +	if (elf_format == ELF64)
> +		flags_memory |= MEMORY_ELF64;
> +	else if (elf_format != ELF32)
> +		return FALSE;
> +
> +	if (!num_pt_loads) {
> +		ERRMSG("Can't get the number of PT_LOAD.\n");
> +		return FALSE;
> +	}
> +
> +	/*
> +	 * The below file information will be used as /proc/vmcore.
> +	 */
> +	fd_memory   = fd;
> +	name_memory = filename;
> +
> +	pt_loads = calloc(sizeof(struct pt_load_segment), num_pt_loads);
> +	if (pt_loads == NULL) {
> +		ERRMSG("Can't allocate memory for the PT_LOAD. %s\n",
> +		    strerror(errno));
> +		return FALSE;
> +	}
> +	for (i = 0, j = 0; i < phnum; i++) {
> +		if (!get_phdr_memory(i, &phdr))
> +			return FALSE;
> +
> +		if (phdr.p_type != PT_LOAD)
> +			continue;
> +
> +		if (j >= num_pt_loads)
> +			return FALSE;
> +		if(!dump_Elf_load(&phdr, j))
> +			return FALSE;
> +		j++;
> +	}
> +
> +	return TRUE;
> +}
> +
>  /*
>   * Get ELF information about /proc/vmcore.
>   */
> @@ -826,6 +910,36 @@ get_phdr_memory(int index, Elf64_Phdr *phdr)
>  	return TRUE;
>  }
>  
> +int
> +get_phdr_load(int index, Elf64_Phdr *phdr)
> +{
> +	Elf32_Phdr phdr32;
> +
> +	if (is_elf64_memory()) { /* ELF64 */
> +		phdr->p_type = PT_LOAD;
> +		phdr->p_vaddr = pt_loads[index].virt_start;
> +		phdr->p_paddr = pt_loads[index].phys_start;
> +		phdr->p_memsz  = pt_loads[index].phys_end - pt_loads[index].phys_start;
> +		phdr->p_filesz = phdr->p_memsz;
> +		phdr->p_offset = pt_loads[index].file_offset;
> +	} else {
> +		if (!get_elf32_phdr(fd_memory, name_memory, index, &phdr32)) {
> +			ERRMSG("Can't find Phdr %d.\n", index);
> +			return FALSE;
> +		}
> +		memset(phdr, 0, sizeof(Elf64_Phdr));
> +		phdr->p_type   = phdr32.p_type;
> +		phdr->p_flags  = phdr32.p_flags;
> +		phdr->p_offset = phdr32.p_offset;
> +		phdr->p_vaddr  = phdr32.p_vaddr;
> +		phdr->p_paddr  = phdr32.p_paddr;
> +		phdr->p_filesz = phdr32.p_filesz;
> +		phdr->p_memsz  = phdr32.p_memsz;
> +		phdr->p_align  = phdr32.p_align;
> +	}
> +	return TRUE;
> +}
> +
>  off_t
>  get_offset_pt_load_memory(void)
>  {
> diff --git a/elf_info.h b/elf_info.h
> index 801faff..0c67d74 100644
> --- a/elf_info.h
> +++ b/elf_info.h
> @@ -27,6 +27,19 @@
>  
>  #define MAX_SIZE_NHDR	MAX(sizeof(Elf64_Nhdr), sizeof(Elf32_Nhdr))
>  
> +struct pt_load_segment {
> +	off_t			file_offset;
> +	unsigned long long	phys_start;
> +	unsigned long long	phys_end;
> +	unsigned long long	virt_start;
> +	unsigned long long	virt_end;
> +};
> +
> +extern off_t			max_file_offset;
> +extern unsigned int		num_pt_loads;
> +extern struct pt_load_segment	*pt_loads;
> +
> +extern off_t			offset_pt_load_memory;
>  
>  off_t paddr_to_offset(unsigned long long paddr);
>  off_t paddr_to_offset2(unsigned long long paddr, off_t hint);
> @@ -44,11 +57,14 @@ int get_elf64_ehdr(int fd, char *filename, Elf64_Ehdr *ehdr);
>  int get_elf32_ehdr(int fd, char *filename, Elf32_Ehdr *ehdr);
>  int get_elf_info(int fd, char *filename);
>  void free_elf_info(void);
> +int get_elf_loads(int fd, char *filename);
>  
>  int is_elf64_memory(void);
>  int is_xen_memory(void);
>  
>  int get_phnum_memory(void);
> +
> +int get_phdr_load(int index, Elf64_Phdr *phdr);
>  int get_phdr_memory(int index, Elf64_Phdr *phdr);
>  off_t get_offset_pt_load_memory(void);
>  int get_pt_load(int idx,
> @@ -68,6 +84,7 @@ void get_pt_note(off_t *offset, unsigned long *size);
>  int has_vmcoreinfo(void);
>  void set_vmcoreinfo(off_t offset, unsigned long size);
>  void get_vmcoreinfo(off_t *offset, unsigned long *size);
> +int set_kcore_vmcoreinfo(uint64_t vmcoreinfo_addr, uint64_t vmcoreinfo_len);
>  
>  int has_vmcoreinfo_xen(void);
>  void get_vmcoreinfo_xen(off_t *offset, unsigned long *size);
> diff --git a/makedumpfile.c b/makedumpfile.c
> index 34db997..ac02747 100644
> --- a/makedumpfile.c
> +++ b/makedumpfile.c
> @@ -5146,6 +5146,7 @@ create_dump_bitmap(void)
>  
>  	if (info->flag_cyclic) {
>  
> +		printf("create_dump_bitmap flag_cyclic\n");
>  		if (info->flag_elf_dumpfile) {
>  			if (!prepare_bitmap_buffer_cyclic())
>  				goto out;
> @@ -5189,14 +5190,23 @@ get_loads_dumpfile(void)
>  
>  	initialize_2nd_bitmap(&bitmap2);
>  
> -	if (!(phnum = get_phnum_memory()))
> -		return FALSE;
> -
> -	for (i = 0; i < phnum; i++) {
> -		if (!get_phdr_memory(i, &load))
> +	if (info->flag_vmcore_estimate) {
> +		phnum = num_pt_loads;
> +	} else {
> +		if (!(phnum = get_phnum_memory()))
>  			return FALSE;
> -		if (load.p_type != PT_LOAD)
> -			continue;
> +	}
> +
> +	for (i = 0; i < num_pt_loads; i++) {
> +		if (info->flag_vmcore_estimate) {
> +			get_phdr_load(i , &load);
> +		} else {
> +			if (!get_phdr_memory(i, &load))
> +				return FALSE;
> +
> +			if (load.p_type != PT_LOAD)
> +				continue;
> +		}
>  
>  		pfn_start = paddr_to_pfn(load.p_paddr);
>  		pfn_end   = paddr_to_pfn(load.p_paddr + load.p_memsz);
> @@ -5734,17 +5744,26 @@ write_elf_pages(struct cache_data *cd_header, struct cache_data *cd_page)
>  	off_seg_load    = info->offset_load_dumpfile;
>  	cd_page->offset = info->offset_load_dumpfile;
>  
> -	if (!(phnum = get_phnum_memory()))
> -		return FALSE;
> +	if (info->flag_vmcore_estimate) {
> +		phnum = num_pt_loads;
> +	} else { 
> +		if (!(phnum = get_phnum_memory()))
> +			return FALSE;
> +	}
>  
>  	gettimeofday(&tv_start, NULL);
>  
>  	for (i = 0; i < phnum; i++) {
> -		if (!get_phdr_memory(i, &load))
> -			return FALSE;
> +		if (info->flag_vmcore_estimate) {
> +			memset(&load, 0, sizeof(load));
> +			get_phdr_load(i , &load);
> +		} else {
> +			if (!get_phdr_memory(i, &load))
> +				return FALSE;
>  
> -		if (load.p_type != PT_LOAD)
> -			continue;
> +			if (load.p_type != PT_LOAD)
> +				continue;
> +		}
>  
>  		off_memory= load.p_offset;
>  		paddr     = load.p_paddr;
> @@ -5923,14 +5942,24 @@ get_loads_dumpfile_cyclic(void)
>  	Elf64_Phdr load;
>  	struct cycle cycle = {0};
>  
> -	if (!(phnum = get_phnum_memory()))
> -		return FALSE;
> +	if (info->flag_vmcore_estimate) {
> +		phnum = num_pt_loads;
> +	} else {
> +		if (!(phnum = get_phnum_memory()))
> +			return FALSE;
> +	}
>  
>  	for (i = 0; i < phnum; i++) {
> -		if (!get_phdr_memory(i, &load))
> -			return FALSE;
> -		if (load.p_type != PT_LOAD)
> -			continue;
> +		if (info->flag_vmcore_estimate) {
> +			memset(&load, 0, sizeof(load) );
> +			get_phdr_load(i , &load);
> +		} else {
> +			if (!get_phdr_memory(i, &load))
> +				return FALSE;
> +
> +			if (load.p_type != PT_LOAD)
> +				continue;
> +		}
>  
>  		pfn_start = paddr_to_pfn(load.p_paddr);
>  		pfn_end = paddr_to_pfn(load.p_paddr + load.p_memsz);
> @@ -6016,17 +6045,26 @@ write_elf_pages_cyclic(struct cache_data *cd_header, struct cache_data *cd_page)
>  	pfn_user = pfn_free = pfn_hwpoison = 0;
>  	pfn_memhole = info->max_mapnr;
>  
> -	if (!(phnum = get_phnum_memory()))
> -		return FALSE;
> +	if (info->flag_vmcore_estimate) {
> +		phnum = num_pt_loads;
> +	} else { 
> +		if (!(phnum = get_phnum_memory()))
> +			return FALSE;
> +	}
>  
>  	gettimeofday(&tv_start, NULL);
>  
>  	for (i = 0; i < phnum; i++) {
> -		if (!get_phdr_memory(i, &load))
> -			return FALSE;
> +		if (info->flag_vmcore_estimate) {
> +			memset(&load, 0, sizeof(load));
> +			get_phdr_load(i , &load);
> +		} else {
> +			if (!get_phdr_memory(i, &load))
> +				return FALSE;
>  
> -		if (load.p_type != PT_LOAD)
> -			continue;
> +			if (load.p_type != PT_LOAD)
> +				continue;
> +		}
>  
>  		off_memory= load.p_offset;
>  		paddr = load.p_paddr;
> @@ -8929,6 +8967,13 @@ check_param_for_creating_dumpfile(int argc, char *argv[])
>  		 */
>  		info->name_memory   = argv[optind];
>  
> +	} else if ((argc == optind + 2) && info->flag_vmcore_estimate) {
> +		/*
> +		 * Parameters for get the /proc/kcore to estimate
> +		 * the size of dumped vmcore
> +		 */
> +		info->name_memory   = argv[optind];
> +		info->name_dumpfile = argv[optind+1];
>  	} else
>  		return FALSE;
>  
> @@ -9011,6 +9056,332 @@ out:
>  	return free_size;
>  }
>  
> +struct memory_range {
> +        unsigned long long start, end;
> +};
> +
> +#define CRASH_RESERVED_MEM_NR   8
> +static struct memory_range crash_reserved_mem[CRASH_RESERVED_MEM_NR];
> +static int crash_reserved_mem_nr;
> +
> +/*
> + * iomem_for_each_line()
> + *
> + * Iterate over each line in the file returned by proc_iomem(). If match is
> + * NULL or if the line matches with our match-pattern then call the
> + * callback if non-NULL.
> + *
> + * Return the number of lines matched.
> + */
> +int iomem_for_each_line(char *match,
> +			      int (*callback)(void *data,
> +					      int nr,
> +					      char *str,
> +					      unsigned long base,
> +					      unsigned long length),
> +			      void *data)
> +{
> +	const char iomem[] = "/proc/iomem";
> +	char line[MAX_LINE];
> +	FILE *fp;
> +	unsigned long long start, end, size;
> +	char *str;
> +	int consumed;
> +	int count;
> +	int nr = 0;
> +
> +	fp = fopen(iomem, "r");
> +	if (!fp) {
> +		ERRMSG("Cannot open %s\n", iomem);
> +		exit(1);
> +	}
> +
> +	while(fgets(line, sizeof(line), fp) != 0) {
> +		count = sscanf(line, "%Lx-%Lx : %n", &start, &end, &consumed);
> +		if (count != 2)
> +			continue;
> +		str = line + consumed;
> +		size = end - start + 1;
> +		if (!match || memcmp(str, match, strlen(match)) == 0) {
> +			if (callback
> +			    && callback(data, nr, str, start, size) < 0) {
> +				break;
> +			}
> +			nr++;
> +		}
> +	}
> +
> +	fclose(fp);
> +
> +	return nr;
> +}
> +
> +static int crashkernel_mem_callback(void *data, int nr,
> +                                          char *str,
> +                                          unsigned long base,
> +                                          unsigned long length)
> +{
> +        if (nr >= CRASH_RESERVED_MEM_NR)
> +                return 1;
> +
> +        crash_reserved_mem[nr].start = base;
> +        crash_reserved_mem[nr].end   = base + length - 1;
> +        return 0;
> +}
> +
> +int is_crashkernel_mem_reserved(void)
> +{
> +        int ret;
> +
> +        ret = iomem_for_each_line("Crash kernel\n",
> +                                        crashkernel_mem_callback, NULL);
> +        crash_reserved_mem_nr = ret;
> +
> +        return !!crash_reserved_mem_nr;
> +}
> +
> +/* Returns the physical address of start of crash notes buffer for a kernel. */
> +static int get_kernel_vmcoreinfo(uint64_t *addr, uint64_t *len)
> +{
> +	char line[MAX_LINE];
> +	int count;
> +	FILE *fp;
> +	unsigned long long temp, temp2;
> +
> +	*addr = 0;
> +	*len = 0;
> +
> +	if (!(fp = fopen("/sys/kernel/vmcoreinfo", "r")))
> +		return -1;
> +
> +	if (!fgets(line, sizeof(line), fp))
> +		ERRMSG("Cannot parse %s: %s\n", "/sys/kernel/vmcoreinfo", strerror(errno));
> +	count = sscanf(line, "%Lx %Lx", &temp, &temp2);
> +	if (count != 2)
> +		ERRMSG("Cannot parse %s: %s\n", "/sys/kernel/vmcoreinfo", strerror(errno));
> +
> +	*addr = (uint64_t) temp;
> +	*len = (uint64_t) temp2;
> +
> +	fclose(fp);
> +	return 0;
> +}
> +
> +
> +static int exclude_segment(struct pt_load_segment **pt_loads, unsigned int	*num_pt_loads, uint64_t start, uint64_t end)
> +{
> +        int i, j, tidx = -1;
> +	unsigned long long	vstart, vend, kvstart, kvend;
> +        struct pt_load_segment temp_seg = {0};
> +	kvstart = (ulong)start | PAGE_OFFSET;
> +	kvend = (ulong)end | PAGE_OFFSET;
> +	unsigned long size;
> +
> +        for (i = 0; i < (*num_pt_loads); i++) {
> +                vstart = (*pt_loads)[i].virt_start;
> +                vend = (*pt_loads)[i].virt_end;
> +                if (kvstart <  vend && kvend > vstart) {
> +                        if (kvstart != vstart && kvend != vend) {
> +				/* Split load segment */
> +				temp_seg.phys_start = end +1;
> +				temp_seg.phys_end = (*pt_loads)[i].phys_end;
> +				temp_seg.virt_start = kvend + 1;
> +				temp_seg.virt_end = vend;
> +				temp_seg.file_offset = (*pt_loads)[i].file_offset + temp_seg.virt_start - (*pt_loads)[i].virt_start;
> +
> +				(*pt_loads)[i].virt_end = kvstart - 1;
> +				(*pt_loads)[i].phys_end =  start -1;
> +
> +				tidx = i+1;
> +                        } else if (kvstart != vstart) {
> +				(*pt_loads)[i].phys_end = start - 1;
> +				(*pt_loads)[i].virt_end = kvstart - 1;
> +                        } else {
> +				(*pt_loads)[i].phys_start = end + 1;
> +				(*pt_loads)[i].virt_start = kvend + 1;
> +                        }
> +                }
> +        }
> +        /* Insert split load segment, if any. */
> +	if (tidx >= 0) {
> +		size = (*num_pt_loads + 1) * sizeof((*pt_loads)[0]);
> +		(*pt_loads) = realloc((*pt_loads), size);
> +		if  (!(*pt_loads) ) {
> +		    ERRMSG("Cannot realloc %ld bytes: %s\n",
> +		            size + 0UL, strerror(errno));
> +			exit(1);
> +		}
> +		for (j = (*num_pt_loads - 1); j >= tidx; j--)
> +		        (*pt_loads)[j+1] = (*pt_loads)[j];
> +		(*pt_loads)[tidx] = temp_seg;
> +		(*num_pt_loads)++;
> +        }
> +        return 0;
> +}
> +
> +static int
> +process_dump_load(struct pt_load_segment	*pls)
> +{
> +	unsigned long long paddr;
> +
> +	paddr = vaddr_to_paddr(pls->virt_start);
> +	pls->phys_start  = paddr;
> +	pls->phys_end    = paddr + (pls->virt_end - pls->virt_start);
> +	MSG("process_dump_load\n");
> +	MSG("  phys_start : %llx\n", pls->phys_start);
> +	MSG("  phys_end   : %llx\n", pls->phys_end);
> +	MSG("  virt_start : %llx\n", pls->virt_start);
> +	MSG("  virt_end   : %llx\n", pls->virt_end);
> +
> +	return TRUE;
> +}
> +
> +int get_kcore_dump_loads()
> +{
> +	struct pt_load_segment	*pls;
> +	int i, j, loads=0;
> +	unsigned long long paddr;
> +
> +	for (i = 0; i < num_pt_loads; ++i) {
> +		struct pt_load_segment *p = &pt_loads[i];
> +		if (is_vmalloc_addr(p->virt_start))
> +			continue;
> +		loads++;
> +	}
> +
> +	pls = calloc(sizeof(struct pt_load_segment), j);
> +	if (pls == NULL) {
> +		ERRMSG("Can't allocate memory for the PT_LOAD. %s\n",
> +		    strerror(errno));
> +		return FALSE;
> +	}
> +
> +	for (i = 0, j=0; i < num_pt_loads; ++i) {
> +		struct pt_load_segment *p = &pt_loads[i];
> +		if (is_vmalloc_addr(p->virt_start))
> +			continue;
> +		if (j >= loads)
> +			return FALSE;
> +
> +		if (j == 0) {
> +			offset_pt_load_memory = p->file_offset;
> +			if (offset_pt_load_memory == 0) {
> +				ERRMSG("Can't get the offset of page data.\n");
> +				return FALSE;
> +			}
> +		}
> +
> +		pls[j] = *p;
> +		process_dump_load(&pls[j]);
> +		j++;
> +	}
> +
> +	free(pt_loads);
> +	pt_loads = pls;
> +	num_pt_loads = loads;
> +
> +	for (i=0; i<crash_reserved_mem_nr; i++)
> +	{
> +		exclude_segment(&pt_loads, &num_pt_loads, crash_reserved_mem[i].start, crash_reserved_mem[i].end);
> +	}
> +
> +	max_file_offset = 0;
> +	for (i = 0; i < num_pt_loads; ++i) {
> +		struct pt_load_segment *p = &pt_loads[i];
> +		max_file_offset = MAX(max_file_offset,
> +				      p->file_offset + p->phys_end - p->phys_start);
> +	}
> +
> +	for (i = 0; i < num_pt_loads; ++i) {
> +		struct pt_load_segment *p = &pt_loads[i];
> +		MSG("LOAD (%d)\n", i);
> +		MSG("  phys_start : %llx\n", p->phys_start);
> +		MSG("  phys_end   : %llx\n", p->phys_end);
> +		MSG("  virt_start : %llx\n", p->virt_start);
> +		MSG("  virt_end   : %llx\n", p->virt_end);
> +	}
> +
> +	return TRUE;
> +}
> +
> +int get_page_offset()
> +{
> +	struct utsname utsname;
> +	if (uname(&utsname)) {
> +		ERRMSG("Cannot get name and information about current kernel : %s", strerror(errno));
> +		return FALSE;
> +	}
> +
> +	info->kernel_version = get_kernel_version(utsname.release);
> +	get_versiondep_info_x86_64();
> +	return TRUE;
> +}
> +
> +int vmcore_estimate(void)
> +{
> +	uint64_t vmcoreinfo_addr, vmcoreinfo_len;
> +	int num_retry, status;
> +
> +	if (!is_crashkernel_mem_reserved()) {
> +		ERRMSG("No memory is reserved for crashkenrel!\n");
> +		exit(1);
> +	}
> +
> +	get_page_offset();
> +
> +#if 1
> +	if (!open_dump_memory())
> +		return FALSE;
> +#endif
> +
> +	if (info->flag_vmcore_estimate) {
> +		if (!get_elf_loads(info->fd_memory, info->name_memory))
> +			return FALSE;
> +	}
> +
> +	if (get_kernel_vmcoreinfo(&vmcoreinfo_addr, &vmcoreinfo_len))
> +		return FALSE;
> +
> +	if (set_kcore_vmcoreinfo(vmcoreinfo_addr, vmcoreinfo_len))
> +		return FALSE;
> +
> +	if (!get_kcore_dump_loads())
> +		return FALSE;
> +
> +#if 1
> +	if (!initial())
> +		return FALSE;
> +#endif
> +
> +retry:
> +	if (!create_dump_bitmap())
> +		return FALSE;
> +
> +	if ((status = writeout_dumpfile()) == FALSE)
> +		return FALSE;
> +
> +	if (status == NOSPACE) {
> +		/*
> +		 * If specifying the other dump_level, makedumpfile tries
> +		 * to create a dumpfile with it again.
> +		 */
> +		num_retry++;
> +		if ((info->dump_level = get_next_dump_level(num_retry)) < 0)
> +			return FALSE;
> +		MSG("Retry to create a dumpfile by dump_level(%d).\n",
> +		    info->dump_level);
> +		if (!delete_dumpfile())
> +			return FALSE;
> +		goto retry;
> +	}
> +	print_report();
> +
> +	clear_filter_info();
> +	if (!close_files_for_creating_dumpfile())
> +		return FALSE;
> +
> +	return TRUE;
> +}
>  
>  /*
>   * Choose the lesser value of the two below as the size of cyclic buffer.
> @@ -9063,6 +9434,7 @@ static struct option longopts[] = {
>  	{"cyclic-buffer", required_argument, NULL, OPT_CYCLIC_BUFFER},
>  	{"eppic", required_argument, NULL, OPT_EPPIC},
>  	{"non-mmap", no_argument, NULL, OPT_NON_MMAP},
> +	{"vmcore-estimate", no_argument, NULL, OPT_VMCORE_ESTIMATE},
>  	{0, 0, 0, 0}
>  };
>  
> @@ -9154,6 +9526,9 @@ main(int argc, char *argv[])
>  		case OPT_DUMP_DMESG:
>  			info->flag_dmesg = 1;
>  			break;
> +		case OPT_VMCORE_ESTIMATE:
> +			info->flag_vmcore_estimate = 1;
> +			break;
>  		case OPT_COMPRESS_SNAPPY:
>  			info->flag_compress = DUMP_DH_COMPRESSED_SNAPPY;
>  			break;
> @@ -9294,6 +9669,19 @@ main(int argc, char *argv[])
>  
>  		MSG("\n");
>  		MSG("The dmesg log is saved to %s.\n", info->name_dumpfile);
> +	} else if (info->flag_vmcore_estimate) {
> +#if 1
> +		if (!check_param_for_creating_dumpfile(argc, argv)) {
> +			MSG("Commandline parameter is invalid.\n");
> +			MSG("Try `makedumpfile --help' for more information.\n");
> +			goto out;
> +		}
> +#endif
> +		if (!vmcore_estimate())
> +			goto out;
> +
> +		MSG("\n");
> +		MSG("vmcore size estimate successfully.\n");
>  	} else {
>  		if (!check_param_for_creating_dumpfile(argc, argv)) {
>  			MSG("Commandline parameter is invalid.\n");
> diff --git a/makedumpfile.h b/makedumpfile.h
> index 9402f05..c401337 100644
> --- a/makedumpfile.h
> +++ b/makedumpfile.h
> @@ -216,6 +216,9 @@ isAnon(unsigned long mapping)
>  #define FILENAME_STDOUT		"STDOUT"
>  #define MAP_REGION		(4096*1024)
>  
> +#define MAX_LINE	160
> +
> +
>  /*
>   * Minimam vmcore has 2 ProgramHeaderTables(PT_NOTE and PT_LOAD).
>   */
> @@ -910,6 +913,7 @@ struct DumpInfo {
>  	int		flag_force;	     /* overwrite existing stuff */
>  	int		flag_exclude_xen_dom;/* exclude Domain-U from xen-kdump */
>  	int             flag_dmesg;          /* dump the dmesg log out of the vmcore file */
> +	int             flag_vmcore_estimate;          /* estimate the size  of vmcore in current system */
>  	int		flag_use_printk_log; /* did we read printk_log symbol name? */
>  	int		flag_nospace;	     /* the flag of "No space on device" error */
>  	int		flag_vmemmap;        /* kernel supports vmemmap address space */
> @@ -1764,6 +1768,7 @@ struct elf_prstatus {
>  #define OPT_CYCLIC_BUFFER       OPT_START+11
>  #define OPT_EPPIC               OPT_START+12
>  #define OPT_NON_MMAP            OPT_START+13
> +#define OPT_VMCORE_ESTIMATE            OPT_START+14
>  
>  /*
>   * Function Prototype.
> -- 
> 1.8.5.3
> 
> 
> _______________________________________________
> kexec mailing list
> kexec at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/kexec



More information about the kexec mailing list