From ee4cb78dc2d1ef668859b2b3168762c91e96ff72 Mon Sep 17 00:00:00 2001 From: Mikhail Zaslonko Date: Thu, 20 Mar 2025 12:00:15 +0100 Subject: [PATCH] zdump: Drop non-extended multi-volume DASD dump support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since DASD standalone dumper does not support non-extended s390 multi-volume dumps for years, drop zgetdump support of non-extended s390_mv DASD dumps and dump-tools: - Merge dfi_s390mv_ext and dt_s390mv_ext with related dfi_s390mv and dt_s390mv counterparts. - Update DFI and DT vectors of supported dump formats and dump-tools removing dfi_s390mv and dt_s390mv entries and keeping dt_s390mv_ext and dfi_s390mv_ext ones for s390_mv extended dump and dump-tool accordingly. - Remove dfi_s390mv.c and dt_s390mv.c sources and update the Makefile. - Make dfi_s390mv_ext_init() and dfi_s390mv_info() static. - Remove magic number relevant to non-extended s390_mv DASD dumper. - Completely drop DASD dumper version 5 case in df_s390_dumper_read(). Note: Since non-extended s390 multi-volume dumps can reside on DASD partitions only and cannot be produced via DFO interface, we can drop this dump format entirely. Signed-off-by: Mikhail Zaslonko Reviewed-by: Alexander Egorenkov Signed-off-by: Jan Höppner --- include/dump/s390_dump.h | 1 - zdump/Makefile | 6 +- zdump/df_s390.c | 5 - zdump/df_s390.h | 4 +- zdump/dfi.c | 1 - zdump/dfi.h | 1 - zdump/dfi_s390mv.c | 661 --------------------------------------- zdump/dfi_s390mv_ext.c | 530 ++++++++++++++++++++++++++++++- zdump/dt.c | 1 - zdump/dt.h | 1 - zdump/dt_s390mv.c | 30 -- zdump/dt_s390mv_ext.c | 10 +- zipl/src/install.c | 1 - 13 files changed, 531 insertions(+), 721 deletions(-) delete mode 100644 zdump/dfi_s390mv.c delete mode 100644 zdump/dt_s390mv.c diff --git a/include/dump/s390_dump.h b/include/dump/s390_dump.h index 6d1d1171..8d3dfe41 100644 --- a/include/dump/s390_dump.h +++ b/include/dump/s390_dump.h @@ -29,7 +29,6 @@ #define DF_S390_DUMPER_MAGIC_SIZE 7 #define DF_S390_DUMPER_MAGIC_EXT "XECKD64" #define DF_S390_DUMPER_MAGIC_FBA_EXT "XDFBA64" -#define DF_S390_DUMPER_MAGIC_MV "ZMULT64" #define DF_S390_DUMPER_MAGIC_MV_EXT "XMULT64" /* diff --git a/zdump/Makefile b/zdump/Makefile index 2cadfe77..5e862a7e 100644 --- a/zdump/Makefile +++ b/zdump/Makefile @@ -67,14 +67,12 @@ endif OBJECTS = zgetdump.o opts.o zg.o zg_error.o zg_print.o \ dfi.o dfi_mem_chunk.o dfi_vmcoreinfo.o \ dfi_lkcd.o dfi_elf.o dfi_elf_common.o dfi_pv_elf.o \ - dfi_s390.o dfi_s390_ext.o\ - dfi_s390mv.o dfi_s390mv_ext.o \ + dfi_s390.o dfi_s390_ext.o dfi_s390mv_ext.o \ dfi_s390tape.o dfi_kdump.o \ dfi_devmem.o dfo.o dfo_mem_chunk.o \ dfo_elf.o dfo_s390.o \ df_elf.o df_s390.o \ - dt.o dt_s390sv_ext.o \ - dt_s390mv.o dt_s390mv_ext.o \ + dt.o dt_s390sv_ext.o dt_s390mv_ext.o \ dt_scsi.o output.o \ ngdump.o dt_ngdump.o dfi_ngdump.o dfi_vmdump.o \ pv_utils.o diff --git a/zdump/df_s390.c b/zdump/df_s390.c index 4c589953..1c3741d6 100644 --- a/zdump/df_s390.c +++ b/zdump/df_s390.c @@ -168,11 +168,6 @@ int df_s390_dumper_read(struct zg_fh *fh, int blk_size, DF_S390_DUMPER_MAGIC_SIZE) == 0) dumper->size = STAGE2_DUMPER_SIZE_MV; break; - case 5: - if (strncmp(dumper->magic, DF_S390_DUMPER_MAGIC_MV, - DF_S390_DUMPER_MAGIC_SIZE) == 0) - dumper->size = STAGE2_DUMPER_SIZE_SV; - break; } if (dumper->size == 0) return -1; diff --git a/zdump/df_s390.h b/zdump/df_s390.h index 0fb0ffbb..b2052227 100644 --- a/zdump/df_s390.h +++ b/zdump/df_s390.h @@ -59,11 +59,9 @@ extern int df_s390_dumper_read(struct zg_fh *fh, int32_t blk_size, /* * DASD dt and dfi functions */ -extern int dt_s390mv_init_gen(bool extended); +extern int dt_s390mv_ext_init(void); extern void dt_s390mv_info(void); extern int dfi_s390_init_gen(bool extended); -extern int dfi_s390mv_init_gen(bool extended); -extern void dfi_s390mv_info(void); #endif /* DF_S390_H */ diff --git a/zdump/dfi.c b/zdump/dfi.c index a6dbc282..39198566 100644 --- a/zdump/dfi.c +++ b/zdump/dfi.c @@ -30,7 +30,6 @@ static struct dfi *dfi_vec[] = { &dfi_s390tape, &dfi_devmem, &dfi_s390mv_ext, - &dfi_s390mv, &dfi_s390_ext, &dfi_s390, &dfi_lkcd, diff --git a/zdump/dfi.h b/zdump/dfi.h index 6624601f..0e1567be 100644 --- a/zdump/dfi.h +++ b/zdump/dfi.h @@ -248,7 +248,6 @@ extern u64 dfi_live_dump_magic; * Supported DFI dump formats */ extern struct dfi dfi_s390tape; -extern struct dfi dfi_s390mv; extern struct dfi dfi_s390mv_ext; extern struct dfi dfi_s390; extern struct dfi dfi_s390_ext; diff --git a/zdump/dfi_s390mv.c b/zdump/dfi_s390mv.c deleted file mode 100644 index 92c6e2f2..00000000 --- a/zdump/dfi_s390mv.c +++ /dev/null @@ -1,661 +0,0 @@ -/* - * zgetdump - Tool for copying and converting System z dumps - * - * S390 multi-volume dump input format - * - * Copyright IBM Corp. 2001, 2018 - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "lib/util_file.h" -#include "lib/util_path.h" -#include "dump/s390_dump.h" - -#include "zgetdump.h" -#include "dt.h" -#include "df_s390.h" -#include "dfi.h" -#include "dfi_s390mv.h" -#include "dfi_mem_chunk.h" - -/* - * Volume information - */ -struct vol { - dev_t dev; - struct zg_fh *fh; - char *devnode; - enum dev_status status; - enum dev_sign sign; - off_t part_off; - u64 part_size; - u64 mem_start; - u64 mem_end; - char bus_id[10]; - u32 nr; - u16 blk_size; - struct df_s390_dumper dumper; - struct df_s390_hdr hdr; -}; - -/* - * Mem chunk helper structure for extended dump format - */ -struct vol_mem_chunk { - struct vol *vol; - u64 off; /* Offset to the memory chunk from the start of the volume */ -}; - -/* - * File local static data - */ -static struct { - struct df_s390_hdr hdr; - struct df_s390_em em; - struct vol vol_vec[MAX_VOLUMES]; - struct vol_parm_table table; - int blk_size; - struct df_s390_dumper dumper; - int dump_incomplete; - bool extended; - u64 magic_number; /* Reference value to compare with */ - char dumper_magic[DF_S390_DUMPER_MAGIC_SIZE]; /* Reference value to compare with */ -} l; - -/* - * Read volume parameter table - */ -static void table_read(struct zg_fh *fh, u16 blk_size, - struct vol_parm_table *table) -{ - int off; - - off = DF_S390_MAGIC_BLK_ECKD * blk_size + l.dumper.size; - zg_seek(fh, off, ZG_CHECK); - zg_read(fh, table, sizeof(*table), ZG_CHECK); -} - -/* - * Initialize dump end marker - */ -static void em_init(struct vol *vol) -{ - off_t em_off; - - em_off = vol->part_off + (vol->mem_end + 1 - vol->mem_start) + - DF_S390_HDR_SIZE; - zg_seek(vol->fh, em_off, ZG_CHECK); - zg_read(vol->fh, &l.em, sizeof(l.em), ZG_CHECK); - if (df_s390_em_verify(&l.em, &l.hdr) != 0) - l.dump_incomplete = 1; -} - -/* - * Check whether a device with a given busid is online - */ -static unsigned int dev_is_online(const char *busid) -{ - unsigned int online; - char *path; - - path = util_path_sysfs("%s/%s/online", SYSFS_BUSDIR, busid); - if (util_file_read_ui(&online, 10, path) != 0) { - warnx("Could not open \"%s\" (%s)", path, strerror(errno)); - free(path); - exit(EXIT_FAILURE); - } - free(path); - - return online; -} - -/* - * Check sysfs, whether a device specified by its bus ID is defined and online. - * Find out the corresponding dev_t - */ -static enum dev_status dev_from_busid(char *bus_id, dev_t *dev) -{ - struct dirent *direntp; - int minor, major; - char buf[10]; - DIR *fh_dir; - char *sysfs; - - sysfs = util_path_sysfs("%s/%s", SYSFS_BUSDIR, bus_id); - if (!util_path_is_dir(sysfs)) { - free(sysfs); - return DEV_UNDEFINED; - } - free(sysfs); - - if (!dev_is_online(bus_id)) - return DEV_OFFLINE; - - sysfs = util_path_sysfs("%s/%s/block", SYSFS_BUSDIR, bus_id); - fh_dir = opendir(sysfs); - if (!fh_dir) { - warnx("Could not open \"%s\" (%s) ", sysfs, strerror(errno)); - goto err; - } - while ((direntp = readdir(fh_dir))) - if (strncmp(direntp->d_name, "dasd", 4) == 0) - break; - if (direntp == NULL) { - warnx("Problem with contents of \"%s\"", sysfs); - goto err; - } - if (util_file_read_line(buf, sizeof(buf), "%s/%s/dev", sysfs, direntp->d_name)) { - warnx("Could not read dev file (%s)", strerror(errno)); - goto err; - } - closedir(fh_dir); - - if (sscanf(buf, "%i:%i", &major, &minor) != 2) { - warnx("Malformed content of \"%s\": %s", sysfs, buf); - goto err; - } - *dev = makedev(major, minor); - - free(sysfs); - - return DEV_ONLINE; - -err: - if (fh_dir) - closedir(fh_dir); - free(sysfs); - exit(EXIT_FAILURE); -} - -/* - * Check whether dump table on user specified dump device is - * identical to the one found on this device. - */ -static void check_vol_table(struct vol *vol) -{ - struct vol_parm_table vol_table; - - table_read(vol->fh, vol->blk_size, &vol_table); - if (memcmp(&vol_table, &l.table, sizeof(vol_table))) - ERR_EXIT("Orphaned multi-volume dump device '%s'", - g.opts.device); -} - -/* - * Read dump tool, multi-volume dump parameter table, and dump header from the - * input dump volume. Check input dump volume for: - * - identical dump parameter table (that is it belongs to the same dump set) - * - valid magic number in the dump tool - * - valid dump sign in the dump header - * - * We read partition data via the device node. If another process - * has changed partition data via the partition node, the corresponding - * device node might still have old data in its buffers. Flush buffers - * to keep things in sync. - */ -static void vol_read(struct vol *vol) -{ - zg_ioctl(vol->fh, BLKFLSBUF, NULL, "BLKFLSBUF", ZG_CHECK); - if (df_s390_dumper_read(vol->fh, vol->blk_size, &vol->dumper)) - ERR_EXIT("No dump tool found on the multi-volume dump device '%s'", - vol->bus_id); - check_vol_table(vol); - zg_seek(vol->fh, vol->part_off, ZG_CHECK); - zg_read(vol->fh, &vol->hdr, DF_S390_HDR_SIZE, ZG_CHECK); -} - -/* - * Read memory chunk - */ -static void dfi_s390mv_mem_read(struct dfi_mem_chunk *mem_chunk, u64 off, - void *buf, u64 cnt) -{ - struct vol *vol = mem_chunk->data; - - zg_seek(vol->fh, vol->part_off + off + DF_S390_HDR_SIZE, ZG_CHECK); - zg_read(vol->fh, buf, cnt, ZG_CHECK); -} - -/* - * Read memory chunk (extended) - */ -static void dfi_s390mv_ext_mem_read(struct dfi_mem_chunk *mem_chunk, u64 off, - void *buf, u64 cnt) -{ - struct vol_mem_chunk *vol_mem_chunk = mem_chunk->data; - struct vol *vol = vol_mem_chunk->vol; - - zg_seek(vol->fh, vol_mem_chunk->off + off, ZG_CHECK); - zg_read(vol->fh, buf, cnt, ZG_CHECK); -} - -/* - * Initialize DASD volume - */ -static void vol_init(struct vol *vol, struct vol_parm *vol_parm, int ssid, - u64 *mem_off) -{ - u64 blk_cnt = vol_parm->end_blk - vol_parm->start_blk + 1; - - sprintf(vol->bus_id, "0.%x.%04x", ssid, vol_parm->devno); - vol->blk_size = vol_parm->blk_size << 8; - vol->part_off = (u64)vol_parm->start_blk * vol->blk_size; - vol->part_size = blk_cnt * vol->blk_size; - vol->status = dev_from_busid(vol->bus_id, &vol->dev); - vol->sign = SIGN_VALID; - - if (vol->status != DEV_ONLINE) - return; - - vol->devnode = zg_devnode_create(vol->dev); - vol->fh = dfi_dump_open(vol->devnode); - - vol_read(vol); - - if ((vol->hdr.volnr == vol->nr) && (vol->hdr.mem_size != 0)) - vol->sign = SIGN_ACTIVE; - - if (vol->hdr.mvdump_sign != l.magic_number) { - vol->sign = SIGN_INVALID; - l.dump_incomplete = 1; - } - - if (strncmp(vol->dumper.magic, l.dumper_magic, DF_S390_DUMPER_MAGIC_SIZE) != 0) { - vol->sign = SIGN_INVALID; - l.dump_incomplete = 1; - } - - if (vol->nr == 0) - l.hdr = vol->hdr; - - if (l.extended) - return; - - if (*mem_off == l.hdr.mem_size) { - /* Unused volume */ - vol->mem_start = 0; - vol->mem_end = 0; - if (vol->sign == SIGN_ACTIVE) - vol->sign = SIGN_VALID; - } else { - /* Used volume */ - vol->mem_start = *mem_off; - vol->mem_end = *mem_off + PAGE_ALIGN(vol->part_size) - - DF_S390_HDR_SIZE - 1; - vol->mem_end = MIN(vol->mem_end, l.hdr.mem_size - 1); - if (vol->mem_end == l.hdr.mem_size - 1) - em_init(vol); - *mem_off += vol->mem_end - vol->mem_start + 1; - } -} - -/* - * Print volume information - */ -static void vol_print(struct vol *vol) -{ - STDERR(" Volume %i: %s (%s", vol->nr, vol->bus_id, - dev_status_str(vol->status)); - if (vol->status == DEV_ONLINE) - STDERR("/%s)\n", dev_sign_str(vol->sign)); - else - STDERR(")\n"); -} - -/* - * Print information for all volumes - */ -static void vol_print_all(void) -{ - unsigned int i; - - for (i = 0; i < l.table.vol_cnt; i++) - vol_print(&l.vol_vec[i]); -} - -/* - * Add memory chunks - */ -static void mem_chunks_add(void) -{ - struct vol *vol; - unsigned int i; - - for (i = 0; i < l.table.vol_cnt; i++) { - vol = &l.vol_vec[i]; - if (vol->sign != SIGN_ACTIVE) - continue; - dfi_mem_chunk_add_vol(vol->mem_start, - vol->mem_end - vol->mem_start + 1, - vol, dfi_s390mv_mem_read, NULL, vol->nr); - } -} - -/* - * Add memory chunks (extended dump format) and verify the end marker - */ -static int mem_chunks_add_ext(void) -{ - u64 off, rc, part_end, old = 0, dump_size = 0; - struct df_s390_dump_segm_hdr dump_segm; - struct vol_mem_chunk *vol_mem_chunk; - unsigned int i; - - for (i = 0; i < l.table.vol_cnt; i++) { - struct vol *vol = &l.vol_vec[i]; - if (vol->sign != SIGN_ACTIVE) - continue; - off = vol->part_off + DF_S390_HDR_SIZE; - part_end = vol->part_off + vol->part_size; - rc = zg_seek(vol->fh, off, ZG_CHECK_NONE); - if (rc != off) - return -EINVAL; - /* - * Reading dump segments from the start of partition (skipping - * the dump header) till the end of partition (considering that - * minimum dump segment size is one megabyte + one page and one - * more page is reserved for the end marker) - */ - while (off < part_end - MIB - PAGE_SIZE) { - rc = zg_read(vol->fh, &dump_segm, sizeof(dump_segm), - ZG_CHECK_ERR); - if (rc != PAGE_SIZE) - return -EINVAL; - off += PAGE_SIZE; - vol_mem_chunk = zg_alloc(sizeof(*vol_mem_chunk)); - vol_mem_chunk->vol = vol; - vol_mem_chunk->off = off; - /* Add zero memory chunk */ - dfi_mem_chunk_add_vol(old, dump_segm.start - old, NULL, - dfi_mem_chunk_read_zero, NULL, - vol->nr); - /* Add memory chunk for a dump segment */ - dfi_mem_chunk_add_vol(dump_segm.start, dump_segm.len, - vol_mem_chunk, - dfi_s390mv_ext_mem_read, NULL, - vol->nr); - old = dump_segm.start + dump_segm.len; - dump_size += dump_segm.len; - off = zg_seek_cur(vol->fh, dump_segm.len, - ZG_CHECK_NONE); - if (dump_segm.stop_marker) - break; - } - if (dump_segm.stop_marker) { - /* Add zero memory chunk at the end*/ - dfi_mem_chunk_add_vol(old, l.hdr.mem_size - old, NULL, - dfi_mem_chunk_read_zero, NULL, - vol->nr); - /* Set the actual size of the dump file */ - dfi_attr_file_size_set(dump_size); - /* Read and verify the end marker */ - rc = zg_read(vol->fh, &l.em, sizeof(l.em), ZG_CHECK); - if (rc != sizeof(l.em) || - df_s390_em_verify(&l.em, &l.hdr) != 0) - return -EINVAL; - return 0; - } - } - /* No dump segment with the stop marker found */ - return -EINVAL; -} - -/* - * Print hint for setting all offline volumes online - */ -static void vol_offline_msg(void) -{ - unsigned int i, first = 1; - - STDERR("\n"); - STDERR("Set all devices online using:\n"); - STDERR("# chccwdev -e "); - for (i = 0; i < l.table.vol_cnt; i++) { - if (l.vol_vec[i].status == DEV_OFFLINE) { - if (first) - first = 0; - else - STDERR(","); - STDERR("%s", l.vol_vec[i].bus_id); - } - } - STDERR("\n"); -} - -/* - * Print error for all undefined volumes - */ -static void vol_undefined_msg(void) -{ - unsigned int i; - - STDERR("\n"); - STDERR("Ensure that the following devices are available to the " - "system:\n"); - for (i = 0; i < l.table.vol_cnt; i++) { - if (l.vol_vec[i].status == DEV_UNDEFINED) - STDERR("* %s\n", l.vol_vec[i].bus_id); - } -} - -/* - * Check that all volumes are in online state - */ -static int vol_online_check(void) -{ - unsigned int i, offline = 0, undefined = 0; - - for (i = 0; i < l.table.vol_cnt; i++) { - if (l.vol_vec[i].status == DEV_OFFLINE) - offline = 1; - if (l.vol_vec[i].status == DEV_UNDEFINED) - undefined = 1; - } - if (!offline && !undefined) - return 0; - - STDERR("Found multi-volume dump tool:\n\n"); - vol_print_all(); - if (offline) - vol_offline_msg(); - if (undefined) - vol_undefined_msg(); - return -ENODEV; -} - -/* - * Check if on device is a multi-volume dump - */ -static int mvdump_hdr_check(const char *file) -{ - struct df_s390_hdr hdr; - struct zg_fh *fh; - int rc = -ENODEV; - - fh = zg_open(file, O_RDONLY, ZG_CHECK); - if (zg_read(fh, &hdr, sizeof(hdr), ZG_CHECK_ERR) != sizeof(hdr)) - goto fail; - if (hdr.magic != l.magic_number) - goto fail; - if (hdr.mvdump_sign != l.magic_number) - goto fail; - rc = 0; -fail: - zg_close(fh); - return rc; -} - -/* - * Read dump tool from DASD and check if we have a multi-volume dump tool - */ -static int mv_dumper_read(void) -{ - if (zg_ioctl(g.fh, BLKSSZGET, &l.blk_size, "BLKSSZGET", - ZG_CHECK_NONE) == -1) - return -ENODEV; - if (df_s390_dumper_read(g.fh, l.blk_size, &l.dumper)) - return -ENODEV; - if (strncmp(l.dumper.magic, l.dumper_magic, DF_S390_DUMPER_MAGIC_SIZE) != 0) - return -ENODEV; - table_read(g.fh, l.blk_size, &l.table); - return 0; -} - -/* - * Initialize all volumes - */ -static void volumes_init(void) -{ - u64 mem_off = 0; - unsigned int i; - - for (i = 0; i < l.table.vol_cnt; i++) { - l.vol_vec[i].nr = i; - vol_init(&l.vol_vec[i], &l.table.vol_parm[i], l.table.ssid[i], - &mem_off); - } - if (l.extended) - return; - if (mem_off != l.hdr.mem_size) - l.dump_incomplete = 1; -} - -/* - * Open dump - If partition is specified open device instead - */ -static int open_dump(void) -{ - const struct stat *stat = zg_stat(g.fh); - unsigned int dev_minor; - enum zg_type type; - char *path; - - type = zg_type(g.fh); - if (type != ZG_TYPE_DASD && type != ZG_TYPE_DASD_PART) - return -ENODEV; - - if (type == ZG_TYPE_DASD_PART) { - dev_minor = minor(stat->st_rdev) - (minor(stat->st_rdev) % 4); - if (mvdump_hdr_check(zg_path(g.fh)) != 0) - return -ENODEV; - path = zg_devnode_create(makedev(major(stat->st_rdev), - dev_minor)); - zg_close(g.fh); - g.fh = zg_open(path, O_RDONLY, ZG_CHECK); - } - if (mv_dumper_read() != 0) - return -ENODEV; - return 0; -} - -/* - * Specify reference values for dumper magic and dump magic numbers - */ -static void set_magic_numbers(void) -{ - if (l.extended) { - l.magic_number = DF_S390_MAGIC_EXT; - memcpy(l.dumper_magic, DF_S390_DUMPER_MAGIC_MV_EXT, - DF_S390_DUMPER_MAGIC_SIZE); - } else { - l.magic_number = DF_S390_MAGIC; - memcpy(l.dumper_magic, DF_S390_DUMPER_MAGIC_MV, - DF_S390_DUMPER_MAGIC_SIZE); - } -} - -/* - * Initialize s390 multi-volume input dump format generic function - */ -int dfi_s390mv_init_gen(bool extended) -{ - int rc; - - l.extended = extended; - set_magic_numbers(); - if (open_dump() != 0) - return -ENODEV; - volumes_init(); - if (vol_online_check() != 0) - zg_exit(1); - if (l.hdr.mem_size == 0) - return -ENODEV; - df_s390_hdr_add(&l.hdr); - if (!extended) - mem_chunks_add(); - else if (mem_chunks_add_ext() != 0) - return -EINVAL; - if (l.dump_incomplete) - return -EINVAL; - rc = df_s390_cpu_info_add(&l.hdr, l.hdr.mem_end); - if (rc) - return rc; - df_s390_em_add(&l.em); - return 0; -} - -/* - * Initializt s390 multi-volume input dump - */ -static int dfi_s390mv_init(void) -{ - return dfi_s390mv_init_gen(DUMP_NON_EXTENDED); -} - -/* - * Print dump information (dfi operation) - */ -void dfi_s390mv_info(void) -{ - vol_print_all(); -} - -/* - * Initialize s390 multi-volume dump tool generic function - */ -int dt_s390mv_init_gen(bool extended) -{ - l.extended = extended; - set_magic_numbers(); - if (open_dump() != 0) - return -ENODEV; - volumes_init(); - dt_arch_set(DFI_ARCH_64); - dt_version_set(l.dumper.version); - dt_attr_mem_limit_set(l.dumper.mem); - dt_attr_force_set(l.dumper.force); - return 0; -} - -/* - * s390 multi-volume dump tool info function (for -d option) - */ -void dt_s390mv_info(void) -{ - vol_print_all(); -} - -/* - * S390 multi-volume DFI operations - */ -struct dfi dfi_s390mv = { - .name = "s390mv", - .init = dfi_s390mv_init, - .info_dump = dfi_s390mv_info, - .feat_bits = DFI_FEAT_COPY | DFI_FEAT_SEEK, -}; diff --git a/zdump/dfi_s390mv_ext.c b/zdump/dfi_s390mv_ext.c index 4f5fad69..81c410df 100644 --- a/zdump/dfi_s390mv_ext.c +++ b/zdump/dfi_s390mv_ext.c @@ -3,23 +3,547 @@ * * S390x multi-volume dump input format * - * Copyright IBM Corp. 2001, 2018 + * Copyright IBM Corp. 2001, 2025 * * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lib/util_file.h" +#include "lib/util_path.h" +#include "dump/s390_dump.h" + #include "zgetdump.h" #include "dt.h" #include "df_s390.h" #include "dfi.h" +#include "dfi_s390mv.h" +#include "dfi_mem_chunk.h" /* - * Initialize s390 multi-volume input dump format (extedend) + * Volume information + */ +struct vol { + dev_t dev; + struct zg_fh *fh; + char *devnode; + enum dev_status status; + enum dev_sign sign; + off_t part_off; + u64 part_size; + u64 mem_start; + u64 mem_end; + char bus_id[10]; + u32 nr; + u16 blk_size; + struct df_s390_dumper dumper; + struct df_s390_hdr hdr; +}; + +/* + * Mem chunk helper structure for extended dump format + */ +struct vol_mem_chunk { + struct vol *vol; + u64 off; /* Offset to the memory chunk from the start of the volume */ +}; + +/* + * File local static data + */ +static struct { + struct df_s390_hdr hdr; + struct df_s390_em em; + struct vol vol_vec[MAX_VOLUMES]; + struct vol_parm_table table; + int blk_size; + struct df_s390_dumper dumper; + int dump_incomplete; +} l; + +/* + * Read volume parameter table + */ +static void table_read(struct zg_fh *fh, u16 blk_size, + struct vol_parm_table *table) +{ + int off; + + off = DF_S390_MAGIC_BLK_ECKD * blk_size + l.dumper.size; + zg_seek(fh, off, ZG_CHECK); + zg_read(fh, table, sizeof(*table), ZG_CHECK); +} + +/* + * Check whether a device with a given busid is online + */ +static unsigned int dev_is_online(const char *busid) +{ + unsigned int online; + char *path; + + path = util_path_sysfs("%s/%s/online", SYSFS_BUSDIR, busid); + if (util_file_read_ui(&online, 10, path) != 0) { + warnx("Could not open \"%s\" (%s)", path, strerror(errno)); + free(path); + exit(EXIT_FAILURE); + } + free(path); + + return online; +} + +/* + * Check sysfs, whether a device specified by its bus ID is defined and online. + * Find out the corresponding dev_t + */ +static enum dev_status dev_from_busid(char *bus_id, dev_t *dev) +{ + struct dirent *direntp; + int minor, major; + char buf[10]; + DIR *fh_dir; + char *sysfs; + + sysfs = util_path_sysfs("%s/%s", SYSFS_BUSDIR, bus_id); + if (!util_path_is_dir(sysfs)) { + free(sysfs); + return DEV_UNDEFINED; + } + free(sysfs); + + if (!dev_is_online(bus_id)) + return DEV_OFFLINE; + + sysfs = util_path_sysfs("%s/%s/block", SYSFS_BUSDIR, bus_id); + fh_dir = opendir(sysfs); + if (!fh_dir) { + warnx("Could not open \"%s\" (%s) ", sysfs, strerror(errno)); + goto err; + } + while ((direntp = readdir(fh_dir))) + if (strncmp(direntp->d_name, "dasd", 4) == 0) + break; + if (!direntp) { + warnx("Problem with contents of \"%s\"", sysfs); + goto err; + } + if (util_file_read_line(buf, sizeof(buf), "%s/%s/dev", sysfs, direntp->d_name)) { + warnx("Could not read dev file (%s)", strerror(errno)); + goto err; + } + closedir(fh_dir); + + if (sscanf(buf, "%i:%i", &major, &minor) != 2) { + warnx("Malformed content of \"%s\": %s", sysfs, buf); + goto err; + } + *dev = makedev(major, minor); + + free(sysfs); + + return DEV_ONLINE; + +err: + if (fh_dir) + closedir(fh_dir); + free(sysfs); + exit(EXIT_FAILURE); +} + +/* + * Check whether dump table on user specified dump device is + * identical to the one found on this device. + */ +static void check_vol_table(struct vol *vol) +{ + struct vol_parm_table vol_table; + + table_read(vol->fh, vol->blk_size, &vol_table); + if (memcmp(&vol_table, &l.table, sizeof(vol_table))) + ERR_EXIT("Orphaned multi-volume dump device '%s'", + g.opts.device); +} + +/* + * Read dump tool, multi-volume dump parameter table, and dump header from the + * input dump volume. Check input dump volume for: + * - identical dump parameter table (that is it belongs to the same dump set) + * - valid magic number in the dump tool + * - valid dump sign in the dump header + * + * We read partition data via the device node. If another process + * has changed partition data via the partition node, the corresponding + * device node might still have old data in its buffers. Flush buffers + * to keep things in sync. + */ +static void vol_read(struct vol *vol) +{ + zg_ioctl(vol->fh, BLKFLSBUF, NULL, "BLKFLSBUF", ZG_CHECK); + if (df_s390_dumper_read(vol->fh, vol->blk_size, &vol->dumper)) + ERR_EXIT("No dump tool found on the multi-volume dump device '%s'", + vol->bus_id); + check_vol_table(vol); + zg_seek(vol->fh, vol->part_off, ZG_CHECK); + zg_read(vol->fh, &vol->hdr, DF_S390_HDR_SIZE, ZG_CHECK); +} + +/* + * Read memory chunk (extended dump format) + */ +static void dfi_s390mv_ext_mem_read(struct dfi_mem_chunk *mem_chunk, u64 off, + void *buf, u64 cnt) +{ + struct vol_mem_chunk *vol_mem_chunk = mem_chunk->data; + struct vol *vol = vol_mem_chunk->vol; + + zg_seek(vol->fh, vol_mem_chunk->off + off, ZG_CHECK); + zg_read(vol->fh, buf, cnt, ZG_CHECK); +} + +/* + * Initialize DASD volume + */ +static void vol_init(struct vol *vol, struct vol_parm *vol_parm, int ssid) +{ + u64 blk_cnt = vol_parm->end_blk - vol_parm->start_blk + 1; + + sprintf(vol->bus_id, "0.%x.%04x", ssid, vol_parm->devno); + vol->blk_size = vol_parm->blk_size << 8; + vol->part_off = (u64)vol_parm->start_blk * vol->blk_size; + vol->part_size = blk_cnt * vol->blk_size; + vol->status = dev_from_busid(vol->bus_id, &vol->dev); + vol->sign = SIGN_VALID; + + if (vol->status != DEV_ONLINE) + return; + + vol->devnode = zg_devnode_create(vol->dev); + vol->fh = dfi_dump_open(vol->devnode); + + vol_read(vol); + + if ((vol->hdr.volnr == vol->nr) && (vol->hdr.mem_size != 0)) + vol->sign = SIGN_ACTIVE; + + if (vol->hdr.mvdump_sign != DF_S390_MAGIC_EXT) { + vol->sign = SIGN_INVALID; + l.dump_incomplete = 1; + } + + if (strncmp(vol->dumper.magic, DF_S390_DUMPER_MAGIC_MV_EXT, + DF_S390_DUMPER_MAGIC_SIZE) != 0) { + vol->sign = SIGN_INVALID; + l.dump_incomplete = 1; + } + + if (vol->nr == 0) + l.hdr = vol->hdr; +} + +/* + * Print volume information + */ +static void vol_print(struct vol *vol) +{ + STDERR(" Volume %i: %s (%s", vol->nr, vol->bus_id, + dev_status_str(vol->status)); + if (vol->status == DEV_ONLINE) + STDERR("/%s)\n", dev_sign_str(vol->sign)); + else + STDERR(")\n"); +} + +/* + * Print information for all volumes + */ +static void vol_print_all(void) +{ + unsigned int i; + + for (i = 0; i < l.table.vol_cnt; i++) + vol_print(&l.vol_vec[i]); +} + +/* + * Add memory chunks (extended dump format) and verify the end marker + */ +static int mem_chunks_add_ext(void) +{ + u64 off, rc, part_end, old = 0, dump_size = 0; + struct df_s390_dump_segm_hdr dump_segm; + struct vol_mem_chunk *vol_mem_chunk; + struct vol *vol; + unsigned int i; + + for (i = 0; i < l.table.vol_cnt; i++) { + vol = &l.vol_vec[i]; + if (vol->sign != SIGN_ACTIVE) + continue; + off = vol->part_off + DF_S390_HDR_SIZE; + part_end = vol->part_off + vol->part_size; + rc = zg_seek(vol->fh, off, ZG_CHECK_NONE); + if (rc != off) + return -EINVAL; + /* + * Reading dump segments from the start of partition (skipping + * the dump header) till the end of partition (considering that + * minimum dump segment size is one megabyte + one page and one + * more page is reserved for the end marker) + */ + while (off < part_end - MIB - PAGE_SIZE) { + rc = zg_read(vol->fh, &dump_segm, sizeof(dump_segm), + ZG_CHECK_ERR); + if (rc != PAGE_SIZE) + return -EINVAL; + off += PAGE_SIZE; + vol_mem_chunk = zg_alloc(sizeof(*vol_mem_chunk)); + vol_mem_chunk->vol = vol; + vol_mem_chunk->off = off; + /* Add zero memory chunk */ + dfi_mem_chunk_add_vol(old, dump_segm.start - old, NULL, + dfi_mem_chunk_read_zero, NULL, + vol->nr); + /* Add memory chunk for a dump segment */ + dfi_mem_chunk_add_vol(dump_segm.start, dump_segm.len, + vol_mem_chunk, + dfi_s390mv_ext_mem_read, NULL, + vol->nr); + old = dump_segm.start + dump_segm.len; + dump_size += dump_segm.len; + off = zg_seek_cur(vol->fh, dump_segm.len, + ZG_CHECK_NONE); + if (dump_segm.stop_marker) + break; + } + if (dump_segm.stop_marker) { + /* Add zero memory chunk at the end*/ + dfi_mem_chunk_add_vol(old, l.hdr.mem_size - old, NULL, + dfi_mem_chunk_read_zero, NULL, + vol->nr); + /* Set the actual size of the dump file */ + dfi_attr_file_size_set(dump_size); + /* Read and verify the end marker */ + rc = zg_read(vol->fh, &l.em, sizeof(l.em), ZG_CHECK); + if (rc != sizeof(l.em) || + df_s390_em_verify(&l.em, &l.hdr) != 0) + return -EINVAL; + return 0; + } + } + /* No dump segment with the stop marker found */ + return -EINVAL; +} + +/* + * Print hint for setting all offline volumes online + */ +static void vol_offline_msg(void) +{ + unsigned int i, first = 1; + + STDERR("\n"); + STDERR("Set all devices online using:\n"); + STDERR("# chccwdev -e "); + for (i = 0; i < l.table.vol_cnt; i++) { + if (l.vol_vec[i].status == DEV_OFFLINE) { + if (first) + first = 0; + else + STDERR(","); + STDERR("%s", l.vol_vec[i].bus_id); + } + } + STDERR("\n"); +} + +/* + * Print error for all undefined volumes + */ +static void vol_undefined_msg(void) +{ + unsigned int i; + + STDERR("\n"); + STDERR("Ensure that the following devices are available to the system:\n"); + for (i = 0; i < l.table.vol_cnt; i++) { + if (l.vol_vec[i].status == DEV_UNDEFINED) + STDERR("* %s\n", l.vol_vec[i].bus_id); + } +} + +/* + * Check that all volumes are in online state + */ +static int vol_online_check(void) +{ + unsigned int i, offline = 0, undefined = 0; + + for (i = 0; i < l.table.vol_cnt; i++) { + if (l.vol_vec[i].status == DEV_OFFLINE) + offline = 1; + if (l.vol_vec[i].status == DEV_UNDEFINED) + undefined = 1; + } + if (!offline && !undefined) + return 0; + + STDERR("Found multi-volume dump tool:\n\n"); + vol_print_all(); + if (offline) + vol_offline_msg(); + if (undefined) + vol_undefined_msg(); + return -ENODEV; +} + +/* + * Check if on device is a multi-volume dump + */ +static int mvdump_hdr_check(const char *file) +{ + struct df_s390_hdr hdr; + struct zg_fh *fh; + int rc = -ENODEV; + + fh = zg_open(file, O_RDONLY, ZG_CHECK); + if (zg_read(fh, &hdr, sizeof(hdr), ZG_CHECK_ERR) != sizeof(hdr)) + goto fail; + if (hdr.magic != DF_S390_MAGIC_EXT) + goto fail; + if (hdr.mvdump_sign != DF_S390_MAGIC_EXT) + goto fail; + rc = 0; +fail: + zg_close(fh); + return rc; +} + +/* + * Read dump tool from DASD and check if we have a multi-volume dump tool + */ +static int mv_dumper_read(void) +{ + if (zg_ioctl(g.fh, BLKSSZGET, &l.blk_size, "BLKSSZGET", + ZG_CHECK_NONE) == -1) + return -ENODEV; + if (df_s390_dumper_read(g.fh, l.blk_size, &l.dumper)) + return -ENODEV; + if (strncmp(l.dumper.magic, DF_S390_DUMPER_MAGIC_MV_EXT, DF_S390_DUMPER_MAGIC_SIZE) != 0) + return -ENODEV; + table_read(g.fh, l.blk_size, &l.table); + return 0; +} + +/* + * Initialize all volumes + */ +static void volumes_init(void) +{ + unsigned int i; + + for (i = 0; i < l.table.vol_cnt; i++) { + l.vol_vec[i].nr = i; + vol_init(&l.vol_vec[i], &l.table.vol_parm[i], l.table.ssid[i]); + } +} + +/* + * Open dump - If partition is specified open device instead + */ +static int open_dump(void) +{ + const struct stat *stat = zg_stat(g.fh); + unsigned int dev_minor; + enum zg_type type; + char *path; + + type = zg_type(g.fh); + if (type != ZG_TYPE_DASD && type != ZG_TYPE_DASD_PART) + return -ENODEV; + + if (type == ZG_TYPE_DASD_PART) { + dev_minor = minor(stat->st_rdev) - (minor(stat->st_rdev) % 4); + if (mvdump_hdr_check(zg_path(g.fh)) != 0) + return -ENODEV; + path = zg_devnode_create(makedev(major(stat->st_rdev), + dev_minor)); + zg_close(g.fh); + g.fh = zg_open(path, O_RDONLY, ZG_CHECK); + } + if (mv_dumper_read() != 0) + return -ENODEV; + return 0; +} + +/* + * Initialize s390 extended multi-volume input dump format function */ static int dfi_s390mv_ext_init(void) { - return dfi_s390mv_init_gen(DUMP_EXTENDED); + int rc; + + if (open_dump() != 0) + return -ENODEV; + volumes_init(); + if (vol_online_check() != 0) + zg_exit(1); + if (l.hdr.mem_size == 0) + return -ENODEV; + df_s390_hdr_add(&l.hdr); + if (mem_chunks_add_ext() != 0) + return -EINVAL; + if (l.dump_incomplete) + return -EINVAL; + rc = df_s390_cpu_info_add(&l.hdr, l.hdr.mem_end); + if (rc) + return rc; + df_s390_em_add(&l.em); + return 0; +} + +/* + * Print dump information (dfi operation) + */ +static void dfi_s390mv_info(void) +{ + vol_print_all(); +} + +/* + * Initialize s390 multi-volume dump tool (extedend) for -d option + */ +int dt_s390mv_ext_init(void) +{ + if (open_dump() != 0) + return -ENODEV; + volumes_init(); + dt_arch_set(DFI_ARCH_64); + dt_version_set(l.dumper.version); + dt_attr_mem_limit_set(l.dumper.mem); + dt_attr_force_set(l.dumper.force); + return 0; +} + +/* + * s390 multi-volume dump tool info function (for -d option) + */ +void dt_s390mv_info(void) +{ + vol_print_all(); } /* diff --git a/zdump/dt.c b/zdump/dt.c index bda0c8a7..0ccded3e 100644 --- a/zdump/dt.c +++ b/zdump/dt.c @@ -18,7 +18,6 @@ */ static struct dt *dt_vec[] = { &dt_s390mv_ext, - &dt_s390mv, &dt_s390sv_ext, &dt_scsi, &dt_ngdump, diff --git a/zdump/dt.h b/zdump/dt.h index 9c9bce02..652b1a95 100644 --- a/zdump/dt.h +++ b/zdump/dt.h @@ -36,7 +36,6 @@ void dt_attr_dasd_type_set(const char *dasd_type); /* * Supported s390 dumpers */ -extern struct dt dt_s390mv; extern struct dt dt_s390mv_ext; extern struct dt dt_s390sv_ext; extern struct dt dt_scsi; diff --git a/zdump/dt_s390mv.c b/zdump/dt_s390mv.c deleted file mode 100644 index 95de89ab..00000000 --- a/zdump/dt_s390mv.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * zgetdump - Tool for copying and converting System z dumps - * - * S390 multi-volume DASD dump tool - * - * Copyright IBM Corp. 2001, 2017 - * - * 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 "dt.h" -#include "df_s390.h" - -/* - * Initialize s390 multi-volume dump tool (for -d option) - */ -static int dt_s390mv_init(void) -{ - return dt_s390mv_init_gen(DUMP_NON_EXTENDED); -} - -/* - * Dump Tool operations - */ -struct dt dt_s390mv = { - .desc = "Multi-volume DASD dump tool", - .init = dt_s390mv_init, - .info = dt_s390mv_info, -}; diff --git a/zdump/dt_s390mv_ext.c b/zdump/dt_s390mv_ext.c index 61b79ec1..98be0c9e 100644 --- a/zdump/dt_s390mv_ext.c +++ b/zdump/dt_s390mv_ext.c @@ -3,7 +3,7 @@ * * S390x multi-volume DASD dump tool * - * Copyright IBM Corp. 2001, 2018 + * Copyright IBM Corp. 2001, 2025 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -12,14 +12,6 @@ #include "dt.h" #include "df_s390.h" -/* - * Initialize s390 multi-volume dump tool (extedend) for -d option - */ -static int dt_s390mv_ext_init(void) -{ - return dt_s390mv_init_gen(DUMP_EXTENDED); -} - /* * Dump Tool (extedned) operations */ diff --git a/zipl/src/install.c b/zipl/src/install.c index 44ed7f19..31e9c486 100644 --- a/zipl/src/install.c +++ b/zipl/src/install.c @@ -368,7 +368,6 @@ static int clear_ccw_dumper(const struct disk_info *info, int fd) * Check if the dump tool is present and clear its first block with zeroes. */ if (strncmp(dumper_magic, DF_S390_DUMPER_MAGIC_EXT, sizeof(dumper_magic)) == 0 || - strncmp(dumper_magic, DF_S390_DUMPER_MAGIC_MV, sizeof(dumper_magic)) == 0 || strncmp(dumper_magic, DF_S390_DUMPER_MAGIC_MV_EXT, sizeof(dumper_magic)) == 0) { if (misc_seek(fd, ECKD_CDL_DUMP_REC * info->phy_block_size)) return -1;