zipl: Implement zipl helper script for NGDump

The purpose of the new zipl helper script is to build a dumper initramfs
for NGDump stand-alone dump. zipl executes the helper script when
preparing a NVMe dump partition for stand-alone dump.

The zipl helper script expects a single parameter - a path to the dump
partition to store a dump on. The helper script terminates with 0 on
success and a positive value otherwise.

The zipl helper script performs the following steps:
- It builds an initramfs image suitable for dumping. To perform this step,
  the script employs the dracut tool on Fedora/RHEL/SLES and
  the initramfs-tools on Ubuntu/Debian.
- It outputs the path to the newly built initramfs image and the currently
  active kernel bzImage on the standard output.
- It prints the kernel command-line to be used by the dumper on
  the standard output.

On success, zipl expects the helper script to return at least three lines
containing:
- initrd=<path to an initramfs image>
- kernel=<path to a kernel bzImage>
- cmdline=<kernel command-line parameters>

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Tested-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Alexander Egorenkov
2021-08-12 13:23:46 +02:00
committed by Jan Höppner
parent c1d08e1380
commit b4142a9966
6 changed files with 257 additions and 0 deletions

View File

@@ -15,6 +15,8 @@ NGDUMPDIR := 99ngdump
#
ifeq ($(HAVE_DRACUT),1)
install:
$(INSTALL) -m 755 zipl_helper.prepare-ngdump \
$(DESTDIR)$(TOOLS_LIBDIR)
$(INSTALL) -m 755 -d $(DESTDIR)$(MODULESDIR)
$(INSTALL) -m 755 -d $(DESTDIR)$(MODULESDIR)/$(NGDUMPDIR)
$(INSTALL) -m 755 $(NGDUMPDIR)/module-setup.sh \

View File

@@ -0,0 +1,93 @@
#!/bin/bash
#
# Copyright IBM Corp. 2021
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
#
set -u
DRACUT_OMIT_MODULES=(
nfs network network-manager
dbus dbus-broker dbus-daemon plymouth
znet dash resume ifcfg earlykdump
kdumpcore i18n lvm mdraid memstrack
systemd-timedated systemd-timesyncd
systemd-networkd systemd-network-manager systemd-coredump)
[ $# -gt 0 ] || { echo "Usage: $0 <dump partition device>" >&2; exit 1; }
#
# Retrieve partition UUID
#
# We use PARTUUID because zipl re-formats the given partition after
# calling us, therefore, a UUID will change.
#
device=$(readlink -f $1)
disk_path=/dev/disk/by-partuuid/$(blkid -o value -s PARTUUID "$device")
[ -e "$disk_path" ] || { echo "Couldn't find disk by PARTUUID." >&2; exit 1; }
function get_kernel_version()
{
local version=$(uname -r)
echo $version
}
function get_kernel_image()
{
local version=$1
if [ -e "/boot/image-$version" ]; then
# SLES kernel image
echo "/boot/image-$version"
else
# Fedora/RHEL kernel image
echo "/boot/vmlinuz-$version"
fi
}
#
# dracut is the standard tool for building initramfs images
# on Fedora, RHEL, and SLES.
#
function create_initrd()
{
local disk=$1
local kver=$2
local initrd=$3
local omit_modules=$(echo ${DRACUT_OMIT_MODULES[@]})
command -v dracut >/dev/null ||
{ echo "Please install dracut." >&2; return 1; }
dracut -v --hostonly --no-hostonly-cmdline --hostonly-i18n \
-o "$omit_modules" --add ngdump \
--mount "$disk /ngdump ext4 defaults" \
--kver "$kver" -f "$initrd" 2>&1
}
kernel_version=$(get_kernel_version)
kernel=$(get_kernel_image "$kernel_version")
[ -e "$kernel" ] || { echo "Couldn't find kernel image." >&2; exit 1; }
initrd=$(mktemp)
create_initrd "$disk_path" "$kernel_version" "$initrd"
[ $? -eq 0 ] || { echo "Failed to create initramfs image" >&2; exit 1; }
#
# zipl expects this script to output three variables to stdout:
# * kernel: path to bzImage file of Linux kernel
# * initrd: path to dumper initramfs image
# * cmdline: command-line for dumper's kernel
#
# The output order is irrelevant.
#
echo "kernel=$kernel"
echo "initrd=$initrd"
echo "cmdline=reset_devices cgroup_disable=memory nokaslr numa=off irqpoll nr_cpus=1"
exit 0

View File

@@ -135,5 +135,6 @@ int job_get(int argc, char* argv[], struct job_data** data);
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);
#endif /* not JOB_H */

View File

@@ -16,6 +16,8 @@ INITPREMOUNTDIR := $(INITRAMFSTOOLSDIR)/scripts/init-premount
#
ifeq ($(HAVE_INITRAMFS),1)
install:
$(INSTALL) -m 755 zipl_helper.prepare-ngdump \
$(DESTDIR)$(TOOLS_LIBDIR)
$(INSTALL) -m 755 -d $(DESTDIR)$(HOOKSDIR)
$(INSTALL) -m 755 -d $(DESTDIR)$(INITPREMOUNTDIR)
$(INSTALL) -m 755 hooks/ngdump $(DESTDIR)$(HOOKSDIR)/

View File

@@ -0,0 +1,73 @@
#!/bin/bash
#
# Copyright IBM Corp. 2021
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
#
[ $# -gt 0 ] || { echo "Usage: $0 <dump partition device>" >&2; exit 1; }
#
# Retrieve partition UUID
#
# We use PARTUUID because zipl re-formats the given partition after
# calling us, therefore, a UUID will change.
#
device=$(readlink -f $1)
disk_path=/dev/disk/by-partuuid/$(blkid -o value -s PARTUUID "$device")
[ -e "$disk_path" ] || { echo "Couldn't find disk by PARTUUID." >&2; exit 1; }
function get_kernel_version()
{
local version=$(uname -r)
echo $version
}
function get_kernel_image()
{
local version=$1
echo "/boot/vmlinuz-$version"
}
#
# initramfs-tools is the standard tool for building initramfs images
# on Ubuntu and Debian.
#
function create_initrd()
{
local disk=$1
local kver=$2
local initrd=$3
command -v mkinitramfs >/dev/null ||
{ echo "Please install mkinitramfs." >&2; return 1; }
NGDUMP=y NGDUMP_DEVICE="$disk" mkinitramfs -o "$initrd" "$kver" 2>&1
}
kernel_version=$(get_kernel_version)
kernel=$(get_kernel_image "$kernel_version")
[ -e "$kernel" ] || { echo "Couldn't find kernel image." >&2; exit 1; }
initrd=$(mktemp)
create_initrd "$disk_path" "$kernel_version" "$initrd"
[ $? -eq 0 ] || { echo "Failed to create initramfs image" >&2; exit 1; }
#
# zipl expects this script to output three variables to stdout:
# * kernel: path to bzImage file of Linux kernel
# * initrd: path to dumper initramfs image
# * cmdline: command-line for dumper's kernel
#
# The output order is irrelevant.
#
echo "kernel=$kernel"
echo "initrd=$initrd"
echo "cmdline=reset_devices cgroup_disable=memory nokaslr numa=off irqpoll nr_cpus=1"
exit 0

View File

@@ -896,6 +896,92 @@ check_job_dump_images(struct job_dump_data* dump, char* name)
}
int
check_job_images_ngdump(struct job_dump_data* dump, char *name)
{
const char *helper = TOOLS_LIBDIR "/zipl_helper.prepare-ngdump";
char *ppn_cmd = NULL;
char *line = NULL;
FILE *fp;
int rc;
misc_asprintf(&ppn_cmd, "%s %s", helper, dump->device);
printf("Run %s\n", ppn_cmd);
fp = popen(ppn_cmd, "r");
if (fp == NULL) {
error_reason("Failed to run popen(%s,\"r\",)");
free(ppn_cmd);
return -1;
}
free(ppn_cmd);
while (fscanf(fp, "%m[^\n]\n", &line) != EOF) {
char *param = NULL;
char *value = NULL;
int n = sscanf(line, "%m[^=]=%m[^\n]\n", &param, &value);
if (n != 2) {
if (verbose)
printf("%s\n", line);
free(line);
free(param);
free(value);
continue;
}
if (strcmp(param, "kernel") == 0) {
dump->common.image = value;
value = NULL;
} else if (strcmp(param, "initrd") == 0) {
dump->common.ramdisk = value;
value = NULL;
} else if (strcmp(param, "cmdline") == 0) {
dump->common.parmline = value;
value = NULL;
} else {
printf("%s\n", line);
}
free(line);
free(param);
free(value);
}
switch (pclose(fp)) {
case 0:
/* success */
break;
case -1:
error_reason("Failed to run pclose");
return -1;
default:
error_reason("Script could not determine dump parameters");
return -1;
}
rc = misc_check_readable_file(dump->common.image);
if (rc) {
error_text("Need external file '%s' for dump",
dump->common.image);
return rc;
}
dump->common.image_addr = IMAGE_LOAD_ADDRESS;
rc = misc_check_readable_file(dump->common.ramdisk);
if (rc) {
error_text("Need external file '%s' for dump",
dump->common.ramdisk);
return rc;
}
dump->common.ramdisk_addr = UNSPECIFIED_ADDRESS;
dump->common.parm_addr = UNSPECIFIED_ADDRESS;
return finalize_common_address_data(&dump->common, name);
}
static int
check_job_menu_data(struct job_menu_data *menu, struct job_envblk_data *envblk)
{