[PATCH] Makedumpfile: vmcore size estimate

bhe at redhat.com bhe at redhat.com
Thu Jun 19 19:33:56 PDT 2014


On 06/20/14 at 01:07am, Atsushi Kumagai wrote:
> Hello Baoquan,
> 
> >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.
> 
> You suggested this feature before, but I don't still agree with this.
> 
> No one can guarantee that the vmcore size will be below the estimated
> size every time. However, if makedumpfile provides "--vmcore-estimate",
> some users may trust it completely and disk overflow might happen. 
> Ideally, users should prepare the disk which can store the possible
> maximum size of vmcore. Of course they can reduce the disk size on their
> responsibility, but makedumpfile can't help it as official feature.

Hi,

Currently I hesitate between 2 different designs. One is dumping
/proc/kcore, user can get its size and check its content. The other is
just give out the dumpable_pages which is just like HP UX has done.

People told me in HP UX if execute crashconf, its output like:

Total pages on system:            260351
Total pages included in dump:     108751

Dump compressed:    ON

Dump Parallel:    ON

This is easier and can also help user. And the dumpable_pages is exactly
the same as vmcore will have if at thie time opoint crash happened.
Since dumping kcore will cause file write, that's the difference between
kcore and vmcore dumping.

What's your opinion on this?

Thanks
Baoquan


> 
> 
> Thanks
> Atsushi Kumagai
> 
> >> 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