From a95bad6c870d75f4de3d0b49407d2b7802b0dbae Mon Sep 17 00:00:00 2001 From: Mikhail Zaslonko Date: Fri, 26 Jul 2024 10:01:17 +0200 Subject: [PATCH] zdump/dfo_s390: Support s390 DFO for vr-kernel dumps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since memory chunks can overlap for vr-kernel dumps stored in elf format (ngdump, zfcpdump), we need to consider this when converting to s390 dump output format. For that sort DFI memory chunks by start address and adjust dfo_s390 logic for identifying memory gaps. Otherwise we might end up with bogus DFO memory chunks being created. Signed-off-by: Mikhail Zaslonko Reviewed-by: Alexander Egorenkov Signed-off-by: Jan Höppner --- zdump/dfi.c | 2 ++ zdump/dfi_mem_chunk.c | 16 +++++++++++++++ zdump/dfi_mem_chunk.h | 2 ++ zdump/dfo_mem_chunk.c | 5 +++++ zdump/dfo_s390.c | 45 ++++++++++++++++++++++++++++++++++++------- 5 files changed, 63 insertions(+), 7 deletions(-) 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())