diff --git a/zdump/dfi.c b/zdump/dfi.c index e87faf1d..a6dbc282 100644 --- a/zdump/dfi.c +++ b/zdump/dfi.c @@ -809,6 +809,8 @@ int dfi_init(void) l.dfi = dfi; g.fh = dfi_dump_open(g.opts.device); rc = dfi->init(); + if (rc == 0) + dfi_mem_chunk_sort(); if (rc == 0 && dfi_feat_seek()) { kdump_init(); dfi_vmcoreinfo_init(); diff --git a/zdump/dfi_mem_chunk.c b/zdump/dfi_mem_chunk.c index cf6d5102..f02c0e22 100644 --- a/zdump/dfi_mem_chunk.c +++ b/zdump/dfi_mem_chunk.c @@ -324,6 +324,14 @@ void dfi_mem_chunk_read_zero(struct dfi_mem_chunk *UNUSED(mem_chunk), memset(buf, 0, cnt); } +/* + * Sort memory chunks by start value + */ +void dfi_mem_chunk_sort(void) +{ + util_list_sort(&l.mem_virt.chunk_list, mem_chunk_cmp_fn, NULL); +} + /* * Return mem_chunk list head */ @@ -350,6 +358,14 @@ u64 dfi_mem_range(void) return l.mem_virt.end_addr - l.mem_virt.start_addr + 1; } +/* + * Return maximum memory address + */ +u64 dfi_mem_end(void) +{ + return l.mem_virt.end_addr; +} + /* * Is memory range valid? */ diff --git a/zdump/dfi_mem_chunk.h b/zdump/dfi_mem_chunk.h index 2a53a1ae..8ef56181 100644 --- a/zdump/dfi_mem_chunk.h +++ b/zdump/dfi_mem_chunk.h @@ -43,6 +43,7 @@ void dfi_mem_chunk_add(u64 start, u64 size, void *data, dfi_mem_chunk_read_fn read_fn, dfi_mem_chunk_free_fn free_fn); u64 dfi_mem_range(void); +u64 dfi_mem_end(void); int dfi_mem_range_valid(u64 addr, u64 len); unsigned int dfi_mem_chunk_cnt(void); struct dfi_mem_chunk *dfi_mem_chunk_first(void); @@ -54,6 +55,7 @@ struct dfi_mem_chunk *dfi_mem_chunk_find(u64 addr); struct util_list *dfi_mem_chunk_list(void); #define dfi_mem_chunk_iterate(mem_chunk) \ util_list_iterate(dfi_mem_chunk_list(), mem_chunk) +void dfi_mem_chunk_sort(void); int dfi_mem_virt_read(u64 addr, void *buf, size_t cnt); int dfi_mem_phys_read(u64 addr, void *buf, size_t cnt); diff --git a/zdump/dfo_mem_chunk.c b/zdump/dfo_mem_chunk.c index 3b091f9b..fb968ac4 100644 --- a/zdump/dfo_mem_chunk.c +++ b/zdump/dfo_mem_chunk.c @@ -6,6 +6,7 @@ */ #include +#include "lib/util_log.h" #include "zg.h" #include "dfi_mem_chunk.h" @@ -27,6 +28,10 @@ void dfo_chunk_add(u64 start, u64 size, void *data, dfo_chunk_read_fn read_fn) { struct dfo_chunk *dfo_chunk; + util_log_print(UTIL_LOG_DEBUG, "DFO add chunk start=0x%lx, size=0x%lx\n", start, size); + + if (size == 0) + return; dfo_chunk = zg_alloc(sizeof(*dfo_chunk)); dfo_chunk->start = start; dfo_chunk->end = start + size - 1; diff --git a/zdump/dfo_s390.c b/zdump/dfo_s390.c index c7c41da1..fc1636c7 100644 --- a/zdump/dfo_s390.c +++ b/zdump/dfo_s390.c @@ -30,6 +30,7 @@ static struct { struct df_s390_hdr hdr; struct df_s390_em em; + u64 dfi_max_end; // Max end address among processed DFI memory chunks } l; /* @@ -159,19 +160,48 @@ static void add_cpu_to_dfo(struct dfi_cpu *cpu) } /* - * Add memory chunk to dump layout + * Add memory chunk to DFO dump layout. + * The function is supposed to be called in a loop for each DFI mem chunk in the list. + * DFI memory chunk list is considered to be sorted by start address, thus the + * input memory chunk coming last has a priority for DFO. */ static void add_mem_chunk_to_dfo(struct dfi_mem_chunk *mem_chunk) { - struct dfi_mem_chunk *mem_chunk_prev = dfi_mem_chunk_prev(mem_chunk); + const u64 dfo_current_memsz = dfo_chunk_dump_size() - DF_S390_HDR_SIZE; - if (mem_chunk_prev && (mem_chunk_prev->end + 1 != mem_chunk->start)) - dfo_chunk_add(mem_chunk_prev->end + 1 + DF_S390_HDR_SIZE, - mem_chunk->start - mem_chunk_prev->end - 1, + /* + * Consider memory holes and filtered memory pages filling the missing + * areas with zeroes for s390 output format. Keep in mind that dfi_mem_chunks + * can overlap for VR-kernel dumps. + * If no dfi_mem_chunk with zero start address registered, add + * zero DFO memory chunk first. + * + * See the diagram of resulting dfo_s390 for several cases of input memory + * chunks layout below: + * + * DFI DFO(s390) + * --------------------------------- + * aaaa.... HDR|aa|bb|cc|cc + * ..bbbb.. + * ....cccc + * --------------------------------- + * ..aa.... HDR|00|aa|00|bb + * ......bb + * --------------------------------- + * aaaaaaaa HDR|aa|bb|aa|cc + * ..bb.... + * ......cc + */ + if (l.dfi_max_end < mem_chunk->start && + mem_chunk->start - l.dfi_max_end > 1) + dfo_chunk_add(dfo_chunk_dump_size(), + mem_chunk->start - dfo_current_memsz, NULL, dfo_chunk_zero_fn); dfo_chunk_add(mem_chunk->start + DF_S390_HDR_SIZE, mem_chunk->size, mem_chunk, dfo_chunk_mem_fn); + + l.dfi_max_end = MAX(mem_chunk->end, l.dfi_max_end); } /* @@ -187,7 +217,7 @@ static void dump_chunks_init(void) add_mem_chunk_to_dfo(mem_chunk); dfi_cpu_iterate(cpu) add_cpu_to_dfo(cpu); - dfo_chunk_add(dfi_mem_range() + DF_S390_HDR_SIZE, + dfo_chunk_add(l.hdr.mem_size + DF_S390_HDR_SIZE, DF_S390_EM_SIZE, &l.em, dfo_chunk_buf_fn); } @@ -209,7 +239,8 @@ static void df_s390_dump_init(void) else dh->version = 5; dh->mem_start = 0; - dh->mem_size = dh->mem_end = dfi_mem_range(); + dh->mem_end = dfi_mem_end(); + dh->mem_size = dh->mem_end + 1; dh->num_pages = dh->mem_size / PAGE_SIZE; dh->arch = df_s390_from_dfi_arch(dfi_arch()); if (dfi_attr_build_arch())