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