Currently, 1st bitmap is created during cyclic process, but the information represented by the 1st bitmap, originally present memory, is still available from ELF program header table, so: - we don't need to keep the 1st bitmap even in cyclic process, and - it's possible to avoid the case where for incomplete crash dump generated in failure case due to for example ENOSPC, we don't know where memory is present. Supported is a conversion from ELF to kdump-compressed format only, not from ELF to ELF. Signed-off-by: HATAYAMA Daisuke <d.hatayama at jp.fujitsu.com> --- makedumpfile.c | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 216 insertions(+), 24 deletions(-) diff --git a/makedumpfile.c b/makedumpfile.c index 4b6c0ed..dafe83b 100644 --- a/makedumpfile.c +++ b/makedumpfile.c @@ -3052,10 +3052,23 @@ out: MSG("The buffer size for the cyclic mode will "); MSG("be truncated to %lld byte.\n", free_memory); /* - * bufsize_cyclic is used to allocate 1st and 2nd bitmap, - * so it should be truncated to the half of free_memory. + * On conversion from ELF to ELF, + * bufsize_cyclic is used to allocate + * 1st and 2nd bitmap, so it should be + * truncated to the half of + * free_memory. + * + * On conversion from ELF to + * kdump-compressed format, a whole + * part of the 1st bitmap is created + * first, so a whole part of + * free_memory is used for the 2nd + * bitmap. */ - info->bufsize_cyclic = free_memory / 2; + if (info->flag_elf_dumpfile) + info->bufsize_cyclic = free_memory / 2; + else + info->bufsize_cyclic = free_memory; } } @@ -3328,6 +3341,33 @@ clear_bit_on_2nd_bitmap_for_kernel(unsigned long long pfn) return clear_bit_on_2nd_bitmap(pfn); } +int +set_bit_on_2nd_bitmap(unsigned long long pfn) +{ + if (info->flag_cyclic) { + return set_bitmap_cyclic(info->partial_bitmap2, pfn, 1); + } else { + return set_bitmap(info->bitmap2, pfn, 1); + } +} + +int +set_bit_on_2nd_bitmap_for_kernel(unsigned long long pfn) +{ + unsigned long long maddr; + + if (is_xen_memory()) { + maddr = ptom_xen(pfn_to_paddr(pfn)); + if (maddr == NOT_PADDR) { + ERRMSG("Can't convert a physical address(%llx) to machine address.\n", + pfn_to_paddr(pfn)); + return FALSE; + } + pfn = paddr_to_pfn(maddr); + } + return set_bit_on_2nd_bitmap(pfn); +} + static inline int is_in_segs(unsigned long long paddr) { @@ -4418,6 +4458,53 @@ exclude_zero_pages(void) return TRUE; } +static int +initialize_2nd_bitmap_cyclic(void) +{ + int i; + unsigned long long pfn; + unsigned long long phys_start, phys_end; + unsigned long long pfn_start, pfn_end; + unsigned long long pfn_start_roundup, pfn_end_round; + unsigned long pfn_start_byte, pfn_end_byte; + + /* + * At first, clear all the bits on the 2nd-bitmap. + */ + initialize_bitmap_cyclic(info->partial_bitmap2); + + /* + * If page is on memory hole, set bit on the 2nd-bitmap. + */ + for (i = 0; get_pt_load(i, &phys_start, &phys_end, NULL, NULL); i++) { + pfn_start = MAX(paddr_to_pfn(phys_start), info->cyclic_start_pfn); + pfn_end = MIN(paddr_to_pfn(phys_end), info->cyclic_end_pfn); + + if (pfn_start >= pfn_end) + continue; + + pfn_start_roundup = roundup(pfn_start, BITPERBYTE); + pfn_end_round = round(pfn_end, BITPERBYTE); + + for (pfn = pfn_start; pfn < pfn_start_roundup; ++pfn) + if (!set_bit_on_2nd_bitmap_for_kernel(pfn)) + return FALSE; + + pfn_start_byte = (pfn_start_roundup - info->cyclic_start_pfn) >> 3; + pfn_end_byte = (pfn_end_round - info->cyclic_start_pfn) >> 3; + + memset(info->partial_bitmap2 + pfn_start_byte, + 0xff, + pfn_end_byte - pfn_start_byte); + + for (pfn = pfn_end_round; pfn < pfn_end; ++pfn) + if (!set_bit_on_2nd_bitmap_for_kernel(pfn)) + return FALSE; + } + + return TRUE; +} + int __exclude_unnecessary_pages(unsigned long mem_map, unsigned long long pfn_start, unsigned long long pfn_end) @@ -4584,12 +4671,6 @@ exclude_unnecessary_pages(void) return TRUE; } -void -copy_bitmap_cyclic(void) -{ - memcpy(info->partial_bitmap2, info->partial_bitmap1, info->bufsize_cyclic); -} - int exclude_unnecessary_pages_cyclic(void) { @@ -4597,10 +4678,8 @@ exclude_unnecessary_pages_cyclic(void) struct mem_map_data *mmd; struct timeval tv_start; - /* - * Copy 1st-bitmap to 2nd-bitmap. - */ - copy_bitmap_cyclic(); + if (!initialize_2nd_bitmap_cyclic()) + return FALSE; if ((info->dump_level & DL_EXCLUDE_FREE) && !info->page_is_buddy) if (!exclude_free_page()) @@ -4657,7 +4736,7 @@ update_cyclic_region(unsigned long long pfn) if (info->cyclic_end_pfn > info->max_mapnr) info->cyclic_end_pfn = info->max_mapnr; - if (!create_1st_bitmap_cyclic()) + if (info->flag_elf_dumpfile && !create_1st_bitmap_cyclic()) return FALSE; if (!exclude_unnecessary_pages_cyclic()) @@ -4841,19 +4920,71 @@ prepare_bitmap_buffer_cyclic(void) return TRUE; } +int +prepare_bitmap1_buffer_cyclic(void) +{ + /* + * Prepare partial bitmap buffers for cyclic processing. + */ + if ((info->partial_bitmap1 = (char *)malloc(info->bufsize_cyclic)) == NULL) { + ERRMSG("Can't allocate memory for the 1st bitmaps. %s\n", + strerror(errno)); + return FALSE; + } + initialize_bitmap_cyclic(info->partial_bitmap1); + + return TRUE; +} + +int +prepare_bitmap2_buffer_cyclic(void) +{ + unsigned long tmp; + + /* + * Create 2 bitmaps (1st-bitmap & 2nd-bitmap) on block_size + * boundary. The crash utility requires both of them to be + * aligned to block_size boundary. + */ + tmp = divideup(divideup(info->max_mapnr, BITPERBYTE), info->page_size); + info->len_bitmap = tmp * info->page_size * 2; + + /* + * Prepare partial bitmap buffers for cyclic processing. + */ + if ((info->partial_bitmap2 = (char *)malloc(info->bufsize_cyclic)) == NULL) { + ERRMSG("Can't allocate memory for the 2nd bitmaps. %s\n", + strerror(errno)); + return FALSE; + } + initialize_bitmap_cyclic(info->partial_bitmap2); + + return TRUE; +} + void -free_bitmap_buffer(void) +free_bitmap1_buffer(void) { if (info->bitmap1) { free(info->bitmap1); info->bitmap1 = NULL; } +} + +void +free_bitmap2_buffer(void) +{ if (info->bitmap2) { free(info->bitmap2); info->bitmap2 = NULL; } +} - return; +void +free_bitmap_buffer(void) +{ + free_bitmap1_buffer(); + free_bitmap2_buffer(); } int @@ -4862,10 +4993,21 @@ create_dump_bitmap(void) int ret = FALSE; if (info->flag_cyclic) { - if (!prepare_bitmap_buffer_cyclic()) - goto out; - info->num_dumpable = get_num_dumpable_cyclic(); + if (info->flag_elf_dumpfile) { + if (!prepare_bitmap_buffer_cyclic()) + goto out; + + info->num_dumpable = get_num_dumpable_cyclic(); + } else { + if (!prepare_bitmap2_buffer_cyclic()) + goto out; + + info->num_dumpable = get_num_dumpable_cyclic(); + + free_bitmap2_buffer(); + } + } else { if (!prepare_bitmap_buffer()) goto out; @@ -6564,7 +6706,7 @@ out: } int -write_kdump_bitmap_cyclic(void) +write_kdump_bitmap1_cyclic(void) { off_t offset; int increment; @@ -6576,10 +6718,30 @@ write_kdump_bitmap_cyclic(void) return FALSE; offset = info->offset_bitmap1; - if (!write_buffer(info->fd_dumpfile, offset, + if (!write_buffer(info->fd_dumpfile, offset + info->bufsize_cyclic * + (info->cyclic_start_pfn / info->pfn_cyclic), info->partial_bitmap1, increment, info->name_dumpfile)) goto out; + ret = TRUE; +out: + return ret; +} + +int +write_kdump_bitmap2_cyclic(void) +{ + off_t offset; + int increment; + int ret = FALSE; + + increment = divideup(info->cyclic_end_pfn - info->cyclic_start_pfn, + BITPERBYTE); + + if (info->flag_elf_dumpfile) + return FALSE; + + offset = info->offset_bitmap1; offset += info->len_bitmap / 2; if (!write_buffer(info->fd_dumpfile, offset, info->partial_bitmap2, increment, info->name_dumpfile)) @@ -6633,6 +6795,30 @@ write_kdump_pages_and_bitmap_cyclic(struct cache_data *cd_header, struct cache_d } /* + * Write the 1st bitmap + */ + if (!prepare_bitmap1_buffer_cyclic()) + return FALSE; + + info->cyclic_start_pfn = 0; + info->cyclic_end_pfn = 0; + for (pfn = 0; pfn < info->max_mapnr; pfn++) { + if (is_cyclic_region(pfn)) + continue; + if (!update_cyclic_region(pfn)) + return FALSE; + if (!create_1st_bitmap_cyclic()) + return FALSE; + if (!write_kdump_bitmap1_cyclic()) + return FALSE; + } + + free_bitmap1_buffer(); + + if (!prepare_bitmap2_buffer_cyclic()) + return FALSE; + + /* * Write pages and bitmap cyclically. */ info->cyclic_start_pfn = 0; @@ -6647,7 +6833,7 @@ write_kdump_pages_and_bitmap_cyclic(struct cache_data *cd_header, struct cache_d if (!write_kdump_pages_cyclic(cd_header, cd_page, &pd_zero, &offset_data)) return FALSE; - if (!write_kdump_bitmap_cyclic()) + if (!write_kdump_bitmap2_cyclic()) return FALSE; } @@ -8681,8 +8867,14 @@ calculate_cyclic_buffer_size(void) { * should be 40% of free memory to keep the size of cyclic buffer * within 80% of free memory. */ - free_size = get_free_memory_size() * 0.4; - needed_size = (info->max_mapnr * 2) / BITPERBYTE; + if (info->flag_elf_dumpfile) { + free_size = get_free_memory_size() * 0.4; + needed_size = (info->max_mapnr * 2) / BITPERBYTE; + } else { + free_size = get_free_memory_size() * 0.8; + needed_size = info->max_mapnr / BITPERBYTE; + } + /* if --split was specified cyclic buffer allocated per dump file */ if (info->num_dumpfile > 1) needed_size /= info->num_dumpfile;