From 2b015183aa5115f479cdb1ac8288bdaa6bea70fd Mon Sep 17 00:00:00 2001 From: Alexander Egorenkov Date: Wed, 4 Aug 2021 00:02:47 +0200 Subject: [PATCH] zipl: Implement NGDump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit finalizes the implementation of the new stand-alone dump - Next Gen Dump (NGDump). NGDump stand-alone dump is a universal stand-alone dump which works for both SCSI and NVMe disks. But currently can be used only with NVMe disks and SCSI stand-alone dump remains the default for SCSI disks. Currently, this stand-alone dump can be used only on IBM z15 or newer machine generations because it requires larger amount of HSA memory offered by firmware only on IBM z15 machines. Whereas SCSI stand-alone dump is able to work with HSA memory of 32M, the new stand-alone dump requires 512M HSA memory at the moment. NGDump stand-alone dump installation is initiated by passing a path to a NVMe disk partition to zipl via the command-line -d, similar to SCSI stand-alone dump. zipl will then: - build a dumper initramfs with either dracut (Fedora/RHEL/SLES) or initramfs-tools (Ubuntu/Debian) - format the given NVMe partition with ext4 file system - create a bootmap file on the newly created file system using the built initramfs and the currently active kernel image - install a boot loader on the disk the given dump partition belongs to The operations described above are destructive for the given NVMe dump partition and the boot record(s) of its disk. After the installation step, users can configure the dumpconf to IPL the dumper automatically on panic or trigger a dump manually via HMC interface. When activated, the dumper will create a dump ELF file named "dump.elf" on the given NVMe dump partition by using the makedumpfile tool. The kdump compressed file format is not supported yet due to zgetdump not being able to read such a file format. Therefore, the dumper is restricted to write the dump only in ELF format but only kernel pages which are in use. This will usually make the dump smaller than the original size of /proc/vmcore and the whole dump process faster as well. Example configuration for dumpconf: ON_PANIC=dump # or dump_reipl DUMP_TYPE=nvme FID=0x00000001 NSID=0x00000001 BOOTPROG=0 BR_LBA=0 $ systemctl enable --now dumpconf To install the dracut support on Fedora/RHEL/SUSE: $ make -C zipl/dracut HAVE_DRACUT=1 install To install the initramfs-tools support on Ubuntu/Debian: $ make -C zipl/initramfs-tools HAVE_INITRAMFS=1 install Example of NGDump console output on SLES during dump ---------------------------------------------------- Starting NGDump... [ 8.932343] ngdump.sh[327]: NGDump started [ 8.934739] ngdump.sh[336]: Checking for memory holes : [ 0.0 %] / [ 8.967536] ngdump.sh[336]: Checking for memory holes : [100.0 %] | [ 9.076976] ngdump.sh[336]: Excluding unnecessary pages : [100.0 %] \ [ 11.721157] ngdump.sh[336]: Copying data : [ 0.0 %] - [ 12.317319] ngdump.sh[336]: Copying data : [ 22.5 %] / eta: 2s [ 13.273000] ngdump.sh[336]: Copying data : [100.0 %] | eta: 0s [ 13.273244] ngdump.sh[336]: The kernel version is not supported. [ 13.273263] ngdump.sh[336]: The makedumpfile operation may be incomplete. [ 13.273281] ngdump.sh[336]: The dumpfile is saved to /ngdump/dump.elf. [ 13.273299] ngdump.sh[336]: makedumpfile Completed. Example of NGDump console output on Ubuntu during dump ------------------------------------------------------- [ 3.240078] zdump: The dump process started for a 64-bit operating system Loading, please wait... Starting version 245.4-4ubuntu3.17 Begin: Starting firmware auto-configuration ... done. Begin: Loading essential drivers ... done. Begin: Running /scripts/init-premount ... Begin: NGDump ... Checking for memory holes : [ 0.0 %] / Checking for memory holes : [100.0 %] | Excluding unnecessary pages : [100.0 %] \ Copying data : [ 0.0 %] - Copying data : [ 40.7 %] / eta: 1s Copying data : [100.0 %] | eta: 0s The kernel version is not supported. The makedumpfile operation may be incomplete. The dumpfile is saved to /ngdump/dump.elf. makedumpfile Completed. Signed-off-by: Alexander Egorenkov Acked-by: Alexander Gordeev Tested-by: Alexander Gordeev Reviewed-by: Mikhail Zaslonko Tested-by: Mikhail Zaslonko Signed-off-by: Jan Höppner --- zipl/include/job.h | 1 + zipl/src/bootmap.c | 141 ++++++++++++++++++++++++++++++++++++++++++--- zipl/src/install.c | 3 +- zipl/src/job.c | 6 ++ zipl/src/zipl.c | 5 +- 5 files changed, 146 insertions(+), 10 deletions(-) diff --git a/zipl/include/job.h b/zipl/include/job.h index a3d5a2a6..f7a35ed3 100644 --- a/zipl/include/job.h +++ b/zipl/include/job.h @@ -136,5 +136,6 @@ void job_free(struct job_data* job); int type_from_target(char *target, disk_type_t *type); int check_job_dump_images(struct job_dump_data* dump, char* name); int check_job_images_ngdump(struct job_dump_data* dump, char* name); +bool is_ngdump_enabled(const char* device, struct job_target_data* target); #endif /* not JOB_H */ diff --git a/zipl/src/bootmap.c b/zipl/src/bootmap.c index e8c3de64..4104e1bc 100644 --- a/zipl/src/bootmap.c +++ b/zipl/src/bootmap.c @@ -17,9 +17,11 @@ #include #include #include +#include #include #include "lib/zt_common.h" +#include "lib/util_libc.h" #include "lib/util_part.h" #include "lib/util_path.h" #include "boot/s390.h" @@ -33,6 +35,8 @@ #include "install.h" #include "misc.h" +#define NGDUMP_FSTYPE "ext4" + /* Pointer to dedicated empty block in bootmap. */ static disk_blockptr_t empty_block; @@ -964,8 +968,11 @@ get_dump_parmline(char *partition, char *parameters, disk_free_info(info); return -1; } - buffer = create_dump_parmline(parameters, "/dev/ram0", - info->partnum, 1); + if (is_ngdump_enabled(partition, target)) + buffer = misc_strdup(parameters); + else + buffer = create_dump_parmline(parameters, "/dev/ram0", + info->partnum, 1); disk_free_info(info); if (buffer == NULL) return -1; @@ -1513,18 +1520,136 @@ out_free_filename: } +static int +ngdump_create_meta(const char *path) +{ + char *filename = NULL; + FILE *fp; + int rc; + + util_asprintf(&filename, "%s/ngdump.meta", path); + + fp = fopen(filename, "w"); + if (!fp) { + free(filename); + error_reason(strerror(errno)); + error_text("Could not create file '%s'", filename); + return -1; + } + free(filename); + + rc = fprintf(fp, "version=1\n"); + if (rc < 0) + return -1; + rc = fprintf(fp, "file=\n"); + if (rc < 0) + return -1; + rc = fprintf(fp, "sha256sum=\n"); + if (rc < 0) + return -1; + rc = fclose(fp); + if (rc < 0) + return -1; + + return 0; +} + + +static int +bootmap_create_device_ngdump(struct job_data *job, disk_blockptr_t *program_table, + disk_blockptr_t *scsi_dump_sb_blockptr, + disk_blockptr_t **stage1b_list, blocknum_t *stage1b_count, + char **new_device, struct disk_info **new_info) +{ + char mount_point[] = "/tmp/zipl-dump-mount-point-XXXXXX"; + struct disk_info *info; + char *device; + int rc; + + /* Retrieve target device information */ + if (disk_get_info(job->data.dump.device, &job->target, &info)) + return -1; + if (misc_temp_dev(info->device, 1, &device)) + goto out_disk_free_info; + if (check_dump_device(job, info, device)) + goto out_misc_free_temp_dev; + /* Create a mount point directory */ + if (mkdtemp(mount_point) == NULL) { + error_reason(strerror(errno)); + error_text("Could not create mount point '%s'", mount_point); + goto out_misc_free_temp_dev; + } + if (!dry_run) { + char *cmd = NULL; + util_asprintf(&cmd, "mkfs.%s -qF %s >/dev/null", + NGDUMP_FSTYPE, job->data.dump.device); + if (verbose) + printf("Formatting partition '%s'\n", + job->data.dump.device); + rc = system(cmd); + free(cmd); + if (rc) { + error_reason(strerror(errno)); + error_text("Could not format partition '%s':", + job->data.dump.device); + goto out_rmdir; + } + } + /* + * Mount partition where bootmap file and also a dump file will + * be stored. + */ + if (mount(job->data.dump.device, mount_point, NGDUMP_FSTYPE, 0, NULL)) { + error_reason(strerror(errno)); + error_text("Could not mount partition '%s':", + job->data.dump.device); + goto out_rmdir; + } + if (bootmap_create_file(job, mount_point, program_table, + scsi_dump_sb_blockptr, + stage1b_list, stage1b_count, + new_device, new_info)) + goto out_umount; + if (ngdump_create_meta(mount_point)) + goto out_umount; + /* Cleanup */ + umount(mount_point); + rmdir(mount_point); + misc_free_temp_dev(device); + disk_free_info(info); + return 0; + +out_umount: + umount(mount_point); +out_rmdir: + rmdir(mount_point); +out_misc_free_temp_dev: + misc_free_temp_dev(device); +out_disk_free_info: + disk_free_info(info); + return -1; +} + + int bootmap_create(struct job_data *job, disk_blockptr_t *program_table, disk_blockptr_t *scsi_dump_sb_blockptr, disk_blockptr_t **stage1b_list, blocknum_t *stage1b_count, char **new_device, struct disk_info **new_info) { - if (job->id == job_dump_partition) - return bootmap_create_device(job, program_table, - scsi_dump_sb_blockptr, - stage1b_list, stage1b_count, - new_device, new_info); - else + if (job->id == job_dump_partition) { + if (is_ngdump_enabled(job->data.dump.device, &job->target)) + return bootmap_create_device_ngdump(job, program_table, + scsi_dump_sb_blockptr, + stage1b_list, + stage1b_count, + new_device, new_info); + else + return bootmap_create_device(job, program_table, + scsi_dump_sb_blockptr, + stage1b_list, stage1b_count, + new_device, new_info); + } else return bootmap_create_file(job, job->target.bootmap_dir, program_table, scsi_dump_sb_blockptr, diff --git a/zipl/src/install.c b/zipl/src/install.c index 6cad861c..d8404c55 100644 --- a/zipl/src/install.c +++ b/zipl/src/install.c @@ -316,7 +316,8 @@ install_bootloader(const char *device, disk_blockptr_t *program_table, case disk_type_scsi: rc = install_scsi(fd, program_table, info, scsi_dump_sb_blockptr); - if (rc == 0 && job->id == job_dump_partition) + if (rc == 0 && job->id == job_dump_partition && + !is_ngdump_enabled(device, &job->target)) rc = overwrite_partition_start(fd, info, 0); break; case disk_type_fba: diff --git a/zipl/src/job.c b/zipl/src/job.c index ecac40d9..ffdc297a 100644 --- a/zipl/src/job.c +++ b/zipl/src/job.c @@ -2009,3 +2009,9 @@ job_get(int argc, char* argv[], struct job_data** data) *data = job; return rc; } + +bool +is_ngdump_enabled(const char* device, struct job_target_data* target) +{ + return disk_is_nvme(device, target); +} diff --git a/zipl/src/zipl.c b/zipl/src/zipl.c index e2a10f87..eed5423b 100644 --- a/zipl/src/zipl.c +++ b/zipl/src/zipl.c @@ -187,7 +187,10 @@ main(int argc, char* argv[]) rc = -1; break; } - rc = check_job_dump_images(&job->data.dump, job->name); + if (is_ngdump_enabled(job->data.dump.device, &job->target)) + rc = check_job_images_ngdump(&job->data.dump, job->name); + else + rc = check_job_dump_images(&job->data.dump, job->name); if (rc != 0) break; /* Fall through. */