Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:13.1:Update
s390-tools
s390-tools-sles11sp3-kdump.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File s390-tools-sles11sp3-kdump.patch of Package s390-tools
Subject: [PATCH] [FEAT RAS1101] kdump: Add s390-tools kdump support From: Michael Holzheu <holzheu@linux.vnet.ibm.com> Summary: kdump: Add s390-tools kdump support Description: The following features have been added for s390-tools kdump support: - kdump base support: The lsshut tool prints information when kdump is enabled. - PSW restart support: * dumpconf: The dumpconf service now configures the same action for the restart trigger as for the panic trigger. * ipl_tools: The lsshut tool now shows the action for the restart trigger. - zgetdump: vmcoreinfo support The zgetdump tool now prints UTS name information for dumps and creates a VMCOREINFO note section for ELF target dump format. - zgetdump: makedumpfile kdump format support The zgetdump tools can now print information on makedumpfile generated dumps (kdump format) with the --info option. - zgetdump: kdump failure recovery support If kdump failed and a stand-alone dump is created afterwards, with the new zgetdump --select option, the user can choose between the production system dump and the failed kdump dump. Problem-ID: RAS1101 --- etc/init.d/dumpconf | 10 + ipl_tools/Makefile | 2 ipl_tools/cmd_chreipl.c | 2 ipl_tools/cmd_chshut.c | 107 +++++------------ ipl_tools/cmd_lsreipl.c | 41 +++--- ipl_tools/cmd_lsshut.c | 72 ++++++----- ipl_tools/ipl_tools.h | 33 ++++- ipl_tools/main.c | 4 ipl_tools/man/chshut.8 | 23 +-- ipl_tools/man/lsshut.8 | 8 - ipl_tools/shutdown.c | 97 +++++++++++++++ ipl_tools/system.c | 45 +++++-- man/dumpconf.8 | 34 +++-- zdump/Makefile | 3 zdump/dfi.c | 297 ++++++++++++++++++++++++++++++++++++++++++------ zdump/dfi.h | 30 ++++ zdump/dfi_kdump.c | 149 +++++++++++++++++++----- zdump/dfi_vmcoreinfo.c | 218 +++++++++++++++++++++++++++++++++++ zdump/dfo.c | 5 zdump/dfo_elf.c | 15 ++ zdump/opts.c | 66 ++++++++-- zdump/zg.c | 26 ++++ zdump/zg.h | 12 + zdump/zgetdump.c | 21 +++ zdump/zgetdump.h | 6 25 files changed, 1079 insertions(+), 247 deletions(-) --- a/etc/init.d/dumpconf +++ b/etc/init.d/dumpconf @@ -71,6 +71,8 @@ check_environment() DUMP_CONFIG_DIR=/$SYSFSDIR/firmware/dump ON_PANIC_CONFIG_FILE=/$SYSFSDIR/firmware/shutdown_act\ ions/on_panic + ON_RESTART_CONFIG_FILE=/$SYSFSDIR/firmware/shutdown_act\ +ions/on_restart if [ ! -d $DUMP_CONFIG_DIR ]; then pr_info "kernel has no dump on panic support" exit 0 @@ -448,7 +450,7 @@ start() fi fi if [ "$ON_PANIC" == "" ]; then - ON_PANIC="stop" + ON_PANIC="$(cat $ON_PANIC_CONFIG_FILE)" fi case "$ON_PANIC" in @@ -474,6 +476,9 @@ start() return fi + if [ -f $ON_RESTART_CONFIG_FILE ]; then + echo $ON_PANIC > $ON_RESTART_CONFIG_FILE 2> /dev/null || RETVAL=1 + fi echo $ON_PANIC > $ON_PANIC_CONFIG_FILE 2> /dev/null || RETVAL=1 # check for errors @@ -490,6 +495,9 @@ stop() killproc -p $PIDFILE -TERM $DUMPCONF_BIN fi echo none > $DUMP_CONFIG_DIR/dump_type || RETVAL=1 + if [ -f $ON_RESTART_CONFIG_FILE ]; then + echo stop > $ON_RESTART_CONFIG_FILE 2> /dev/null || RETVAL=1 + fi echo stop > $ON_PANIC_CONFIG_FILE || RETVAL=1 if [ $RETVAL -eq 0 ]; then pr_info "Dump on panic is disabled now" --- a/ipl_tools/Makefile +++ b/ipl_tools/Makefile @@ -4,7 +4,7 @@ CPPFLAGS += -I../include all: chreipl lsreipl chshut lsshut -objects = main.o ccw.o fcp.o system.o \ +objects = main.o ccw.o fcp.o system.o shutdown.o \ cmd_lsshut.o cmd_chshut.o cmd_lsreipl.o cmd_chreipl.o proc.o $(objects): ipl_tools.h --- a/ipl_tools/cmd_chreipl.c +++ b/ipl_tools/cmd_chreipl.c @@ -568,7 +568,7 @@ static void chreipl_fcp(void) sprintf(l.bootprog, "0"); write_str(l.bootprog, "reipl/fcp/bootprog"); - print_fcp(0); + print_fcp(0, 0); } static void chreipl_nss(void) --- a/ipl_tools/cmd_chshut.c +++ b/ipl_tools/cmd_chshut.c @@ -3,32 +3,17 @@ * * Command: chshut * - * Copyright IBM Corp. 2008, 2010 + * Copyright IBM Corp. 2008, 2011 * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com> * Michael Holzheu <holzheu@linux.vnet.ibm.com> */ #include "ipl_tools.h" -enum shutdown_action { - SA_IPL, - SA_REIPL, - SA_DUMP, - SA_STOP, - SA_VMCMD, -}; - -enum shutdown_trigger { - ST_HALT, - ST_POFF, - ST_REBOOT, - ST_PANIC, -}; - static const char *const usage_chshut = "Usage: %s TRIGGER ACTION [COMMAND] [OPTIONS]\n" "\n" -"Change action to be performed after shutdown.\n" +"Change the shutdown actions for Linux on System z.\n" "\n" "TRIGGER specifies when the action is performed:\n" " halt System has been shut down (e.g. shutdown -h -H now)\n" @@ -76,40 +61,38 @@ static void parse_chshut_options(int arg ERR_EXIT("You must be root to perform this operation"); } -static enum shutdown_trigger shutdown_trigger_get(const char *trigger) +static struct shutdown_trigger *shutdown_trigger_get(const char *trigger) { - if (strcmp(trigger, "halt") == 0) - return ST_HALT; - if (strcmp(trigger, "poff") == 0) - return ST_POFF; - if (strcmp(trigger, "reboot") == 0) - return ST_REBOOT; - if (strcmp(trigger, "panic") == 0) - return ST_PANIC; + int i; + + for (i = 0; shutdown_trigger_vec[i]; i++) { + if (strcmp(trigger, shutdown_trigger_vec[i]->name) != 0) + continue; + if (shutdown_trigger_vec[i]->available) + return shutdown_trigger_vec[i]; + ERR_EXIT("Shutdown trigger \"%s\" is not available on " + "your system", trigger); + } ERR_EXIT("Unknown shutdown trigger \"%s\" specified", trigger); } -static enum shutdown_action shutdown_action_get(const char *action) +static struct shutdown_action *shutdown_action_get(const char *action) { - if (strcmp(action, "ipl") == 0) - return SA_IPL; - if (strcmp(action, "reipl") == 0) - return SA_REIPL; - if (strcmp(action, "dump") == 0) - return SA_DUMP; - if (strcmp(action, "stop") == 0) - return SA_STOP; - if (strcmp(action, "vmcmd") == 0) - return SA_VMCMD; + int i; + + for (i = 0; shutdown_action_vec[i]; i++) { + if (strcmp(action, shutdown_action_vec[i]->name) == 0) + return shutdown_action_vec[i]; + } ERR_EXIT("Unknown shutdown action \"%s\" specified", action); } /* * Multiple CP commands can be specified via "vmcmd XY1 vmcmd XY2 ..." */ -static void vmcmd_set(enum shutdown_trigger st, int argc, char *argv[]) +static void vmcmd_set(struct shutdown_trigger *st, int argc, char *argv[]) { - char vmcmd[1024]; + char vmcmd[1024], path[PATH_MAX]; int first = 1, i; int vmcmd_length = 0; @@ -136,25 +119,15 @@ static void vmcmd_set(enum shutdown_trig i++; } - switch (st) { - case ST_HALT: - write_str(vmcmd, "vmcmd/on_halt"); - break; - case ST_POFF: - write_str(vmcmd, "vmcmd/on_poff"); - break; - case ST_REBOOT: - write_str(vmcmd, "vmcmd/on_reboot"); - break; - case ST_PANIC: - break; - } + sprintf(path, "vmcmd/%s", st->name_sysfs); + write_str(vmcmd, path); } void cmd_chshut(int argc, char *argv[]) { - enum shutdown_trigger st; - enum shutdown_action sa; + struct shutdown_trigger *st; + struct shutdown_action *sa; + char path[PATH_MAX]; parse_chshut_options(argc, argv); @@ -162,34 +135,26 @@ void cmd_chshut(int argc, char *argv[]) ERR("No trigger specified"); print_help_hint_exit(); } + shutdown_init(); st = shutdown_trigger_get(argv[1]); - if (st == ST_PANIC) + if (st == &shutdown_trigger_panic || + st == &shutdown_trigger_restart) ERR_EXIT("Please use \"service dumpconf\" for " - "configuring the panic action"); + "configuring the %s trigger", + st->name); if (argc < 3) { ERR("No action specified"); print_help_hint_exit(); } sa = shutdown_action_get(argv[2]); - if (sa == SA_VMCMD) { + if (sa == &shutdown_action_vmcmd) { vmcmd_set(st, argc, argv); } else if (argc != 3) { ERR("Too many parameters specified"); print_help_hint_exit(); } - - switch (st) { - case ST_HALT: - write_str(argv[2], "shutdown_actions/on_halt"); - break; - case ST_POFF: - write_str(argv[2], "shutdown_actions/on_poff"); - break; - case ST_REBOOT: - write_str(argv[2], "shutdown_actions/on_reboot"); - break; - case ST_PANIC: - break; - } + sprintf(path, "shutdown_actions/%s", st->name_sysfs); + if (write_str_errno(argv[2], path)) + ERR_EXIT_ERRNO("Could not set \"%s\"", path); } --- a/ipl_tools/cmd_lsreipl.c +++ b/ipl_tools/cmd_lsreipl.c @@ -45,26 +45,29 @@ void print_nss(int show_ipl) "/sys/firmware/reipl/nss/parm"; printf("%-12s nss\n", get_ipl_banner(show_ipl)); - print_str("Name: %s\n", dir, "name"); + print_fw_str("Name: %s\n", dir, "name"); if (access(path_bootparms, R_OK) == 0) - print_str("Bootparms: \"%s\"\n", dir, "parm"); + print_fw_str("Bootparms: \"%s\"\n", dir, "parm"); } -void print_fcp(int show_ipl) +void print_fcp(int show_ipl, int dump) { char *dir = show_ipl ? "ipl" : "reipl/fcp"; char *path_bootparms = show_ipl ? "/sys/firmware/ipl/scp_data" : "/sys/firmware/reipl/fcp/scp_data"; - printf("%-12s fcp\n", get_ipl_banner(show_ipl)); + if (dump) + printf("%-12s fcp_dump\n", get_ipl_banner(show_ipl)); + else + printf("%-12s fcp\n", get_ipl_banner(show_ipl)); - print_str("WWPN: %s\n", dir, "wwpn"); - print_str("LUN: %s\n", dir, "lun"); - print_str("Device: %s\n", dir, "device"); - print_str("bootprog: %s\n", dir, "bootprog"); - print_str("br_lba: %s\n", dir, "br_lba"); + print_fw_str("WWPN: %s\n", dir, "wwpn"); + print_fw_str("LUN: %s\n", dir, "lun"); + print_fw_str("Device: %s\n", dir, "device"); + print_fw_str("bootprog: %s\n", dir, "bootprog"); + print_fw_str("br_lba: %s\n", dir, "br_lba"); if (access(path_bootparms, R_OK) == 0) - print_str("Bootparms: \"%s\"\n", dir, "scp_data"); + print_fw_str("Bootparms: \"%s\"\n", dir, "scp_data"); } void print_ccw(int show_ipl) @@ -77,16 +80,16 @@ void print_ccw(int show_ipl) "/sys/firmware/reipl/ccw/parm"; printf("%-12s ccw\n", get_ipl_banner(show_ipl)); - print_str("Device: %s\n", dir, "device"); + print_fw_str("Device: %s\n", dir, "device"); if (access(path_loadparm, R_OK) == 0) { sprintf(loadparm_path, "%s/%s", dir, "loadparm"); - read_str(loadparm, loadparm_path, sizeof(loadparm)); + read_fw_str(loadparm, loadparm_path, sizeof(loadparm)); if (strcmp(loadparm, " ") == 0) loadparm[0] = 0; printf("Loadparm: \"%s\"\n", loadparm); } if (access(path_bootparms, R_OK) == 0) - print_str("Bootparms: \"%s\"\n", dir, "parm"); + print_fw_str("Bootparms: \"%s\"\n", dir, "parm"); } static void parse_lsreipl_options(int argc, char *argv[]) @@ -125,14 +128,16 @@ void cmd_lsreipl(int argc, char *argv[]) parse_lsreipl_options(argc, argv); if (l.ipl_set) - read_str(reipl_type_str, "ipl/ipl_type", - sizeof(reipl_type_str)); + read_fw_str(reipl_type_str, "ipl/ipl_type", + sizeof(reipl_type_str)); else - read_str(reipl_type_str, "reipl/reipl_type", - sizeof(reipl_type_str)); + read_fw_str(reipl_type_str, "reipl/reipl_type", + sizeof(reipl_type_str)); if (strcmp(reipl_type_str, "fcp") == 0) - print_fcp(l.ipl_set); + print_fcp(l.ipl_set, 1); + else if (strcmp(reipl_type_str, "fcp_dump") == 0) + print_fcp(l.ipl_set, 1); else if (strcmp(reipl_type_str, "ccw") == 0) print_ccw(l.ipl_set); else if (strcmp(reipl_type_str, "nss") == 0) --- a/ipl_tools/cmd_lsshut.c +++ b/ipl_tools/cmd_lsshut.c @@ -3,7 +3,7 @@ * * Command: lsshut * - * Copyright IBM Corp. 2008, 2010 + * Copyright IBM Corp. 2008, 2011 * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com> * Michael Holzheu <holzheu@linux.vnet.ibm.com> */ @@ -13,7 +13,7 @@ static const char *const usage_lsshut = "Usage: %s [OPTIONS]\n" "\n" -"Show actions to be taken after the kernel has shut down.\n" +"Print the shutdown action configuration for Linux on System z.\n" "\n" "OPTIONS:\n" " -h, --help Print this help, then exit\n" @@ -64,7 +64,7 @@ static void read_vmcmd(char *str, const *str = 0; ptr_old = ptr = buf; - read_str(buf, path, sizeof(buf)); + read_fw_str(buf, path, sizeof(buf)); while ((ptr = strchr(ptr_old, '\n'))) { *ptr = 0; sprintf(tmp, "\"%s\",", ptr_old); @@ -75,44 +75,52 @@ static void read_vmcmd(char *str, const strcat(str, tmp); } -void cmd_lsshut(int argc, char *argv[]) +static void print_kdump(void) { - char tmp[1024], cmd[1024]; + struct stat sb; + char tmp[1024]; - parse_lsshut_options(argc, argv); + if (stat("/sys/kernel/kexec_crash_loaded", &sb) != 0) + return; + read_str(tmp, "/sys/kernel/kexec_crash_loaded", sizeof(tmp)); + if (strncmp(tmp, "1", 1) == 0) + printf("kdump,"); +} - printf("Trigger Action\n"); - printf("========================\n"); +static void shutdown_trigger_print(struct shutdown_trigger *trigger) +{ + char tmp[1024], cmd[1024], path[PATH_MAX]; - read_str(tmp, "shutdown_actions/on_halt", sizeof(tmp)); - if (strncmp(tmp, "vmcmd", strlen("vmcmd")) == 0) { - read_vmcmd(cmd, "vmcmd/on_halt"); - printf("Halt %s (%s)\n", tmp, cmd); - } else { - printf("Halt %s\n", tmp); - } + sprintf(path, "shutdown_actions/%s", trigger->name_sysfs); - read_str(tmp, "shutdown_actions/on_panic", sizeof(tmp)); - if (strncmp(tmp, "vmcmd", strlen("vmcmd")) == 0) { - read_vmcmd(cmd, "vmcmd/on_panic"); - printf("Panic %s (%s)\n", tmp, cmd); - } else { - printf("Panic %s\n", tmp); - } + printf("%-16s ", trigger->name_print); - read_str(tmp, "shutdown_actions/on_poff", sizeof(tmp)); + if ((trigger == &shutdown_trigger_panic || + trigger == &shutdown_trigger_restart)) + print_kdump(); + read_fw_str(tmp, path, sizeof(tmp)); if (strncmp(tmp, "vmcmd", strlen("vmcmd")) == 0) { - read_vmcmd(cmd, "vmcmd/on_poff"); - printf("Power off %s (%s)\n", tmp, cmd); + sprintf(path, "vmcmd/%s", trigger->name_sysfs); + read_vmcmd(cmd, path); + printf("vmcmd (%s)\n", cmd); } else { - printf("Power off %s\n", tmp); + printf("%s\n", tmp); } +} - read_str(tmp, "shutdown_actions/on_reboot", sizeof(tmp)); - if (strncmp(tmp, "vmcmd", strlen("vmcmd")) == 0) { - read_vmcmd(cmd, "vmcmd/on_reboot"); - printf("Reboot %s (%s)\n", tmp, cmd); - } else { - printf("Reboot %s\n", tmp); +void cmd_lsshut(int argc, char *argv[]) +{ + int i; + + parse_lsshut_options(argc, argv); + shutdown_init(); + + printf("Trigger Action\n"); + printf("========================\n"); + + for (i = 0; shutdown_trigger_vec[i]; i++) { + if (!shutdown_trigger_vec[i]->available) + continue; + shutdown_trigger_print(shutdown_trigger_vec[i]); } } --- a/ipl_tools/ipl_tools.h +++ b/ipl_tools/ipl_tools.h @@ -3,7 +3,7 @@ * * Common macro definitions and declarations * - * Copyright IBM Corp. 2008, 2010 + * Copyright IBM Corp. 2008, 2011 * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com> * Michael Holzheu <holzheu@linux.vnet.ibm.com> */ @@ -39,7 +39,7 @@ extern void cmd_lsreipl(int argc, char * extern void cmd_chreipl(int argc, char *argv[]); extern void print_ccw(int show_ipl); -extern void print_fcp(int show_ipl); +extern void print_fcp(int show_ipl, int dump); extern void print_nss(int show_ipl); /* @@ -51,8 +51,10 @@ extern int is_root(void); extern void strlow(char *s); extern void write_str(char *string, char *file); +extern int write_str_errno(char *string, char *file); extern void read_str(char *string, const char *file, size_t len); -extern void print_str(const char *fmt, const char *dir, const char *file); +extern void read_fw_str(char *string, const char *file, size_t len); +extern void print_fw_str(const char *fmt, const char *dir, const char *file); extern void print_version_exit(void); extern void print_help_hint_exit(void); @@ -72,6 +74,31 @@ extern int ccw_is_device(const char *dev extern void ccw_busid_get(const char *device, char *devno); /* + * Shutdown trigger + */ +struct shutdown_trigger { + const char *name; + const char *name_print; + const char *name_sysfs; + int available; +}; + +extern struct shutdown_trigger shutdown_trigger_panic; +extern struct shutdown_trigger shutdown_trigger_restart; +extern struct shutdown_trigger *shutdown_trigger_vec[]; +extern void shutdown_init(void); + +/* + * Shutdown actions + */ +struct shutdown_action { + const char *name; +}; + +extern struct shutdown_action shutdown_action_vmcmd; +extern struct shutdown_action *shutdown_action_vec[]; + +/* * Error and print functions */ #define ERR(x...) \ --- a/ipl_tools/main.c +++ b/ipl_tools/main.c @@ -3,7 +3,7 @@ * * Main functions * - * Copyright IBM Corp. 2008, 2010 + * Copyright IBM Corp. 2008, 2011 * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com> * Michael Holzheu <holzheu@linux.vnet.ibm.com> */ @@ -24,7 +24,7 @@ void print_version_exit() { printf("%s: Linux on System z shutdown actions version %s\n", g.prog_name, RELEASE_STRING); - printf("Copyright IBM Corp. 2008, 2010\n"); + printf("Copyright IBM Corp. 2008, 2011\n"); exit(0); } --- a/ipl_tools/man/chshut.8 +++ b/ipl_tools/man/chshut.8 @@ -1,28 +1,27 @@ -.TH CHSHUT 8 "July 2010" "s390-tools" +.TH CHSHUT 8 "Sept 2011" "s390-tools" .SH NAME chshut \- change the shutdown actions for Linux on System z .SH SYNOPSIS -\fBchshut\fR [halt | poff | reboot] [ipl | reipl | stop | vmcmd] [VM Command] +\fBchshut\fR TRIGGER ACTION [VM Command] .SH DESCRIPTION -\fBchshut\fR is a tool that can be used to configure the Linux on System z -shutdown actions. +Use \fBchshut\fR to configure the Linux on System z shutdown actions. -The tool handles up to three parameters. The first specifies +The tool handles up to three parameters. The first parameter specifies the shutdown trigger. A shutdown trigger is an event that will stop Linux. -The following shutdown triggers are supported: "halt", "power off" and -"reboot". There exists a fourth shutdown trigger "panic" which is controlled -by the +The following shutdown triggers are supported: "halt", "poff", and "reboot". +There are two other shutdown triggers "panic" and "restart" that are +controlled by the .BR dumpconf (8) service script. -The second argument specifies the shutdown action that you want to execute -in case of the specified trigger. Valid action arguments are "ipl", "reipl", -"stop" and "vmcmd". +The second parameter specifies the shutdown action that you want to run +if the specified trigger occurs. Valid action arguments are "ipl", "reipl", +"stop", and "vmcmd". -In case you have chosen "vmcmd" as action a third parameter is used for the +If you have chosen "vmcmd" as action, a third parameter is required for the CP command you want to execute under z/VM. .B Note: --- a/ipl_tools/man/lsshut.8 +++ b/ipl_tools/man/lsshut.8 @@ -1,4 +1,4 @@ -.TH LSSHUT 8 "July 2010" "s390-tools" +.TH LSSHUT 8 "Sept 2011" "s390-tools" .SH NAME lsshut \- print the shutdown action configuration for Linux on System z @@ -9,8 +9,12 @@ lsshut \- print the shutdown action conf .SH DESCRIPTION The \fBlsshut\fR command lists the Linux on System z shutdown action configuration. This configuration handles what the system should do for -the following shutdown triggers: "halt", "panic", "power off" and, "reboot". +the following shutdown triggers: "halt", "poff", "reboot", "restart", +and "panic". +If kdump is enabled on your system, "restart" and "panic" also show the +"kdump" action together with the action that is run in case of a "kdump" +failure. .SH OPTIONS .TP \fB-h\fR or \fB--help\fR --- /dev/null +++ b/ipl_tools/shutdown.c @@ -0,0 +1,97 @@ +/* + * ipl_tools - Linux for System z reipl and shutdown tools + * + * Shutdown actions and triggers common functions + * + * Copyright IBM Corp. 2008, 2011 + * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com> + */ + +#include "ipl_tools.h" + +struct shutdown_trigger shutdown_trigger_halt = { + .name = "halt", + .name_print = "Halt", + .name_sysfs = "on_halt", +}; + +struct shutdown_trigger shutdown_trigger_poff = { + .name = "poff", + .name_print = "Power off", + .name_sysfs = "on_poff", +}; + +struct shutdown_trigger shutdown_trigger_reboot = { + .name = "reboot", + .name_print = "Reboot", + .name_sysfs = "on_reboot", +}; + +struct shutdown_trigger shutdown_trigger_restart = { + .name = "restart", + .name_print = "Restart", + .name_sysfs = "on_restart", +}; + +struct shutdown_trigger shutdown_trigger_panic = { + .name = "panic", + .name_print = "Panic", + .name_sysfs = "on_panic", +}; + +struct shutdown_trigger *shutdown_trigger_vec[] = { + &shutdown_trigger_halt, + &shutdown_trigger_poff, + &shutdown_trigger_reboot, + &shutdown_trigger_restart, + &shutdown_trigger_panic, + NULL, +}; + +struct shutdown_action shutdown_action_ipl = { + .name = "ipl", +}; + +struct shutdown_action shutdown_action_reipl = { + .name = "reipl", +}; + +struct shutdown_action shutdown_action_dump = { + .name = "dump", +}; + +struct shutdown_action shutdown_action_dump_reipl = { + .name = "dump_reipl", +}; + +struct shutdown_action shutdown_action_stop = { + .name = "stop", +}; + +struct shutdown_action shutdown_action_vmcmd = { + .name = "vmcmd", +}; + +struct shutdown_action *shutdown_action_vec[] = { + &shutdown_action_ipl, + &shutdown_action_reipl, + &shutdown_action_dump, + &shutdown_action_dump_reipl, + &shutdown_action_stop, + &shutdown_action_vmcmd, + NULL, +}; + +void shutdown_init(void) +{ + char path[PATH_MAX]; + struct stat sb; + int i; + + for (i = 0; shutdown_trigger_vec[i]; i++) { + sprintf(path, "/sys/firmware/shutdown_actions/%s", + shutdown_trigger_vec[i]->name_sysfs); + if (stat(path, &sb) == 0) + shutdown_trigger_vec[i]->available = 1; + } +} --- a/ipl_tools/system.c +++ b/ipl_tools/system.c @@ -3,7 +3,7 @@ * * Shared system functions * - * Copyright IBM Corp. 2008, 2010 + * Copyright IBM Corp. 2008, 2011 * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com> * Michael Holzheu <holzheu@linux.vnet.ibm.com> */ @@ -58,19 +58,17 @@ void strlow(char *s) /* * Read a string from a particular file */ -void read_str(char *string, const char *file, size_t len) +void read_str(char *string, const char *path, size_t len) { - char path[PATH_MAX]; size_t rc; FILE *fh; - snprintf(path, sizeof(path), "/sys/firmware/%s", file); fh = fopen(path, "rb"); if (fh == NULL) - ERR_EXIT_ERRNO("Could not open \"%s\"", file); + ERR_EXIT_ERRNO("Could not open \"%s\"", path); rc = fread(string, 1, len - 1, fh); if (rc == 0 && ferror(fh)) - ERR_EXIT_ERRNO("Could not read \"%s\"", file); + ERR_EXIT_ERRNO("Could not read \"%s\"", path); fclose(fh); string[rc] = 0; if (string[strlen(string) - 1] == '\n') @@ -78,14 +76,25 @@ void read_str(char *string, const char * } /* + * Read a string from a particular /sys/firmware file + */ +void read_fw_str(char *string, const char *file, size_t len) +{ + char path[PATH_MAX]; + + snprintf(path, sizeof(path), "/sys/firmware/%s", file); + return read_str(string, path, len); +} + +/* * Print content of a file (path = dir/file) */ -void print_str(const char *fmt, const char *dir, const char *file) +void print_fw_str(const char *fmt, const char *dir, const char *file) { char path[PATH_MAX], str[4096]; snprintf(path, sizeof(path), "%s/%s", dir, file); - read_str(str, path, sizeof(str)); + read_fw_str(str, path, sizeof(str)); printf(fmt, str); } @@ -106,3 +115,23 @@ void write_str(char *string, char *file) ERR_EXIT_ERRNO("Could not set \"%s\"", file); close(fh); } + +/* + * Write a string to a file and return ERRNO + */ +int write_str_errno(char *string, char *file) +{ + char path[PATH_MAX], value[4096]; + int fh; + + snprintf(value, sizeof(value), "%s\n", string); + snprintf(path, sizeof(path), "/sys/firmware/%s", file); + fh = open(path, O_WRONLY); + if (fh < 0) + ERR_EXIT_ERRNO("Could not open \"%s\"", file); + if (write(fh, value, strlen(value)) < 0) + return errno; + close(fh); + return 0; +} + --- a/man/dumpconf.8 +++ b/man/dumpconf.8 @@ -1,7 +1,7 @@ -.TH DUMPCONF 8 "Nov 2009" "s390-tools" +.TH DUMPCONF 8 "Sept 2011" "s390-tools" .SH NAME -dumpconf \- Configure an ON_PANIC action for Linux on System z. +dumpconf \- Configure panic and PSW restart actions for Linux on System z .SH SYNOPSIS .br @@ -11,30 +11,32 @@ dumpconf \- Configure an ON_PANIC action .SH DESCRIPTION \fBdumpconf\fR reads the /etc/sysconfig/dumpconf file -and establishes the action to be taken in case a kernel panic occurs. +and establishes the action to be taken if a kernel panic occurs +or PSW restart is triggered. The following keywords can be used in the dumpconf file: .TP \fB - ON_PANIC:\fR -Shutdown action in case of a kernel panic. Possible values are 'dump', 'reipl', 'dump_reipl', 'stop' and 'vmcmd': +Shutdown action in case of a kernel panic or a PSW restart. Possible values +are 'dump', 'reipl', 'dump_reipl', 'stop' and 'vmcmd': .br -dump: trigger dump according to the configuration in /etc/sysconfig/dumpconf. +dump: Trigger dump according to the configuration in /etc/sysconfig/dumpconf. .br -reipl: trigger re-IPL according to the configuration under /sys/firmware/reipl. +reipl: Trigger re-IPL according to the configuration under /sys/firmware/reipl. .br -dump_reipl: first trigger dump according to the configuration in +dump_reipl: First trigger dump according to the configuration in /etc/sysconfig/dumpconf, then trigger re-IPL according to the configuration under /sys/firmware/reipl. .br -stop: stop Linux and enter disabled wait (default). +stop: Stop Linux and enter disabled wait (default). .br -vmcmd: trigger CP command according to the 'VMCMD_X' configuration in +vmcmd: Trigger CP command according to the 'VMCMD_X' configuration in /etc/sysconfig/dumpconf. .TP @@ -63,7 +65,8 @@ Boot record logical block address. .TP \fB - VMCMD_1, VMCMD_2 ... VMCMD_8:\fR -Up to eight CP commands, which are triggered in case of a kernel panic. +Up to eight CP commands, which are executed in case of a kernel panic +or PSW restart. .TP \fB - DELAY_MINUTES:\fR @@ -107,6 +110,11 @@ Print usage information, then exit. \fB-v\fR or \fB--version\fR Print version information, then exit. +.SH PSW Restart +PSW Restart can be triggered by the operator under z/VM with the CP +command "#cp system restart" and under LPAR on the HMC with +"Recovery/PSW Restart". + .SH EXAMPLES: The following are examples of the /etc/sysconfig/dumpconf file: .br @@ -149,7 +157,7 @@ BR_LBA=0 # .br -# Example configuration for CP commands on panic +# Example configuration for CP commands .br # .br @@ -163,7 +171,7 @@ VMCMD_3="IPL 3456" # .br -# Example config for re-IPL on panic +# Example config for re-IPL .br # .br @@ -172,4 +180,4 @@ ON_PANIC=reipl DELAY_MINUTES=5 .SH SEE ALSO -Linux on zSeries: Using the Dump Tools +Linux on System z: Using the Dump Tools --- a/zdump/Makefile +++ b/zdump/Makefile @@ -6,7 +6,8 @@ LDLIBS += -lz all: zgetdump OBJECTS = zgetdump.o opts.o zg.o \ - dfi.o dfi_lkcd.o dfi_elf.o dfi_s390.o dfi_s390mv.o dfi_s390tape.o \ + dfi.o dfi_vmcoreinfo.o \ + dfi_lkcd.o dfi_elf.o dfi_s390.o dfi_s390mv.o dfi_s390tape.o \ dfi_kdump.o \ dfo.o dfo_elf.o dfo_s390.o \ df_s390.o \ --- a/zdump/dfi.c +++ b/zdump/dfi.c @@ -3,7 +3,7 @@ * * Generic input dump format functions (DFI - Dump Format Input) * - * Copyright IBM Corp. 2001, 2010 + * Copyright IBM Corp. 2001, 2011 * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com> */ @@ -23,6 +23,7 @@ static struct dfi *dfi_vec[] = { &dfi_lkcd, &dfi_elf, &dfi_kdump, + &dfi_kdump_flat, NULL, }; @@ -50,14 +51,16 @@ struct mem { * Dump header attribute information */ struct attr { - unsigned int *dfi_version; - struct timeval *time; - struct timeval *time_end; - u64 *cpu_id; - u64 *mem_size_real; - enum dfi_arch *build_arch; - unsigned int *vol_nr; - u32 *real_cpu_cnt; + unsigned int *dfi_version; + struct timeval *time; + struct timeval *time_end; + u64 *cpu_id; + u64 *mem_size_real; + enum dfi_arch *build_arch; + unsigned int *vol_nr; + u32 *real_cpu_cnt; + struct new_utsname *utsname; + char *dump_method; }; /* @@ -69,6 +72,8 @@ static struct { struct mem mem; struct cpus cpus; struct dfi *dfi; + unsigned long kdump_base; + unsigned long kdump_size; } l; /* @@ -92,6 +97,16 @@ static void date_print(void) } /* + * Initialize DFI mem + */ +static void mem_init(void) +{ + l.mem.start_addr = U64_MAX; + l.mem.end_addr = 0; + list_init(&l.mem.chunk_list); +} + +/* * Print memory map */ static void mem_map_print(void) @@ -106,6 +121,23 @@ static void mem_map_print(void) } /* + * Is memory range valid? + */ +int dfi_mem_range_valid(u64 addr, u64 len) +{ + struct dfi_mem_chunk *mem_chunk; + u64 addr_end = addr + len; + + do { + mem_chunk = dfi_mem_chunk_find(addr); + if (!mem_chunk) + return 0; + addr += MIN(len, mem_chunk->end - addr + 1); + } while (addr < addr_end); + return 1; +} + +/* * Print dump information (--info option) */ void dfi_info_print(void) @@ -115,8 +147,15 @@ void dfi_info_print(void) if (l.attr.dfi_version) STDERR(" Version............: %d\n", *l.attr.dfi_version); date_print(); + if (l.attr.dump_method) + STDERR(" Dump method........: %s\n", l.attr.dump_method); if (l.attr.cpu_id) STDERR(" Dump CPU ID........: %llx\n", *l.attr.cpu_id); + if (l.attr.utsname) { + STDERR(" UTS node name......: %s\n", l.attr.utsname->nodename); + STDERR(" UTS kernel release.: %s\n", l.attr.utsname->release); + STDERR(" UTS kernel version.: %s\n", l.attr.utsname->version); + } if (l.attr.vol_nr) STDERR(" Volume number......: %d\n", *l.attr.vol_nr); if (l.attr.build_arch) @@ -127,11 +166,14 @@ void dfi_info_print(void) STDERR(" CPU count (online).: %d\n", l.cpus.cnt); if (l.attr.real_cpu_cnt) STDERR(" CPU count (real)...: %d\n", *l.attr.real_cpu_cnt); - STDERR(" Dump memory range..: %lld MB\n", TO_MIB(dfi_mem_range())); + if (dfi_mem_range()) + STDERR(" Dump memory range..: %lld MB\n", + TO_MIB(dfi_mem_range())); if (l.attr.mem_size_real) STDERR(" Real memory range..: %lld MB\n", TO_MIB(*l.attr.mem_size_real)); - mem_map_print(); + if (dfi_mem_range()) + mem_map_print(); if (l.dfi->info_dump) { STDERR("\nDump device info:\n"); l.dfi->info_dump(); @@ -181,6 +223,8 @@ unsigned int dfi_mem_chunk_cnt(void) */ u64 dfi_mem_range(void) { + if (l.mem.start_addr == U64_MAX) + return 0; return l.mem.end_addr - l.mem.start_addr + 1; } @@ -246,6 +290,8 @@ struct dfi_mem_chunk *dfi_mem_chunk_find void dfi_cpu_info_init(enum dfi_cpu_content cpu_content) { l.cpus.content = cpu_content; + list_init(&l.cpus.list); + l.cpus.cnt = 0; } /* @@ -324,7 +370,7 @@ struct list *dfi_cpu_list(void) /* * Read memory at given address */ -void dfi_mem_read(u64 addr, void *buf, size_t cnt) +static void dfi_mem_read_raw(u64 addr, void *buf, size_t cnt) { struct dfi_mem_chunk *mem_chunk; u64 size, copied = 0; @@ -340,6 +386,55 @@ void dfi_mem_read(u64 addr, void *buf, s } /* + * Read memory at given address and do kdump swap if necessary + */ +void dfi_mem_read(u64 addr, void *buf, size_t cnt) +{ + u64 copied = 0; + + if (!g.opts.kdump_swap) + return dfi_mem_read_raw(addr, buf, cnt); + + if (addr < l.kdump_size) { + copied = MIN(cnt, l.kdump_size - addr); + dfi_mem_read_raw(addr + l.kdump_base, buf, copied); + } + dfi_mem_read_raw(addr + copied, buf + copied, cnt - copied); +} + +/* + * Read memory at given address with return code + */ +static int dfi_mem_read_raw_rc(u64 addr, void *buf, size_t cnt) +{ + if (!dfi_mem_range_valid(addr, cnt)) + return -EINVAL; + dfi_mem_read(addr, buf, cnt); + return 0; +} + +/* + * Read memory at given address with return code and do kdump swap if necessary + * rc = 0: Read was successful + */ +int dfi_mem_read_rc(u64 addr, void *buf, size_t cnt) +{ + u64 copied = 0; + int rc; + + if (!g.opts.kdump_swap) + return dfi_mem_read_raw_rc(addr, buf, cnt); + + if (addr < l.kdump_size) { + copied = MIN(cnt, l.kdump_size - addr); + rc = dfi_mem_read_raw_rc(addr + l.kdump_base, buf, copied); + if (rc) + return rc; + } + return dfi_mem_read_raw_rc(addr + copied, buf + copied, cnt - copied); +} + +/* * Get input dump format name */ const char *dfi_name(void) @@ -380,27 +475,11 @@ const char *dfi_arch_str(enum dfi_arch a } /* - * Initialize input dump format. + * Initialize attributes */ -int dfi_init(void) +static void attr_init(void) { - struct dfi *dfi; - int i = 0, rc; - - l.mem.start_addr = U64_MAX; - l.mem.end_addr = 0; - list_init(&l.mem.chunk_list); - list_init(&l.cpus.list); - while ((dfi = dfi_vec[i])) { - l.dfi = dfi; - g.fh = zg_open(g.opts.device, O_RDONLY, ZG_CHECK); - rc = dfi->init(); - if (rc == 0 || rc == -EINVAL) - return rc; - zg_close(g.fh); - i++; - } - ERR_EXIT("No valid dump found on \"%s\"", g.opts.device); + memset(&l.attr, 0, sizeof(l.attr)); } /* @@ -408,6 +487,8 @@ int dfi_init(void) */ void dfi_attr_time_set(struct timeval *time) { + if (time->tv_sec == 0) + return; l.attr.time = zg_alloc(sizeof(*l.attr.time)); *l.attr.time = *time; } @@ -422,6 +503,8 @@ struct timeval *dfi_attr_time(void) */ void dfi_attr_time_end_set(struct timeval *time_end) { + if (time_end->tv_sec == 0) + return; l.attr.time_end = zg_alloc(sizeof(*l.attr.time_end)); *l.attr.time_end = *time_end; } @@ -464,6 +547,33 @@ u64 *dfi_attr_cpu_id(void) } /* + * Attribute: utsname + */ +void dfi_attr_utsname_set(struct new_utsname *utsname) +{ + l.attr.utsname = zg_alloc(sizeof(*utsname)); + memcpy(l.attr.utsname, utsname, sizeof(*utsname)); +} + +struct new_utsname *dfi_attr_utsname(void) +{ + return l.attr.utsname; +} + +/* + * Attribute: dump method + */ +void dfi_attr_dump_method_set(char *dump_method) +{ + l.attr.dump_method = zg_strdup(dump_method); +} + +char *dfi_attr_dump_method(void) +{ + return l.attr.dump_method; +} + +/* * Attribute: Real memory size */ void dfi_attr_mem_size_real_set(u64 mem_size_real) @@ -612,3 +722,128 @@ void dfi_cpu_add_from_lc(u32 lc_addr) dfi_cpu_add(cpu); } +/* + * Return kdump base + */ +unsigned long dfi_kdump_base(void) +{ + return l.kdump_base; +} + +/* + * Check if dump contains a kdump dump and initialize kdump_base and kdump_size + */ +static void kdump_init(void) +{ + unsigned long base, size; + + dfi_mem_read_raw(0x10418, &base, sizeof(base)); + dfi_mem_read_raw(0x10420, &size, sizeof(size)); + if (base == 0 || size == 0) + return; + if (base % MIB || size % MIB) + return; + if (!dfi_mem_range_valid(base, size)) + return; + l.kdump_base = base; + l.kdump_size = size; +} + +/* + * If "--select prod" is set, modify DFI to show production system dump + */ +static void kdump_swap_init(void) +{ + unsigned long prefix, ptr, count, tv_sec, i; + struct timeval timeval; + + if (g.opts.select_specified && !l.kdump_base) + ERR_EXIT("The \"--select\" option is not possible with this " + "dump"); + if (!g.opts.kdump_swap) + return; + + attr_init(); + dfi_arch_set(DFI_ARCH_64); + dfi_cpu_info_init(DFI_CPU_CONTENT_NONE); + if (dfi_vmcoreinfo_symbol(&ptr, "lowcore_ptr")) + return; + if (dfi_vmcoreinfo_length(&count, "lowcore_ptr")) + return; + if (dfi_vmcoreinfo_val(&tv_sec, "CRASHTIME") == 0) { + timeval.tv_sec = tv_sec; + timeval.tv_usec = 0; + dfi_attr_time_set(&timeval); + } + dfi_cpu_info_init(DFI_CPU_CONTENT_ALL); + for (i = 0; i < count; i++) { + if (dfi_mem_read_rc(ptr + i * sizeof(long), &prefix, + sizeof(prefix))) + continue; + if (prefix == 0) + continue; + if (prefix % 0x1000) + continue; + dfi_cpu_add_from_lc(prefix); + } +} + +/* + * Try to get utsname info from dump + */ +static void utsname_init(void) +{ + struct new_utsname *utsname; + unsigned long ptr; + char buf[1024]; + + if (dfi_vmcoreinfo_symbol(&ptr, "init_uts_ns")) + return; + if (dfi_mem_read_rc(ptr, buf, sizeof(buf))) + return; + utsname = memchr(buf, 'L', sizeof(buf) - sizeof(*utsname)); + if (!utsname) + return; + if (strncmp(utsname->sysname, "Linux", sizeof(utsname->version) != 0)) + return; + dfi_attr_utsname_set(utsname); +} + +/* + * Initialize input dump format. + */ +int dfi_init(void) +{ + struct dfi *dfi; + int i = 0, rc; + + l.arch = DFI_ARCH_UNKNOWN; + mem_init(); + attr_init(); + dfi_cpu_info_init(DFI_CPU_CONTENT_NONE); + while ((dfi = dfi_vec[i])) { + l.dfi = dfi; + g.fh = zg_open(g.opts.device, O_RDONLY, ZG_CHECK); + rc = dfi->init(); + if (rc == 0 && dfi_feat_seek()) { + kdump_init(); + dfi_vmcoreinfo_init(); + kdump_swap_init(); + utsname_init(); + } + if (rc == 0 || rc == -EINVAL) + return rc; + zg_close(g.fh); + i++; + } + ERR_EXIT("No valid dump found on \"%s\"", g.opts.device); +} + +/* + * Cleanup input dump format. + */ +void dfi_exit(void) +{ + if (l.dfi && l.dfi->exit) + l.dfi->exit(); +} --- a/zdump/dfi.h +++ b/zdump/dfi.h @@ -3,13 +3,14 @@ * * Generic input dump format functions (DFI - Dump Format Input) * - * Copyright IBM Corp. 2001, 2010 + * Copyright IBM Corp. 2001, 2011 * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com> */ #ifndef DFI_H #define DFI_H +#include <linux/utsname.h> #include "zg.h" #include "list.h" @@ -144,6 +145,7 @@ struct dfi_mem_chunk { extern void dfi_mem_chunk_add(u64 start, u64 size, void *data, dfi_mem_chunk_read_fn read_fn); extern u64 dfi_mem_range(void); +extern int dfi_mem_range_valid(u64 addr, u64 len); extern unsigned int dfi_mem_chunk_cnt(void); extern struct dfi_mem_chunk *dfi_mem_chunk_first(void); extern struct dfi_mem_chunk *dfi_mem_chunk_next(struct dfi_mem_chunk *chunk); @@ -166,6 +168,12 @@ extern struct timeval *dfi_attr_time_end extern void dfi_attr_cpu_id_set(u64 cpu_id); extern u64 *dfi_attr_cpu_id(void); +extern void dfi_attr_utsname_set(struct new_utsname *utsname); +extern struct new_utsname *dfi_attr_utsname(void); + +extern void dfi_attr_dump_method_set(char *dump_method); +extern char *dfi_attr_dump_method(void); + extern void dfi_attr_mem_size_real_set(u64 mem_size_real); extern u64 *dfi_attr_mem_size_real(); @@ -185,6 +193,7 @@ extern u32 *dfi_attr_real_cpu_cnt(void); * DFI external functions */ extern void dfi_mem_read(u64 addr, void *buf, size_t cnt); +extern int dfi_mem_read_rc(u64 addr, void *buf, size_t cnt); extern void dfi_info_print(void); /* @@ -197,16 +206,35 @@ extern int dfi_feat_seek(void); extern int dfi_feat_copy(void); /* + * DFI kdump functions + */ +extern unsigned long dfi_kdump_base(void); + +/* + * DFI vmcoreinfo functions + */ +extern void dfi_vmcoreinfo_init(void); +extern char *dfi_vmcoreinfo_get(void); +extern int dfi_vmcoreinfo_tag(char *str, int len, const char *sym); +extern int dfi_vmcoreinfo_symbol(unsigned long *val, const char *sym); +extern int dfi_vmcoreinfo_offset(unsigned long *offs, const char *sym); +extern int dfi_vmcoreinfo_size(unsigned long *size, const char *sym); +extern int dfi_vmcoreinfo_length(unsigned long *len, const char *sym); +extern int dfi_vmcoreinfo_val(unsigned long *val, const char *sym); + +/* * DFI operations */ struct dfi { const char *name; int (*init)(void); + void (*exit)(void); void (*info_dump)(void); int feat_bits; }; extern const char *dfi_name(void); extern int dfi_init(void); +extern void dfi_exit(void); #endif /* DFI_H */ --- a/zdump/dfi_kdump.c +++ b/zdump/dfi_kdump.c @@ -1,27 +1,18 @@ /* * zgetdump - Tool for copying and converting System z dumps * - * kdump input format + * kdump and kdump_flat input format * - * Copyright IBM Corp. 2001, 2010 + * Copyright IBM Corp. 2001, 2011 * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com> */ #include "zgetdump.h" -struct l_new_utsname { - char sysname[65]; - char nodename[65]; - char release[65]; - char version[65]; - char machine[65]; - char domainname[65]; -}; - struct df_kdump_hdr { char signature[8]; int header_version; - struct l_new_utsname utsname; + struct new_utsname utsname; struct timeval timestamp; unsigned int status; int block_size; @@ -46,6 +37,17 @@ struct df_kdump_sub_hdr { unsigned long size_vmcoreinfo; }; +struct df_kdump_flat_hdr { + char signature[16]; + u64 type; + u64 version; +}; + +struct df_kdump_flat_data_hdr { + s64 offs; + s64 size; +}; + /* * File local static data */ @@ -70,6 +72,10 @@ static void print_header(void) STDERR(" written_blocks : %d\n", l.hdr.written_blocks); STDERR(" current_cpu : %d\n", l.hdr.current_cpu); STDERR(" nr_cpus : %d\n", l.hdr.nr_cpus); +} + +static void print_sub_header(void) +{ STDERR("kdump sub header\n"); STDERR(" phys_base : 0x%lx\n", l.shdr.phys_base); STDERR(" dump_level : %d\n", l.shdr.dump_level); @@ -80,9 +86,34 @@ static void print_header(void) #endif /* - * Read kdump dump header + * Check for kdump flat end marker + */ +static inline int kdump_flat_endmarker(struct df_kdump_flat_data_hdr *d_hdr) +{ + return (d_hdr->offs == -1) && (d_hdr->size == -1); +} + +/* + * Init kdump dump header + */ +static int init_kdump_hdr(struct df_kdump_hdr *hdr) +{ + if (memcmp(hdr->signature, "KDUMP", 5) != 0) + return -ENODEV; + dfi_attr_version_set(hdr->header_version); + dfi_attr_real_cpu_cnt_set(hdr->nr_cpus); + dfi_attr_utsname_set(&hdr->utsname); + dfi_attr_time_set(&hdr->timestamp); + dfi_arch_set(DFI_ARCH_64); + dfi_mem_chunk_add(0, (unsigned long) hdr->max_mapnr * PAGE_SIZE, + NULL, NULL); + return 0; +} + +/* + * Initialize kdump DFI */ -static int read_kdump_hdr(void) +static int dfi_kdump_init(void) { if ((zg_type(g.fh) == ZG_TYPE_FILE) && (zg_size(g.fh) < sizeof(l.hdr))) return -ENODEV; @@ -91,32 +122,98 @@ static int read_kdump_hdr(void) return -ENODEV; zg_seek(g.fh, l.hdr.block_size, ZG_CHECK); zg_read(g.fh, &l.shdr, sizeof(l.shdr), ZG_CHECK); - dfi_attr_version_set(l.hdr.header_version); - dfi_attr_real_cpu_cnt_set(l.hdr.nr_cpus); - dfi_arch_set(DFI_ARCH_64); #ifdef DEBUG print_header(); + print_sub_header(); #endif - return 0; + return init_kdump_hdr(&l.hdr); } /* - * Initialize kdump DFI + * kdump DFI operations */ -static int dfi_kdump_init(void) +struct dfi dfi_kdump = { + .name = "kdump", + .init = dfi_kdump_init, + .feat_bits = 0, +}; + +#ifdef DEBUG +static void print_kdump_flat_header(struct df_kdump_flat_hdr *hdr) +{ + STDERR("diskdump main header\n"); + STDERR(" signature : %s\n", hdr->signature); + STDERR(" version : %lld\n", hdr->version); + STDERR(" type : %lld\n", hdr->type); +} +#endif + +/* + * Read makedumpfile dump header + */ +static int read_kdump_flat_hdr(void) { - if (read_kdump_hdr() != 0) + struct df_kdump_flat_hdr hdr; + + if ((zg_type(g.fh) == ZG_TYPE_FILE) && (zg_size(g.fh) < sizeof(l.hdr))) return -ENODEV; - dfi_mem_chunk_add(0, l.hdr.max_mapnr * PAGE_SIZE, NULL, NULL); + zg_read(g.fh, &hdr, sizeof(hdr), ZG_CHECK); + if (memcmp(hdr.signature, "makedumpfile", 12) != 0) + return -ENODEV; + if (hdr.type != 1) + return -ENODEV; +#ifdef DEBUG + print_kdump_flat_header(&hdr); +#endif return 0; +} + +/* + * Read kdump header from fh + */ +static int read_kdump_hdr(struct zg_fh *fh, s64 size) +{ + struct df_kdump_hdr hdr; + if (size < (s64) sizeof(hdr)) + ERR_EXIT("Can't get kdump header"); + if (zg_read(fh, &hdr, sizeof(hdr), ZG_CHECK_ERR) != sizeof(hdr)) + return -EINVAL; + if (init_kdump_hdr(&hdr)) + return -EINVAL; + zg_seek_cur(fh, -sizeof(hdr), ZG_CHECK_NONE); + return 0; } /* - * S390 DFI operations + * Initialize kdump_flat DFI */ -struct dfi dfi_kdump = { - .name = "kdump", - .init = dfi_kdump_init, +static int dfi_kdump_flat_init(void) +{ + struct df_kdump_flat_data_hdr d_hdr; + + if (read_kdump_flat_hdr() != 0) + return -ENODEV; + zg_seek(g.fh, 4096, ZG_CHECK); + zg_read(g.fh, &d_hdr, sizeof(d_hdr), ZG_CHECK); + do { + if (d_hdr.offs == 0 && read_kdump_hdr(g.fh, d_hdr.size) != 0) + return -EINVAL; + zg_seek_cur(g.fh, d_hdr.size, ZG_CHECK_NONE); + if (zg_read(g.fh, &d_hdr, sizeof(d_hdr), + ZG_CHECK_ERR) != sizeof(d_hdr)) + return -EINVAL; + } while ((d_hdr.offs >= 0) && (d_hdr.size > 0)); + if (kdump_flat_endmarker(&d_hdr)) + return 0; + return -EINVAL; +} + +/* + * kdump_flat DFI operations + */ +struct dfi dfi_kdump_flat = { + .name = "kdump_flat", + .init = dfi_kdump_flat_init, .feat_bits = 0, }; --- /dev/null +++ b/zdump/dfi_vmcoreinfo.c @@ -0,0 +1,218 @@ +/* + * zgetdump - Tool for copying and converting System z dumps + * + * vmcoreinfo access functions + * + * Copyright IBM Corp. 2011 + * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com> + */ + +#include <elf.h> +#include "zgetdump.h" + +#ifdef __s390x__ +#define LC_VMCORE_INFO 0xe0c +#else +#define LC_VMCORE_INFO 0xe08 +#endif + +#define LC_OS_INFO 0xe18 +#define OS_INFO_MAGIC 0x4f53494e464f535aULL /* OSINFOSZ */ + +struct os_info { + u64 magic; + u32 csum; + u16 version_major; + u16 version_minor; + u64 crashkernel_addr; + u64 crashkernel_size; + u64 vmcoreinfo_addr; + u64 vmcoreinfo_size; + u32 vmcoreinfo_csum; + u64 reipl_block_addr; + u64 reipl_block_size; + u32 reipl_block_csum; + u64 init_fn_addr; + u64 init_fn_size; + u32 init_fn_csum; + u8 reserved[4004]; +} __attribute__ ((packed)); + +/* + * File local static data + */ +static struct { + char *vmcoreinfo; + struct os_info *os_info; +} l; + +static inline u32 csum_partial(const void *buff, int len, u32 sum) +{ + register unsigned long reg2 asm("2") = (unsigned long) buff; + register unsigned long reg3 asm("3") = (unsigned long) len; + + asm volatile( + "0: cksm %0,%1\n" /* do checksum on longs */ + " jo 0b\n" + : "+d" (sum), "+d" (reg2), "+d" (reg3) : : "cc", "memory"); + return sum; +} + +static u32 os_info_csum(struct os_info *os_info) +{ + int size = sizeof(*os_info) - offsetof(struct os_info, version_major); + return csum_partial(&os_info->version_major, size, 0); +} + +static struct os_info *os_info_get(void) +{ + static struct os_info os_info; + unsigned long addr; + + dfi_mem_read(LC_OS_INFO, &addr, sizeof(addr)); + if (addr % 0x1000) + return NULL; + if (dfi_mem_read_rc(addr, &os_info, sizeof(os_info))) + return NULL; + if (os_info.magic != OS_INFO_MAGIC) + return NULL; + if (os_info.csum != os_info_csum(&os_info)) + return NULL; + return &os_info; +} + +/* + * Initialize vmcoreinfo + */ +void dfi_vmcoreinfo_init(void) +{ + unsigned long addr, size; + Elf64_Nhdr note; + char str[128]; + + l.os_info = os_info_get(); + + if (l.os_info && l.os_info->vmcoreinfo_size) { + addr = l.os_info->vmcoreinfo_addr; + size = l.os_info->vmcoreinfo_size; + } else { + dfi_mem_read(LC_VMCORE_INFO, &addr, sizeof(addr)); + if (addr == 0) + return; + if (dfi_mem_read_rc(addr, ¬e, sizeof(note))) + return; + memset(str, 0, sizeof(str)); + if (dfi_mem_read_rc(addr + sizeof(note), str, note.n_namesz)) + return; + if (memcmp(str, "VMCOREINFO", sizeof("VMCOREINFO") != 0)) + return; + size = note.n_descsz; + addr += 24; + } + l.vmcoreinfo = zg_alloc(size + 1); + if (dfi_mem_read_rc(addr, l.vmcoreinfo, size)) { + zg_free(l.vmcoreinfo); + l.vmcoreinfo = NULL; + return; + } + l.vmcoreinfo[size] = 0; +} + +/* + * Return vmcoreinfo data + */ +char *dfi_vmcoreinfo_get(void) +{ + return l.vmcoreinfo; +} + +/* + * Generic function: Return vmcoreinfo item (-1 on failure) + */ +static int vmcoreinfo_item(char *buf, int len, const char *fmt, const char *sym) +{ + + char str[1024], *sym_str, *sym_str_end; + + if (!l.vmcoreinfo) + return -1; + if (fmt) + snprintf(str, sizeof(str), "%s(%s)=", fmt, sym); + else + snprintf(str, sizeof(str), "%s=", sym); + sym_str = strstr(l.vmcoreinfo, str); + if (!sym_str) + return -1; + sym_str += strlen(str); + sym_str_end = strchr(sym_str, '\n'); + if (!sym_str_end) + sym_str_end = strchr(sym_str, '\0'); + memset(str, 0, sizeof(str)); + memcpy(str, sym_str, (unsigned long) (sym_str_end - sym_str)); + strcpy(buf, str); + return 0; +} + +/* + * Generic function: Return vmcoreinfo ulong item (-1 on failure) + */ +static int vmcoreinfo_item_ulong(unsigned long *val, const char *fmt, + const char *sym, unsigned long base) +{ + char str[1024]; + int rc; + + rc = vmcoreinfo_item(str, sizeof(str), fmt, sym); + if (rc) + return rc; + *val = strtoul(str, NULL, base); + return 0; +} + +/* + * Return vmcoreinfo tag (-1 on failure) + */ +int dfi_vmcoreinfo_tag(char *str, int len, const char *sym) +{ + return vmcoreinfo_item(str, len, NULL, sym); +} + +/* + * Return vmcoreinfo symbol address (-1 on failure) + */ +int dfi_vmcoreinfo_symbol(unsigned long *addr, const char *sym) +{ + return vmcoreinfo_item_ulong(addr, "SYMBOL", sym, 16); +} + +/* + * Return vmcoreinfo offset of a member of a datastructure (-1 on failure) + */ +int dfi_vmcoreinfo_offset(unsigned long *off, const char *sym) +{ + return vmcoreinfo_item_ulong(off, "OFFSET", sym, 10); +} + +/* + * Return vmcoreinfo datatype size (-1 on failure) + */ +int dfi_vmcoreinfo_size(unsigned long *size, const char *sym) +{ + return vmcoreinfo_item_ulong(size, "SIZE", sym, 10); +} + +/* + * Return vmcoreinfo symbol length (-1 on failure) + */ +int dfi_vmcoreinfo_length(unsigned long *len, const char *sym) +{ + return vmcoreinfo_item_ulong(len, "LENGTH", sym, 10); +} + +/* + * Return vmcoreinfo number (-1 on failure) + */ +int dfi_vmcoreinfo_val(unsigned long *val, const char *sym) +{ + return vmcoreinfo_item_ulong(val, NULL, sym, 10); +} --- a/zdump/dfo.c +++ b/zdump/dfo.c @@ -84,7 +84,10 @@ void dfo_chunk_mem_fn(struct dfo_chunk * { struct dfi_mem_chunk *mem_chunk = dfo_chunk->data; - mem_chunk->read_fn(mem_chunk, off, buf, cnt); + if (g.opts.kdump_swap) + dfi_mem_read(mem_chunk->start + off, buf, cnt); + else + mem_chunk->read_fn(mem_chunk, off, buf, cnt); } /* --- a/zdump/dfo_elf.c +++ b/zdump/dfo_elf.c @@ -83,7 +83,7 @@ static u64 loads_init(Elf64_Phdr *phdr, * Initialize ELF note */ static void *nt_init(void *buf, Elf64_Word type, void *desc, int d_len, - const char *name) + const char *name) { Elf64_Nhdr *note; u64 len; @@ -199,6 +199,18 @@ static void *nt_prpsinfo(void *ptr) } /* + * Initialize vmcoreinfo note + */ +static void *nt_vmcoreinfo(void *ptr) +{ + char *vmcoreinfo = dfi_vmcoreinfo_get(); + + if (!vmcoreinfo) + return ptr; + return nt_init(ptr, 0, vmcoreinfo, strlen(vmcoreinfo), "VMCOREINFO"); +} + +/* * Initialize notes */ static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset) @@ -221,6 +233,7 @@ static void *notes_init(Elf64_Phdr *phdr ptr = nt_s390_prefix(ptr, cpu); } out: + ptr = nt_vmcoreinfo(ptr); memset(phdr, 0, sizeof(*phdr)); phdr->p_type = PT_NOTE; phdr->p_offset = notes_offset; --- a/zdump/opts.c +++ b/zdump/opts.c @@ -18,23 +18,32 @@ * Text for --help option */ static char help_text[] = -"Usage: zgetdump [OPTIONS] [DUMPDEV] [DIR]\n" +"Usage: zgetdump DUMP [-s SYS] [-f FMT] > DUMP_FILE\n" +" -m DUMP [-s SYS] [-f FMT] DIR\n" +" -i DUMP [-s SYS]\n" +" -d DUMPDEV\n" +" -u DIR\n" "\n" -"The zgetdump tool takes as source a dump device or dump file (DUMPDEV)\n" -"and writes its contents to standard output, which you can redirect to a\n" -"specific file. Alternatively you can also mount the dump content.\n" -"Because zgetdump is able to read and write different dump formats, it\n" -"can be used to convert a dump from one format to another. zgetdump can\n" -"also verify if a dump is valid or check, whether a DASD device contains\n" -"a valid dump tool.\n" +"The zgetdump tool can read different dump formats from a dump device or from\n" +"a dump file. You can use zgetdump to:\n" "\n" -"-h, --help Print this help, then exit.\n" -"-v, --version Print version information, then exit.\n" -"-m, --mount Mount dump to mount point DIR\n" -"-u, --umount Unmount dump from mount point DIR\n" -"-f, --fmt <FMT> Specify target dump format FMT (\"elf\" or \"s390\")\n" -"-i, --info Print dump information\n" -"-d, --device Print dump device information\n"; +" - Write the dump content to standard output or to a file\n" +" - Mount the dump content to a Linux directory\n" +" - Convert a dump to a different dump format\n" +" - Check if a dump is valid\n" +" - Check if a DASD contains a valid dump tool.\n" +"\n" +"In the syntax description, DUMP specifies a dump device or dump file to be\n" +"read. The following options are available:\n" +"\n" +"-m, --mount Mount DUMP to mount point DIR\n" +"-u, --umount Unmount dump from mount point DIR\n" +"-i, --info Print DUMP information\n" +"-f, --fmt Specify target dump format FMT (\"elf\" or \"s390\")\n" +"-s, --select Select system data SYS (\"kdump\" or \"prod\")\n" +"-d, --device Print DUMPDEV (dump device) information\n" +"-v, --version Print version information, then exit\n" +"-h, --help Print this help, then exit\n"; static const char copyright_str[] = "Copyright IBM Corp. 2001, 2010"; @@ -90,6 +99,20 @@ static void fmt_set(const char *fmt) } /* + * Set "--select" option + */ +static void select_set(const char *select) +{ + if (strcmp(select, "kdump") != 0 && strcmp(select, "prod") != 0) + ERR_EXIT("Invalid select argument \"%s\" specified", select); + + g.opts.select_specified = 1; + g.opts.select = select; + if (strcmp(select, "prod") == 0) + g.opts.kdump_swap = 1; +} + +/* * Set mount point */ static void mount_point_set(const char *mount_point) @@ -138,6 +161,13 @@ static void action_set(enum zg_action ac */ static void verify_opts(void) { + if (g.opts.select_specified) { + if (g.opts.action != ZG_ACTION_MOUNT && + g.opts.action != ZG_ACTION_STDOUT && + g.opts.action != ZG_ACTION_DUMP_INFO) + ERR_EXIT("The \"--select\" option can only be " + "specifed for info, mount, or copy"); + } if (!g.opts.fmt_specified) return; @@ -203,10 +233,11 @@ void opts_parse(int argc, char *argv[]) {"mount", no_argument, NULL, 'm'}, {"umount", no_argument, NULL, 'u'}, {"fmt", required_argument, NULL, 'f'}, + {"select", required_argument, NULL, 's'}, {"debug", no_argument, NULL, 'X'}, {0, 0, 0, 0 } }; - static const char optstr[] = "hvidmuf:X"; + static const char optstr[] = "hvidmus:f:X"; init_defaults(); while ((opt = getopt_long(argc, argv, optstr, long_opts, &idx)) != -1) { @@ -230,6 +261,9 @@ void opts_parse(int argc, char *argv[]) case 'f': fmt_set(optarg); break; + case 's': + select_set(optarg); + break; case 'X': g.opts.debug_specified = 1; break; --- a/zdump/zg.c +++ b/zdump/zg.c @@ -199,6 +199,32 @@ ssize_t zg_read(struct zg_fh *zg_fh, voi } /* + * Read line + */ +ssize_t zg_gets(struct zg_fh *zg_fh, void *ptr, size_t cnt, enum zg_check check) +{ + size_t copied = 0; + char *buf = ptr; + ssize_t rc; + + if (cnt == 0) + return 0; + do { + rc = read(zg_fh->fh, &buf[copied], 1); + if (rc == -1) { + if (check == ZG_CHECK_NONE) + return rc; + ERR_EXIT_ERRNO("Could not read \"%s\"", zg_fh->path); + } + if (rc == 0 || buf[copied] == '\n' || copied == cnt - 1) + break; + copied++; + } while (1); + buf[copied] = '\0'; + return copied; +} + +/* * Return file size */ u64 zg_size(struct zg_fh *zg_fh) --- a/zdump/zg.h +++ b/zdump/zg.h @@ -31,12 +31,12 @@ /* * IEC definitions */ -#define KIB_DIFF (1024) -#define MIB_DIFF (1024 * 1024) -#define GIB_DIFF (1024 * 1024 * 1024) +#define KIB (1024) +#define MIB (1024 * 1024) +#define GIB (1024 * 1024 * 1024) -#define TO_MIB(x) ((x + (MIB_DIFF / 2)) / MIB_DIFF) -#define TO_KIB(x) ((x + (KIB_DIFF / 2)) / KIB_DIFF) +#define TO_MIB(x) ((x + (MIB / 2)) / MIB) +#define TO_KIB(x) ((x + (KIB / 2)) / KIB) /* * Memory functions @@ -162,6 +162,8 @@ extern struct zg_fh *zg_open(const char extern void zg_close(struct zg_fh *zg_fh); extern ssize_t zg_read(struct zg_fh *zg_fh, void *buf, size_t cnt, enum zg_check check); +extern ssize_t zg_gets(struct zg_fh *zg_fh, void *buf, size_t cnt, + enum zg_check check); extern u64 zg_size(struct zg_fh *zg_fh); extern off_t zg_tell(struct zg_fh *zg_fh, enum zg_check check); extern off_t zg_seek(struct zg_fh *zg_fh, off_t off, enum zg_check check); --- a/zdump/zgetdump.c +++ b/zdump/zgetdump.c @@ -81,6 +81,24 @@ fail: } /* + * Check if dump contains kdump dump and production system dump + */ +static void kdump_select_check(void) +{ + static char *msg = + "The dump contains \"kdump\" and \"production system\"\n" + " Access \"production system\" with \"-s prod\"\n" + " Access \"kdump\" with \"-s kdump\"\n" + " Send both dumps to your service organization"; + + if (g.opts.select_specified) + return; + if (!dfi_kdump_base()) + return; + ERR_EXIT(msg); +} + +/* * Run "--umount" action */ static int do_umount(void) @@ -109,6 +127,7 @@ static int do_dump_info(void) STDERR("\nERROR: Dump is not complete\n"); zg_exit(1); } + kdump_select_check(); dfi_info_print(); return 0; } @@ -121,6 +140,7 @@ static int do_mount(void) if (dfi_init() != 0) ERR_EXIT("Dump cannot be processed (is not complete)"); dfo_init(); + kdump_select_check(); return zfuse_mount_dump(); } @@ -132,6 +152,7 @@ static int do_stdout(void) if (dfi_init() != 0) ERR_EXIT("Dump cannot be processed (is not complete)"); dfo_init(); + kdump_select_check(); return stdout_write_dump(); } --- a/zdump/zgetdump.h +++ b/zdump/zgetdump.h @@ -30,10 +30,13 @@ struct options { char *device; char *mount_point; int fmt_specified; - const char *fmt; + const char *fmt; int debug_specified; char **argv_fuse; int argc_fuse; + const char *select; + int select_specified; + int kdump_swap; }; /* @@ -74,6 +77,7 @@ extern struct dfi dfi_s390; extern struct dfi dfi_lkcd; extern struct dfi dfi_elf; extern struct dfi dfi_kdump; +extern struct dfi dfi_kdump_flat; /* * Supported DFO dump formats
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor