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