Files
s390-tools/zipl/boot/eckd2dump_sv.c
T
Mikhail Zaslonko d53bfb9201 zipl/boot: Integrate zlib compression to single volume DASD dumper
Integrate zlib DFLTCC deflate compression to single volume dasd dumper
using the existing s390 extended dump format. Compression takes place
only if DFLTCC facility is available, otherwise dump is written
uncompressed as before.

First megabyte of memory is always written uncompressed and afterwards
this area is used for zlib workspace and for the compression output buffer.
The compression takes place in chunks of data of equal size (currently 1MB)
and the offset of each compressed chunk is stored in the dump segment
header. Since existing dump segment headers of 1 page size are used, we
need to limit the maximum size of compressed dump segments.
Chunk is written uncompressed in case of compression error or if
deflate compression only makes it bigger.

Thus every chunk of data is compressed separately and can be decompressed
independently. The main reason for that is to enable zgetdump to make fast
read seeks. Otherwise, zgetdump would need to decompress a big dump segment
in the worst case to extract a single piece of data.

Put compression related functions and structures to eckd2dump_zlib.c
and eckd2dump_zlib.h

Update zipl man page with the general information of zlib compression
support.

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>
2023-09-27 18:29:06 +02:00

162 lines
4.2 KiB
C

/*
* zipl - zSeries Initial Program Loader tool
*
* Single-volume ECKD DASD dump tool
*
* Copyright IBM Corp. 2013, 2023
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include "lib/zt_common.h"
#include "boot/boot_defs.h"
#include "boot/error.h"
#include "dump/s390_dump.h"
#include "eckd2dump.h"
#include "eckd2dump_zlib.h"
#include "stage2dump.h"
/*
* Magic number at start of dump record
*/
const uint64_t __section(.stage2.head) magic = 0x5845434b44363401ULL; /* "XECKD64", version 1 */
/*
* Get device characteristics from zipl parameter block
*/
void dt_device_parm_setup(void)
{
struct eckd_dump_param *parm = (void *) __stage2_desc;
device.blk_start = parm->blk_start;
device.blk_end = parm->blk_end;
device.blk_size = parm->blk_size;
device.num_heads = parm->num_heads;
device.bpt = parm->bpt;
device.sid = IPL_SC;
}
/*
* Enable DASD device
*/
void dt_device_enable(void)
{
io_irq_enable();
set_device(device.sid, ENABLED);
stage2dump_eckd_init();
}
static unsigned long dt_dump_mem_non_compressed(unsigned long addr,
unsigned long blk)
{
struct df_s390_dump_segm_hdr *dump_segm;
unsigned long end;
dump_segm = (void *)get_zeroed_page();
/* Write memory uncompressed */
end = dump_hdr->mem_size;
while (addr < end) {
addr = find_dump_segment(addr, end, 0, dump_segm);
blk = write_dump_segment(blk, dump_segm);
total_dump_size += dump_segm->len;
if (dump_segm->stop_marker) {
addr = end;
break;
}
}
free_page(__pa(dump_segm));
progress_print(addr);
return blk;
}
static unsigned long dt_dump_mem_compressed(unsigned long addr,
unsigned long blk)
{
struct df_s390_dump_segm_hdr *dump_segm;
unsigned long end;
z_stream strm;
/* Write memory compressed with zlib deflate */
dump_segm = (void *)get_zeroed_page();
end = dump_hdr->mem_size;
/*
* Always write first megabyte of memory uncompressed in
* order to use it as zlib workarea
*/
dump_segm->start = addr;
dump_segm->len = ZLIB_WORKSPACE_LIMIT;
blk = write_dump_segment(blk, dump_segm);
total_dump_size += dump_segm->len;
addr += dump_segm->len;
/* Initialize zlib workarea, return value 0 is expected */
if (zlib_workarea_init(dump_segm->start, &strm)) {
printf("Zlib workarea initialization failed! Dumping without compression");
free_page(__pa(dump_segm));
return dt_dump_mem_non_compressed(addr, blk);
}
/*
* Compress on level 1 (hardware only) using default zlib
* wrapped stream.
*/
if (zlib_deflateInit2(&strm, 1, Z_DEFLATED, MAX_WBITS,
DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK) {
/*
* Could not allocate or initialyze a workarea for zlib deflate,
* continue dumping without compression.
*/
printf("Deflate initialization failed! Dumping without compression");
free_page(__pa(dump_segm));
return dt_dump_mem_non_compressed(addr, blk);
}
while (addr < end) {
/*
* Limit the max size of compressed dump segment in order to
* fit all the compressed chunk entries in the segment header.
*/
addr = find_dump_segment(addr, end, DUMP_SEGM_ZLIB_MAXLEN,
dump_segm);
blk = write_compressed_dump_segment(blk, dump_segm, &strm);
total_dump_size += dump_segm->size_on_disk ?
b2m(dump_segm->size_on_disk) : dump_segm->len;
if (dump_segm->stop_marker) {
addr = end;
break;
}
}
zlib_deflateEnd(&strm);
free_page(__pa(dump_segm));
progress_print(addr);
return blk;
}
/*
* Dump all memory to DASD partition.
* Use zlib compression if DFLTCC facility is available.
*/
void dt_dump_mem(void)
{
unsigned long blk, start, page;
total_dump_size = 0;
/* Write dump header */
blk = device.blk_start;
writeblock(blk, __pa(dump_hdr), m2b(DF_S390_HDR_SIZE), 0);
blk += m2b(DF_S390_HDR_SIZE);
/* Write memory starting from zero address */
start = 0;
/* Check for zlib flag in the dump header */
if (dump_hdr->zlib_version_s390) {
printf("DFLTCC facility available, using zlib compression");
blk = dt_dump_mem_compressed(start, blk);
} else {
blk = dt_dump_mem_non_compressed(start, blk);
}
/* Write end marker */
page = get_zeroed_page();
df_s390_em_page_init(page);
writeblock(blk, page, 1, 0);
free_page(page);
}