zdump/dfo_s390: Support s390 DFO for vr-kernel dumps

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 <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Mikhail Zaslonko
2024-07-26 10:01:17 +02:00
committed by Jan Höppner
parent 147ff1bf49
commit a95bad6c87
5 changed files with 63 additions and 7 deletions

View File

@@ -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();

View File

@@ -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?
*/

View File

@@ -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);

View File

@@ -6,6 +6,7 @@
*/
#include <string.h>
#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;

View File

@@ -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())