Compare commits

..

163 Commits

Author SHA1 Message Date
Jan Höppner
18efac6306 New release s390-tools-2.20.0
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-04 12:34:47 +01:00
Jan Höppner
18f8db2225 bin/mk-authors: Run only on master branch history
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-04 12:34:47 +01:00
Marc Hartmayer
f1a13749df genprotimg: pv_comp: remove useless function
The endianness handling is already done before, so there is no need for
this function. Let's remove the useless `uint64_to_uint8_buf` function.

Suggested-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-04 09:50:29 +01:00
Matthew Rosato
b5da337d1e zdev: check for errors when removing a devtype setting
Currently, a device type setting being --removed from both the active and
persistent configuration via 'chzdev -t' can result in a scenario where
the setting is not removed from the active configuration (and an error
message is presented) but chzdev still proceeds to remove the setting from
the persistent configuration.
Update this logic so that devtype_remove_settings behaves the same way as
device_remove_settings and only perform the removal when no errors are
encountered.

Reported-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Jason J. Herne <jjherne@linux.ibm.com>
Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-04 09:50:29 +01:00
Peter Oberparleiter
a67888f36a cpictl: Report extended version information
Extend cpictl to report Linux distribution type and version information,
and another sublevel of Linux kernel version data via the system level
field of the SCLP CPI firmware interface. This data is intended to be
decoded by the IBM Z HMC web-UI to provide users a more detailed view of
Linux software levels installed in LPARs.

For this purpose, the format of the 64-bit system level word is extended
in a compatible way, that is, the meaning of existing fields remains
unchanged while additional data is added to previously unused fields.

The new format is defined as 0xabccddeeeeffgghh, where:
 - a=statistics flags
 - b=distro id
 - c=distro major version
 - d=distro minor version(s)
 - e=kernel sublevel 2
 - f=kernel version
 - g=kernel patchlevel
 - h=kernel sublevel 1

This format will be automatically reported for supported distributions
based on data from /etc/os-release. As before, users can override the
data by specifying a custom system level word in /etc/sysconfig/cpi.

To support manual specification of new data fields, the format of
cpictl's -L command line option and the CPI_SYSTEM_LEVEL environment
variable are extended as follows:

 - 0x<level>

   Specifies the system level as 64 bit hex value

 - [[[flags:]distro_id:distro_version:]kernel_version]

   Specifies the system level as list of optional fields. Any field that
   is omitted is initialized with automatically determined values.

Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Acked-by: Viktor Mihajlovski <mihajlov@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-02 11:54:30 +01:00
Marc Hartmayer
e1f174ae22 zipl/libc.h: declare start as __noreturn function
Declare `start` as __noreturn function since the function doesn't
return. Use the gcc/clang built-in function `__builtin_unreachable` to
make clear that `lpsw` and `diag308(DIAG390_IPL, NULL)` doesn't
return (see https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html and
https://clang.llvm.org/docs/LanguageExtensions.html#builtin-unreachable).

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-02 11:54:30 +01:00
Marc Hartmayer
7503d88b3b genprotimg/boot: add extended kernel command line support
In the past s390 used a fixed command line length of 896 bytes. This has
changed with newer Linux kernels. There is now a parm area indicating
the maximum command line size. This parm area has always been
initialized to zero, so with old kernels this field would read zero and
we must then assume that only 896 bytes are available.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-02 11:54:30 +01:00
Marc Hartmayer
43039943cd genprotimg/boot: remove useless volatile keyword
There is no reason to declare the variable @psw on the stack as
volatile.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-02 11:54:30 +01:00
Marc Hartmayer
b2e02d202a Add EditorConfig configuration
EditorConfig (https://editorconfig.org/) defines a file format for
defining coding styles. The most common editor do either provide native
support or via plugin support for EditorConfig.

This patch adds an EditorConfig configuration for s390-tools.

Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-02 11:54:30 +01:00
Peter Oberparleiter
1faa5d2957 zdev: Fix path resolution for multi-mount point file systems
zdev provides path resolution logic to determine which z-specific
devices contribute to the file system mounted at a specific mount point.
This logic is used by command-line option --by-path, but also to
determine the list of devices needed to enable the root file system.

Path resolution fails when a device provides multiple mount points such
as, for example, when using btrfs subvolumes, or when mounting the same
file system at multiple mount points. The failure is caused by zdev
relying on the MOUNTPOINT attribute of lsblk's output which only
contains a single mount point.

Fix this by making use of lsblk's MOUNTPOINTS attribute that contains
the full list of mount points. Note that MOUNTPOINTS was only introduced
with util-linux v2.37, therefore a fall-back to the old format is
needed.

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/129
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Reviewed-by: Eduard Shishkin <edward6@linux.ibm.com>
Reported-by: Dan Horák <dan@danny.cz>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-02 11:54:30 +01:00
Thomas Richter
d62e075450 cpumf/lshwc.c: Fix CPU list parameter setup for device driver
lshwc allows to specify a list of CPUs, for example

   # ./lshwc -a 2-3,66-68:b
   Date,Time,CPU,CPU_CYCLES(0),INSTRUCTIONS(1),L1I_DIR_WRITES(2),....
   2022-01-21,12:51:54,CPU2,68762,20999,283,14157,601,87255
   2022-01-21,12:51:54,CPU3,70514,21179,288,10654,586,90188
   2022-01-21,12:51:54,CPU4,48504,21018,141,7831,438,78494
   2022-01-21,12:51:54,Total,187780,63196,712,32642,1625,255937
   #

However, as seen on the output, the CPU list is incorrect. It shows
CPUs 2, 3 and 4 even when only CPU 2 and 3 was requested. CPUs 66, 67
and 68 have not been online and can not be displayed.

What happens is a wrong parameter conversion for the device driver.
CPUs 66, 67 and 68 are passed to the device driver as CPUs 2 3 and 4
and that data is returned.

Fix this and submit a CPU list with correct bit ordering:

   # ./lshwc -a 2-3,66-68:b
   Date,Time,CPU,CPU_CYCLES(0),INSTRUCTIONS(1),L1I_DIR_WRITES(2),...
   2022-01-21,12:59:18,CPU2,50753,18042,246,10972,494,60345
   2022-01-21,12:59:18,CPU3,54002,20390,232,9219,511,66033
   2022-01-21,12:59:18,Total,104755,38432,478,20191,1005,126378
   #

Reported-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-02 11:54:30 +01:00
Marc Hartmayer
983233730c zipl: add missing static declarations
Fix Sparse findings like:

 warning: symbol 'hash_table_find' was not declared. Should it be static?

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-02 11:54:30 +01:00
Vineeth Vijayan
ad024c06e1 zdev: modify the lsblk output parser in lszdev
Since version 2.37.x, with the commit 58b510e58 ("libsmartcols: sanitize
variable names on export output"), util-linux changes the output
characters of lsblk, where the ":" is replaced with an "_". Align the
lsblk output parser function in lszdev as per this change.

Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Suggested-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reported-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Tested-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-01-20 09:35:02 +01:00
Eduard Shishkin
e2843232d5 zipl/src: make gcc 11.2 happy
Add a prophylactic check that @filename is not NULL before its
dereference.

This addresses the following warning (which is a false positive,
since stat(2) is never called with NULL file name):

job.c:514:13: warning: argument 1 null where non-null expected
[-Wnonnull]
514 | if (stat(filename, &stats)) {
| ^~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/features.h:488,
from /usr/include/errno.h:25,
from job.c:13:
job.c: In function 'check_job_ipl_data':
/usr/include/sys/stat.h:227:12: note: in a call to function
'stat' declared 'nonnull'
227 | extern int __REDIRECT_NTH (stat, (const char *__restrict __file,

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/127
Reported-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-01-20 09:35:02 +01:00
Viktor Mihajlovski
b79d17d233 cpictl: Suppress messages for unwritable sysfs files
Under certain conditions, e.g. in a KVM guest, a write operation
to /sys/firmware/cpi/set can result in an error message to
stderr while the script returns with a zero exit code, indicating
success.

This can cause confusion if cpictl is called by systemd due to
the existence of a writable /sys/firmware/cpi/. Let's silence
cpictl when writing to the /sys/firmware/cpi/set. This is OK, as
nothing can be inferred from failure or success from the perspective
of the invoking Linux instance.

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/120

Signed-off-by: Viktor Mihajlovski <mihajlov@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-01-20 09:35:02 +01:00
Sven Schnelle
11b401b599 zipl: move and make check for maximum command line length dynamic
The maximum command line length is now dependent on the kernel image
that is loaded. Therefore move the check to check_common_ipl_data().
This function now reads the new kernel image, and check whether the
command line length is in the allowed range.

The command line size limit in zipl is now set to 64k, which is hopefully
enough.

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-01-20 09:35:02 +01:00
Sven Schnelle
69c5ee2e52 zipl: no need to check for NULL when calling free()
free() accepts NULL pointers, so no need for an extra check.

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-01-20 09:35:02 +01:00
Sven Schnelle
3ee625d74f zipl: add check_common_ipl_data()
There are two places where we check whether the initrd and kernel image
is readably. Add one helper function that checks this. This is also a
preparation for the extended command line handling, so that we have to
add that code in only one location.

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-01-20 09:35:02 +01:00
Sven Schnelle
832268ecb0 zipl: add error_text_section()
There are quite a few places that do:

if (section == NULL) {
	error_text("file '%s'", file);
} else {
	error_text("file '%s' in section '%s'", file, section);
}

Add a helper function to deduplicate that.

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-01-20 09:35:02 +01:00
Sven Schnelle
5fb6434548 zipl: add get_common_components() and finalize_common_address_data()
Most of get_*_components() and finalize_*_address_data() is the same
for normal ip, tape and dump types, so we can unify that.

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-01-20 09:35:02 +01:00
Sven Schnelle
5894e3f700 zipl: add free_common_ipl_data()
Add a small helper function to free the common ipl data to avoid
having the same code duplicated multiple times. Also remove the if()
check before the free as it is allowed to pass NULL pointers to free().

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-01-20 09:35:02 +01:00
Sven Schnelle
e384f06014 zipl: add common ipl data
Each ipl type takes at least a kernel image, parameter line and initrd
parameter. This is duplicated all over the place in the current
implementation. To simplify this, add struct job_common_ipl_data which
will hold this data.

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-01-20 09:35:02 +01:00
Sven Schnelle
1627c6a39f zipl: Support command lines longer than 896 bytes in bootloader
This adds support for long command lines. The boot loader stages
will no longer use a fixed limit when copying the command line, but
will use the maximum length from the kernel image that is being loaded.

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-01-20 09:35:02 +01:00
Sven Schnelle
bb8f17a7da zipl: fix tape boot
The assembly code in tape0.S loads the kernel from tape to offset 0x4000.
After loading the kernel it loads the parm file and stores it to the
address provided by zipl. zipl doesn't know about the 0x4000 load offset,
so this address is inside of the kernel image and will silently corrupt
the loaded image in memory.

Fix this by copying the kernel to the final destination before loading
the parm files and initrd. We can do this because we can strip the first
0x10000 bytes like the zipl C code does for non-tape IPL.

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-01-20 09:35:02 +01:00
Sven Schnelle
8b3d3dd4bd zipl: rename COMMAND_LINE_SIZE to LEGACY_COMMAND_LINE_SIZE
Preparation to support command lines that are longer than 896 bytes.

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-01-20 09:35:02 +01:00
Sven Schnelle
a5c04e5746 zipl/boot: rewrite setup_commandline()
No need to use memcpy() and carry the length around all the time.
Switch to using strlcpy() to simplify the code.

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-01-20 09:35:02 +01:00
Sven Schnelle
c5ae1a41da zipl/boot: add strlcpy implementation
add strlcpy from libutil to the zipl boot mini libc.

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-01-20 09:35:02 +01:00
Sven Schnelle
970c697983 zipl: move command line processing into its own function
Makes the code easier to read.

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Stefan Haberland<sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-01-20 09:35:01 +01:00
Sven Schnelle
cff4b0384f zipl: move secure boot verification into its own function
Makes the code easier to read.

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-01-20 09:35:01 +01:00
Dan Horák
724f800dc5 cpictl: fix permissions
The regular 0755 permission should be sufficient for cpictl.

Link: https://bugzilla.redhat.com/show_bug.cgi?id=2024102
Closes: https://github.com/ibm-s390-linux/s390-tools/pull/124
Signed-off-by: Dan Horák <dan@danny.cz>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-12-09 21:48:58 +01:00
Graham Inggs
4cdfe91ca9 README.md: refer to fuse3 instead of fuse
Update READMEs to refer to fuse3 instead of fuse.
Also, update minimum versions and FUSE upstream's homepage

Closes: https://github.com/ibm-s390-linux/s390-tools/pull/117
Signed-off-by: Graham Inggs <ginggs@debian.org>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-12-09 16:19:25 +01:00
Graham Inggs
a44db0f367 zdump, man pages: remove references to 'nonempty' option
In FUSE 3, nonempty is always true, and has been removed.
By default it is false on FUSE 2.

Therefore, remove 'nonempty' option from zdump and references to
the same in man pages.

GitHub-ID: https://github.com/ibm-s390-linux/s390-tools/pull/117
Signed-off-by: Graham Inggs <ginggs@debian.org>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-12-09 16:19:25 +01:00
Graham Inggs
03ddcd6267 zdsfs: fix compiler warnings
Compiling against fuse3 shows 'incompatible pointer type' warnings due
to the additional function arguments in the new API.

Therefore, adjust the declarations of zdsfs_getattr() and
zdsfs_readdir() to match.

GitHub-ID: https://github.com/ibm-s390-linux/s390-tools/pull/117
Signed-off-by: Graham Inggs <ginggs@debian.org>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-12-09 16:19:25 +01:00
Graham Inggs
5c468a220e hmcdrvfs: fix compiler warnings
Compiling against fuse3 shows 'incompatible pointer type' warnings due
to the additional function arguments in the new API.

Therefore, adjust the declarations of hmcdrv_fuse_getattr(),
hmcdrv_fuse_readdir() and hmcdrv_fuse_init() to match.

GitHub-ID: https://github.com/ibm-s390-linux/s390-tools/pull/117
Signed-off-by: Graham Inggs <ginggs@debian.org>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-12-09 16:19:25 +01:00
Graham Inggs
4ba65eaa74 cmsfs-fuse: fix compiler warnings
Compiling against fuse3 shows 'incompatible pointer type' warnings due
to the additional function arguments in the new API.

Therefore, adjust the declarations of cmsfs_getattr(), cmsfs_readdir(),
cmsfs_utimens(), cmsfs_rename() and cmsfs_truncate() to match.

GitHub-ID: https://github.com/ibm-s390-linux/s390-tools/pull/117
Signed-off-by: Graham Inggs <ginggs@debian.org>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-12-09 16:19:25 +01:00
Graham Inggs
58cae4fecd zdump: fix compiler warnings
Compiling against fuse3 shows 'incompatible pointer type' warnings due
to the additional function arguments in the new API.

Therefore, adjust the declarations of zfuse_getattr() and
zfuse_readdir() to match.

GitHub-ID: https://github.com/ibm-s390-linux/s390-tools/pull/117
Signed-off-by: Graham Inggs <ginggs@debian.org>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-12-09 16:19:25 +01:00
Graham Inggs
9b84de4b0a hsavmcore: fix compiler warnings
Compiling against fuse3 shows 'incompatible pointer type' warnings due
to the additional function arguments in the new API.

Therefore, adjust the declarations of vmcore_fuse_getattr() and
vmcore_fuse_readdir() to match.

GitHub-ID: https://github.com/ibm-s390-linux/s390-tools/pull/117
Signed-off-by: Graham Inggs <ginggs@debian.org>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-12-09 16:19:25 +01:00
Graham Inggs
e679a88d88 Switch from fuse2 to fuse3
Fuse 3.0.0 was released in December 2016. The last maintenance release
from the 2.9 branch was in January 2019, and users are encouraged to
transition to the actively developed 3.x branch.
https://github.com/libfuse/libfuse/releases/tag/fuse-2.9.9

Therefore, adapt cmsfs-fuse, hmcdrvfs, hsavmcore, zdsfs and zdump to
the new API, and adapt associated Makefiles to link the new library.

Closes: https://github.com/ibm-s390-linux/s390-tools/issues/116
GitHub-ID: https://github.com/ibm-s390-linux/s390-tools/pull/117
Link: https://bugs.launchpad.net/ubuntu/+source/s390-tools/+bug/1935666
[hoeppner@linux.ibm.com: Add links to commit message]
Signed-off-by: Graham Inggs <ginggs@debian.org>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-12-09 16:19:25 +01:00
Benjamin Block
6acf6ed76d chreipl-fcp-mpath: fix directory dependencies for parallel make install
When `make install` is called with parallel execution enabled (e.g.:
`-j2`), the dependencies for the necessary directories are not correct.
The `install` target depends on `install_dirs`, which creates the
necessary directories, and needs to run before any of the
`chreipl-fcp-mpath-install*` targets that have prerequisites on these
directories; but the `chreipl-fcp-mpath-install*` targets have
indirectly the same "hierarchy level" as `install_dirs`, and no direct
dependency on it.

Simplified it looks like this:
    install: install_dirs chreipl-fcp-mpath-install
    chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-udev-rules ...

This works fine with only one job, as `install_dirs` will be satisfied
first, before recursing into any other branch of the dependency tree.
But if we have more than one job, there is nothing in the rules that
prevents Make from working on both branches - `install_dirs` and
`chreipl-fcp-mpath-install` - at the same time, and so
`chreipl-fcp-mpath-install-udev-rules` might run before `install_dirs`,
and end up with a unsatisfied dependency:
    make[2]: *** No rule to make target '/usr/lib/udev/rules.d', needed by 'chreipl-fcp-mpath-install-udev-rules'.  Stop.

Fix this by adding direct dependencies on `install_dirs` for all the
directory prerequisites of `chreipl-fcp-mpath-install*` targets. This
way Make will need to satisfy `install_dirs` before it can work on any
of the other targets, and so the necessary directories will be created
in the correct order.

Reported-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Tested-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-12-09 16:19:25 +01:00
Marc Hartmayer
e7abf256f6 genprotimg: use NULL and not 0 for a NULL pointer
This fixes the sparse warning:

utils/crypto.c:443:68: warning: Using plain integer as NULL pointer

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-12-09 16:19:25 +01:00
Alexander Egorenkov
0d407904dd zdump/zg: Convert print macros to functions which can be mocked
This change allows mocking of print macros in unit tests.
Being able to do this in unit tests, enables us to catch output from
zgetdump functions and test it.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-12-09 16:19:25 +01:00
Alexander Egorenkov
2238eb820f zdump/zg: Save errno in _zg_err_errno()
_zg_err_errno() should save the current errno value before calling any
libc functions because they could change it. Failing to do so, may result
in _zg_err_errno() displaying an incorrect error message.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-12-09 16:19:25 +01:00
Alexander Egorenkov
81013f0c70 zdump/zg: Convert error and abort macros to functions which can be mocked
This change allows mocking of error/abort macros in unit tests.
Being able to do this in unit tests, enables us to test error conditions w/o
terminating the unit test runner.

The new error functions do not have "noreturn" attribute because
this would make mocking of them in unit tests impossible. We must not
compile these functions as noreturn because we need to return from them
in unit tests and returning from a noreturn function is an undefined
behavior in the C++ standard!

For more details:
- ISO/IEC 14882:2017, Chapter 10.6.8 "Noreturn attribute""
- https://en.cppreference.com/w/cpp/language/attributes/noreturn.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-12-09 16:19:25 +01:00
Marc Hartmayer
697c5dc405 zdump: write_dump: use FILE *
Use the more common `FILE *` for writing to the output.

Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-12-09 16:19:25 +01:00
Marc Hartmayer
e9deec4c62 zdump: copy: add support for file output
It is unusual to write the file output from a tool to stdout. Therefore
add a positional argument to the zgetdump convert action where the
output file can be specified. If no positional argument is given the
output is written to stdout as before and therefore there is no change
in the default behavior.

If the file output already exists an error is returned. The reason for
this is to avoid the situation where an existing dump is accidentally
overwritten by the user.

Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-12-09 16:19:25 +01:00
Alexander Egorenkov
d60b7770fd zdump/zg.h: Remove extern keyword from function declarations
The keyword extern before a function declaration is not required with
modern C compilers.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-12-09 16:19:25 +01:00
Alexander Egorenkov
70925f9aff zdump/df_elf: Introduce symbolic names for note names
To reduce code duplication.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-12-09 16:19:25 +01:00
Alexander Egorenkov
ef88fac874 zdump: Extract common ELF routines from dfo_elf and move to df_elf
The primary goal of this change is to split DFO ELF module into
multiple smaller ones for better unit testability.

The change doesn't introduce any functionality changes, just shuffling code
around.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-12-09 16:19:25 +01:00
Alexander Egorenkov
4bd16ba8ea zdump: Extract dfo_mem_chunk interface from DFO
The primary goal is to separate DFO code into multiple smaller modules
and make it unit testable.

This refactoring only moved the code around w/o changing any functionality.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-12-09 16:19:25 +01:00
Steffen Maier
f6a7da141c dbginfo.sh: fix missing syslog for step create_package
Without the fix, readers of syslog / systemd-journal can erroneously
think that dbginfo.sh was incomplete because the last logged step is
"17 of 18".
The fix also makes the missing line appear in dbginfo.log inside the
generated DBGINFO....tgz.
s390-tools v2.17.0 commit b7807d0195 ("dbginfo.sh: Add KVM commands
and rework data collection") turned create_package into a numbered
step.

Snippet of terminal output:

...
17 of 18:  Postprocessing
18 of 18:  Finalizing: Creating archive with collected data
Collected data was saved to:
 >>  /tmp/DBGINFO-....tgz  <<
Please review all collected data before sending to your service organization.

Syslog before:

...
dbginfo.sh[...]: 17 of 18:  Postprocessing
dbginfo.sh[...]: Data collection completed

Syslog after:

...
dbginfo.sh[...]: 17 of 18:  Postprocessing
dbginfo.sh[...]: 18 of 18:  Finalizing: Creating archive with collected data
dbginfo.sh[...]: Data collection completed

Fixes: b7807d0195 ("dbginfo.sh: Add KVM commands and rework data collection")
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-17 15:48:22 +01:00
Benjamin Block
1bbd34e500 chreipl-fcp-mpath: don't compress the manpage before installing it
Remove the call to `gzip` before installing the manpage during the
`make install` call. What and if compression is done should be handled by
the distribution tooling.

This also removes a dependency for the build process.

Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-17 15:48:22 +01:00
Benjamin Block
c2f8988444 chreipl-fcp-mpath: remove shebang from chreipl-fcp-mpath-common.sh.in
`chreipl-fcp-mpath-common.sh.in` is never executed, only used as argument
for `source` in the udev helper scripts, so the shebang is unnecessary, and
might be confusing.

Also, tools like `rpmlint` from the rpm software management will complain
about this; e.g.:
  s390-tools-chreipl-fcp-mpath.s390x: W: non-executable-script /usr/lib/chreipl-fcp-mpath/chreipl-fcp-mpath-common.sh 644 /bin/bash

Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-17 15:48:22 +01:00
Alexander Egorenkov
d2990db15f zdump/df_elf.h: Remove unused header include
df_elf.h doesn't use anything from dfo.h

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-17 15:48:22 +01:00
Marc Hartmayer
fd3d79335a zdump: dfo_elf: get rid of file local static data
Remove the need to have global file local static data.

Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-17 15:48:22 +01:00
Marc Hartmayer
07b3837e68 zdump: dump_chunks_init: replace 0 with off variable
...to make clear why `off` is initialized to 0 and that all calls to
`dfo_chunk_add` occur for the same reason. For consistency reasons adapt
the `off` value calculation as well.

Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-17 15:48:22 +01:00
Marc Hartmayer
13a1227a02 zdump: notes_init: rename some parameters
Rename the parameter `ptr` of `notes_init` to something meaningful. Since
it points to the start of the notes segment rename it to `segment_start`.
In addition, improve the documentation for the function.

Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-17 15:48:22 +01:00
Marc Hartmayer
52118a8d02 zdump: loads_init: refactor the code
Use `mem_chunk->size` instead of recalculate it. In addition, assign
`p_vaddr` to `p_paddr` to make clear that they must be equal and rename the
parameter `load_offset` to `elf_offset` to make clear that the offset in
the ELF vmcore file is meant. Finally rename `loads_init` to
`load_phdrs_init`.

Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-17 15:48:22 +01:00
Marc Hartmayer
ee89b850fe zdump: dfo_elf: notes_init: use PTR_DIFF
Use `PTR_DIFF` since this is exactly what is done here.

Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-17 15:48:22 +01:00
Marc Hartmayer
5160f41079 zdump: PTR_(SUB|ADD) cast result to void pointer
This cast makes the macros easier to use without getting compiler warnings.

e.g.

dfo_elf.c: In function 'dfo_elf_init':
dfo_elf.c:343:20: warning: assignment to 'Elf64_Phdr *' from incompatible pointer type 'char *' [-Wincompatible-pointer-types]
  343 |         phdrs_load = PTR_ADD(phdr_notes, sizeof(Elf64_Phdr) * phdrs_notes_count);

Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-17 15:48:22 +01:00
Steffen Eiden
5b0115fdb4 zdump: refractor PTR_DIFF
PTR_SUB already implements subtraction of pointers. Let's reuse it.

Suggested-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-17 15:48:22 +01:00
Jan Höppner
ae305b5158 Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 17:05:37 +01:00
Jan Höppner
04407d24fc New release s390-tools-2.19.0
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 17:05:37 +01:00
Jan Höppner
bcb8ea09d1 lshwc: Fix compile error for gcc <8.1
With gcc < 8.1 the following compile error occurs:

lshwc.c:52:37: error: initializer element is not constant
 static unsigned int read_interval = ioctlsleep, cfvn, csvn, authorization;
                                     ^~~~~~~~~~

Even though this gcc bug was fixed in gcc 8.1+, change the constant
definition to a #define to make the tool compile with older compilers as
well.

Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69960
Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66618
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Benjamin Block
88619b6dba chreipl-fcp-mpath: documentation and man page
Add a README.md for chreipl-fcp-mpath and infrastructure to build and
install a man page generated from the README.md. Building and installing
of the man page is only done when supplying the make option `ENABLE_DOC=1`
(per default disabled). The `pandoc` utility is used to build the man page.

The README.md is reused since there is no other tool or command as part of
chreipl-fcp-mpath that needs to be documented in a separate man page.

Also add information about chreipl-fcp-mpath to the main README.md and
CHANGELOG.md.

Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Benjamin Block
e127b89624 chreipl-fcp-mpath: optional dracut config to bundle toolset into initrd
Add a dracut configuration file that might optionally be installed along
with the toolset (per default to: $(USRLIBDIR)/dracut/dracut.conf.d). It
causes the udev rules and helper scripts to be included into an initial
ramdisk, when (re-)built with dracut; along with any dependency.

This is only done when passing `HAVE_DRACUT` set to 1 during the
installation (default is 0), e.g.: make install HAVE_DRACUT=1.

Enabling the toolset during the initial ramdisk phase has the advantage
that paths can be audited earlier in the life cycle of this Linux
runtime, e.g. to record the WWID in the ID-file.

Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Benjamin Block
3591b94c42 chreipl-fcp-mpath: try to change the re-IPL target if the old one went away
In the final step of the udev rules toolset, we either know that the
current event subject is the re-IPL target, a dm-multipath device with
the re-IPL target, or represents the same volume based on its WWID. As
such it is a candidate to replace the current re-IPL target.

The new helper `chreipl-fcp-mpath-try-change-ipl-path` will use the
subject itself - in case it is a single scsi disk -, or the dm-multipath
device, to test whether there is a path in a good state.

"Good state" is based on the zfcp device driver state
(<SDEV>/zfcp_failed, <SDEV>/zfcp_in_recovery), the scsi_transport_fc
port state (<SDEV>/../../fc_remote_ports/rport-*/port_state), and the
scsi device state (<SDEV>/state). A path is only considered if they all
indicate a device in good conditions.

If such a path is found, the helper will try to set it as new re-IPL
target regardless of whether the current re-IPL is still in good shape
or not. This is by design, and done to reduce complexity in further
state checking, and prevention of races with overlapping events in udev
(when executing in parallel workers).

Whenever a new re-IPL target is selected and set in
/sys/firmware/reipl/fcp/{device,wwpn,lun}, the helper will also update
the records in the ID-file - otherwise they might appear as stale, when
they aren't.

This step in the udev rule processing might also result in log messages
written to the syslog (using the utility `logger` from util-linux;
writing to /dev/log).

In case the re-IPL target is changed, a message with level notice is
logged, informing about the new target.

In case no good path is found as part of a dm-multipath device, a
message with level critical is logged, as it might result in a failed
re-IPL if no path is available.

Lastly, when changing the information in /sys/firmware/reipl/fcp/ fails
for whatever reason, a message with level alert is logged, as the
written information might be inconsistent and must be audited/corrected
manually by an operator.

Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Benjamin Block
2a29a28f78 chreipl-fcp-mpath: if event subject is not re-IPL target, test if WWID matches
When the first test, whether the current event subject represents the
re-IPL target failed, we attempt a second test, using the recorded WWID
of a previously successful attempt.

The new helper `chreipl-fcp-mpath-is-ipl-vol` utilizes the information
previously stored in the ID-file (read under lock via `flock`).

The recorded WWID is compared with the one of the event subject; if it
matches we know that it addresses the same volume, and might be used as
alternative re-IPL target.

Additionally we also compare the current re-IPL triplet with the one
recorded in the ID-file. If it doesn't match anymore, we assume the
recorded WWID is stale - e.g., because the operator changed the re-IPL
target manually - and the previous check invalid.

If both the WWID match, and the re-IPL triplet is still the same as
previously recorded, the toolset may continue with the subject, and use
it as replacement for the current re-IPL target.

Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Benjamin Block
cb831aea44 dbginfo.sh: collect config- and debug-data for chreipl-fcp-mpath
When built with `D=1` chreipl-fcp-mpath automatically creates debug data
for the helpers that run during udev event processing. This is the only
way to effectively debug what is happening during event processing in
chreipl-fcp-mpath.

Collect this data under its default path in /run/udev/.

Also collect the chreipl-fcp-mpath statefile which contains WWID, Device
Bus-ID and LUN of the last path that was detected to represent a FCP
re-IPL device.

Suggested-by: Steffen Maier <maier@linux.ibm.com>
Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Benjamin Block
04be704083 chreipl-fcp-mpath: record the event subject WWID if it repr. the tgt
When we have identified the current event subject to represent the
re-IPL target, we record its WWID for future identification in a
stateful ID-file (per default: /run/udev/chreiplzfcpmp-ipl-volume-id). In
addition to the WWID, we also record the current re-IPL triplet
(<Dev-Bus-ID>:<WWPN>:<LUN>), so that when that changes - e.g. due to an
operator manually changing the re-IPL target -, we know that the
recorded WWID is stale.

This record may be used in cases when the current re-IPL target is
completely gone from the system, so we can't used it as comparison
object for when events arrive for paths that go to the same volume, but
don't have the same I_T_L nexus. They however have the same WWID. We
may use these (new) paths as replacement for the one that is completely
gone.

The new helper `chreipl-fcp-mpath-record-volume-identifier` uses the
kernel scsi-device attribute `wwid` as source for the WWID (verbatim).

As with reading the re-IPL firmware information, when writing to the
ID-file, a lock is taken via `flock`, to prevent overlapping
writes/reads to the file.

Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Benjamin Block
1bcfcd3253 chreipl-fcp-mpath: test if event subject represents re-IPL target
Now that we know that the system uses s390x IPL and the current re-IPL
target is from FCP, whenever we get a udev event that indicates a path
state changed, we have to figure out whether it affects the path that is
currently set as re-IPL target, or goes to the same volume (so we might
use it as alternative re-IPL path).

Add a new helper `chreipl-fcp-mpath-is-ipl-tgt` for this task.

Based on the information provided in
/sys/firmware/reipl/fcp/{device,wwpn,lun} it figures out whether the
current event subject has the same triplet <Dev-Bus-ID>:<WWPN>:<LUN> (in
T10 SCSI: I_T_L nexus), or whether one of its parts (in case of
dm-multipath) has.

If true, we know for sure, that we deal with an event affecting the
current re-IPL setting, and continue.

When accessing the re-IPL firmware information a lock is taken via the
`flock` utility (from util-linux). This is done so concurrent changes
from the toolset, that are added in a later commit, don't result in
inconsistent reads.

Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Benjamin Block
2dbaf9f991 chreipl-fcp-mpath: test if the system uses s390x IPL and re-IPL is from FCP
Add second filter stage to the udev rules: only continue with the
toolset, if the system uses s390x IPL and if the current re-IPL target
is from FCP.

For the test, whether the next re-IPL target is planned to be done from
FCP, a helper `chreipl-fcp-mpath-is-reipl-zfcp` is added, and the
information in /sys/firmware/reipl/reipl_type is used.

If either one or both of the tests are not true, the udev rules will
exit.

For debugging, the toolset can be built with the Make variable `D` set
to 1 (e.g.: make D=1; make install D=1). This causes the toolset to
write shell traces of the helper to $(DEBUGOUTDIR) (per default:
/run/udev); otherwise no output is generated. `dbginfo.sh` will be
changed to collect this data automatically.

Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Benjamin Block
2ea20094d0 chreipl-fcp-mpath: toolset skeleton with initial set of udev rules
Add a new tool to s390-tools: chreipl-fcp-mpath. A toolset based on udev
to change the active re-IPL target if the current target goes into an
error-state, due to for example a pulled cable.

Add the base infrastructure consisting of a Makefile and a base set of
udev rules. Integrate the Makefile into s390-tools Make machinery.

The rules filter events base on the event subject type (dm-multipath,
scsi disk), udev action (change, or add), and device mapper action
(path failure, or path reinstated). No further processing is done right
now in case of a match; if neither of these criteria matches, the
rules exit, and the toolset won't be invoked.

Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Joern Siglen
a80c14d72c dbginfo.sh: addtional timeout and omitting a report
running mpio data disks with offline paths might cause dbginfo
to hang up on the command "blockdev --report" -> we remove
it to ensure a non blocking data collection.
In addition we add a second kill step with the same timeout
value to retry stopping a command

Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Thomas Huth
10518da618 zipl/boot: Always clear COMMAND_LINE_EXTRA region
Always clear the COMMAND_LINE_EXTRA region, also in case sclp_setup()
fails. If the region is not cleared properly, there might be junk
in there after a reboot, causing confusion for the kernel later.

While we're at it, also switch to COMMAND_LINE_EXTRA_SIZE instead
of COMMAND_LINE_SIZE, since that constant is more appropriate here.

Closes: https://github.com/ibm-s390-linux/s390-tools/pull/122
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Marc Hartmayer
e9d1e168b2 zdump: rename ZG_ACTION_STDOUT to ZG_ACTION_COPY
With an upcoming patch the output target can be different to `stdout`.
Therefore, the term `ZG_ACTION_STDOUT` is no longer generic enough. In addition,
rename `do_write` to `do_copy` to match the enum name.

Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Marc Hartmayer
7567506cca zdump: stdout_write_dump: replace magic value
Replace magic value with something easier to read.

Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Marc Hartmayer
524017ac06 zdump: stdout_write_dump: if dfo_size() == 0 then don't enter the loop
While at it, decrease the scope of @cnt and @rc.

Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Marc Hartmayer
15774dbe32 zdump: stdout_write_dump: replace dfo_size() calls
Read the `dfo_size()` value only once and then reuse it.

Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Marc Hartmayer
f247850ff0 zdump: only mount command uses the optional arguments
Currently, for some commands (e.g. `zgetdump unmount`) unused positional
arguments are silently ignored, for some commands (`zgetdump mount`) they're
not. Therefore let's fix this by always returning an error message and exit code
if too many positional arguments are given.

Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Alexandra Winter
800ef7cb13 hsci: Compatibility with old hsci tool
In case the hsci tool was upgraded on a running system, it can happen
that an hsci interface exists, that was created by an older version of
the tool (and thus has no veth pair). Add support to show and delete
such an hsci interface.

Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
Reviewed-by: Wenjia Zhang <wenjia@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Alexandra Winter
48cf3b3809 hsci: Compatibility with old kernel
Without kernel commits
f7936b7b2663 s390/qeth: Update MACs of LEARNING_SYNC device
4e20e73e631a s390/qeth: Switchdev event handler
60bb1089467d s390/qeth: Register switchdev event handler
HSCI cannot be used with multiple MACs, but the single MAC usecase needs
to be supported even with old kernel. So manually setting the same single
MAC on hsci, HiperSockets and the external interface is still required.
The hsci itself is not a bridgeport, so a static forwarding rule in the
bridge is also required. It seems cleaner to use the initial MAC of the
veth hsci as single static MAC, than the initial MAC of the HiperSockets
interface.

Even with an updated kernel a single static MAC interface, that is not
subject to ageing and re-learning, is beneficial when hsci is used as
a single MAC interface.

Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
Reviewed-by: Wenjia Zhang <wenjia@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Alexandra Winter
99c8c27302 hsci: Support multiple MAC addresses
The first implementation of HSCI (HiperSockets Converged Interface)
supports only a single static MAC address per HSCI and thus constructs
like MACVTAP or OpenVSwitch cannot be used on top of it.

Kernel commits
f7936b7b2663 s390/qeth: Update MACs of LEARNING_SYNC device
4e20e73e631a s390/qeth: Switchdev event handler
60bb1089467d s390/qeth: Register switchdev event handler
changed the behaviour of a LEARNING_SYNC HiperSockets (HS) device
such that any MAC address that is added or learned on a non-isolated
bridgeport of the HSCI bridge is set on the LEARNING_SYNC HS device and
its isolated siblings.

So no new trigger is required for a HS device with the bridge attribute
LEARNING_SYNC to support multiple MACs on a northbound HSCI interface.
However the first implementation of the hsci tool uses the bridge itself
as northbound HSCI interface. This is not treated as a real bridgeport.
So we add a veth bridgeport as northern link for HSCI.

Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
Reviewed-by: Wenjia Zhang <wenjia@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Alexandra Winter
a5c3af1361 hsci: Idempotency and cleanup
Instead of checking for ideal starting conditions, try to achieve
the desired outcome and accept conditions that do not prevent it.

This allows the user to get to a defined state, even if the
hsci interface was manipulated by other means than the hsci tool,
e.g. by ip commands or bridge commands

Minor cleanup:
hsci show:
	- display PNET_ID, even if only one hsci port has one
	  (e.g. if External is a bond)
	- only 1 header for mulitple hscis
hsci add:
	- sanitize error messages
	- allow nonsense HSCI of 2 HiperSockets

Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
Reviewed-by: Wenjia Zhang <wenjia@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Alexander Egorenkov
353c23a157 zdump: Include dfi_mem_chunk.h only if required
Don't include dfi_mem_chunk.h in dfi.h because not every module including
dfi.h needs it.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Alexander Egorenkov
d371ba0db8 zdump: Cleanup zgetdump.h C header
Separate the definition of a struct from the declaration of a global
variable of the type. To improve readability.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Alexander Egorenkov
8308143008 zdump/stdout: Extract stdout.h header from zgetdump.h
Create a separate C header for STDOUT to separate independent things and
make it more readable.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Alexander Egorenkov
d8871197ea zdump/opts: Make command-line argument parsing independent of DFO
Set DFO format after the parsing of command-line arguments is done.
The command-line argument parsing should be independent of DFO.
This improves testability of the command-line argument parsing and
separates independent things from each other.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Alexander Egorenkov
df338a3bac zdump/opts: Make parsing of command line arguments testable
Make the C module responsible for the parsing of command-line arguments
independent of other global variables. This improves its testability.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Alexander Egorenkov
1005e7be7e zdump: Don't use god-like C headers
Get rid of C headers which include everything. This is bad for testing and
maintainability. C files should include only what they need and no more.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Alexander Egorenkov
afb14cba7a zdump/zfuse: Extract zfuse.h header from zgetdump.h
Create a separate C header for FUSE to separate independent things and
make it more readable.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 15:12:10 +01:00
Alexander Egorenkov
1e450e6f7b zdump/dt: Move declaration of DT structs to dt.h
Move DT structs to the header where they belong to.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 14:59:57 +01:00
Alexander Egorenkov
696a007b62 zdump/dfi: Move declaration of DFI structs to dfi.h
Move DFI structs to the header where they belong to.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 14:59:57 +01:00
Alexander Egorenkov
ea5f3f4a1c zdump/dfo: Move declaration of DFO structs to dfo.h
Move DFO structs to the header where they belong to.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 14:59:57 +01:00
Alexander Egorenkov
6afd5e97d1 zdump/dfi: Extract dfi_vmcoreinfo.h header from dfi.h
Create a separate C header for DFI VMCOREINFO to separate
independent things and make it more readable.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 14:59:57 +01:00
Alexander Egorenkov
b1da8bbbe9 zdump/dfi: Introduce symbolic constants for OLDMEM base and size
Replace magic values with descriptive names to improve readability.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 14:59:57 +01:00
Alexander Egorenkov
6ece595532 zdump/dfi_mem_chunk: Validate parameters passed to dfi_mem_phys_read()
To prevent segmentation faults when the function dfi_mem_phys_read() is
given invalid parameters, check that the given memory range falls within
a known physical memory chunk, just like it is done for dfi_mem_virt_read().

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 14:59:57 +01:00
Alexander Egorenkov
40d4aa38e9 zdump/dfi_mem_chunk: Rename dfi_mem_read_rc() to dfi_mem_virt_read()
The new name describes the purpose of the function better and
emphasizes its difference with the function dfi_mem_phys_read().

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 14:59:57 +01:00
Alexander Egorenkov
c58cfd1ec1 zdump/dfi_mem_chunk: Replace dfi_mem_read() with dfi_mem_read_rc()
Always use the function dfi_mem_read_rc() which verifies that the given
address and size fall within a valid memory chunk. We cannot trust
user's input.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 14:59:57 +01:00
Alexander Egorenkov
02086f26d2 zdump/dfi_mem_chunk: Don't expose private function dfi_mem_chunk_virt_add()
The function dfi_mem_chunk_virt_add() is used only internally and should
not be exported to prevent misuse.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 14:59:57 +01:00
Alexander Egorenkov
7a2666d727 zdump/dfi: Remove redundant extern from function declarations in headers
The keyword extern is redundant for function declarations in C headers.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 14:11:29 +01:00
Alexander Egorenkov
2df532c1fa zdump: Extract dfi_mem_chunk module
To make dfi_mem_chunk API unit testable.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 11:50:58 +01:00
Eduard Shishkin
969a439aaa zipl: check add_envblk predicate when setting stage3_parms
Set stage3_parms.envblk_len to 0, if add_envblk is false.
This fixes segmentation fault when performing job with
not defined zIPL environment (e.g. installing SCSI dump)

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Tested-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 11:50:58 +01:00
Fedor Loshakov
f8331a4b8e ziomon: correct throughput calculation in ziorep_printers.cpp
During evaluation of the collected ziomon data from the system with following
multipath configuration:

$ multipath -ll
3600507630bffc3200000000000005294 dm-0 IBM,2107900
size=20G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
`-+- policy='service-time 0' prio=50 status=active
  |- 1:0:0:1083457618 sdd 8:48  active ready running
  `- 0:0:0:1083457618 sda 8:0   active ready running
3600507630bffc3200000000000005394 dm-1 IBM,2107900
size=20G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
`-+- policy='service-time 0' prio=50 status=active
  |- 1:0:0:1083457619 sdf 8:80  active ready running
  `- 0:0:0:1083457619 sdb 8:16  active ready running
3600507630bffc3200000000000005494 dm-2 IBM,2107900
size=20G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
`-+- policy='service-time 0' prio=50 status=active
  |- 1:0:0:1083457620 sdg 8:96  active ready running
  `- 0:0:0:1083457620 sdc 8:32  active ready running
3600507630bffc3200000000000005594 dm-3 IBM,2107900
size=20G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
`-+- policy='service-time 0' prio=50 status=active
  |- 1:0:0:1083457621 sdh 8:112 active ready running
  `- 0:0:0:1083457621 sde 8:64  active ready running

there were low throughput values for adapter noticed in ziorep_utilization
virtual adapter report:

$ ziorep_utilization adp_line_speed.log
...
CHP Bus-ID  |qdio util.%|queu|fail|-thp in MB/s-|I/O reqs-|
 ID            max   avg full  erc     rd    wrt   rd  wrt
2021-08-18 12:56:44
 61/0.0.1946  32.8   3.1    0    0   0.0   84.5    21 204K
12:57:04
...

there were also low values for throughput of devices noticed in
ziorep_traffic report. And were no aggregation of throughput for
different aggregation parameters provided:

$ ziorep_traffic adp_line_speed.log -i 0
       WWPN                LUN       |I/O rt MB/s|thrp in MB/s-|...
                                        min   max    avg  stdev ...
2021-08-18 12:58:24
0x500507630b09c320:0x4052409400000000   0.0 219.2  85.7  3.352K ...
0x500507630b09c320:0x4053409400000000   0.0 348.6  84.6  3.330K ...
0x500507630b09c320:0x4054409400000000   0.0 268.6  84.0  3.317K ...
0x500507630b09c320:0x4055409400000000   0.0 354.2  83.7  3.312K ...

$ ziorep_traffic adp_line_speed.log -i 0 -Cu
 Bus-ID |I/O rt MB/s|thrp in MB/s-|...
           min   max    avg  stdev ...
2021-08-18 12:58:24
0.0.1946   0.0 354.2  84.5  3.328K ...

although, iostat tool showed decent throughput values for each scsi disk, which
belongs to investigated zfcp adapter. In this example each scsi disk has
throughput more than 300MB/s, which is much larger, than 84.5MB/s
throughput for the adapter:

$ iostat -x 1
...
Device            r/s     w/s     rkB/s     wkB/s ...
dasda            0.00    0.00      0.00      0.00 ...
dasdb            0.00    0.00      0.00      0.00 ...
sda              0.00 2556.00      0.00 327168.00 ...
sdc              0.00 2554.00      0.00 326912.00 ...
sdb              0.00 2559.00      0.00 327552.00 ...
sdf              0.00 2865.00      0.00 366720.00 ...
sdd              0.00 2843.00      0.00 363904.00 ...
sdg              0.00 2845.00      0.00 364160.00 ...
sde              0.00 2471.00      0.00 315416.00 ...
sdh              0.00 2768.00      0.00 353768.00 ...
dm-0             0.00 5399.00      0.00 691072.00 ...
dm-1             0.00 5424.00      0.00 694272.00 ...
dm-2             0.00 5400.00      0.00 691200.00 ...
dm-3             0.00 5240.00      0.00 669312.00 ...

Use Frameset interval size for calculation of throughput of zfcp adapter
instead of d2c (dispatch to complete) time of request, which is used for I/O
rate calculation. Also use Frameset interval instead of total_latency.sum
(which in fact is a sum of d2c times for each repuest in specifed interval).
Use calc_avg() function for throughput calculation.

With fix applied, virtual adapter report now contains correct value for adpater
throughput for specified interval:

$ ziorep_utilization adp_line_speed.log
...
CHP Bus-ID  |qdio util.%|queu|fail|-thp in MB/s-|I/O reqs-|
 ID            max   avg full  erc     rd    wrt   rd  wrt
2021-08-18 12:56:44
 61/0.0.1946  32.8   3.1    0    0   0.0  1.336K   21 204K
...

With fix applied, traffic report now contains correct values of
throughput for each device and aggregation now works correctly:

$ ziorep_traffic adp_line_speed.log -i 0
       WWPN                LUN       |I/O rt MB/s|thrp in MB/s-|...
                                        min   max    avg  stdev ...
2021-08-18 12:58:24
0x500507630b09c320:0x4052409400000000   0.0 219.2 339.6  3.352K ...
0x500507630b09c320:0x4053409400000000   0.0 348.6 335.4  3.330K ...
0x500507630b09c320:0x4054409400000000   0.0 268.6 333.1  3.317K ...
0x500507630b09c320:0x4055409400000000   0.0 354.2 331.9  3.312K ...

$ ziorep_traffic adp_line_speed.log -i 0 -Cu
 Bus-ID |I/O rt MB/s|thrp in MB/s-|...
           min   max    avg  stdev ...
2021-08-18 12:58:24
0.0.1946   0.0 354.2 1.340K 3.328K ...

Signed-off-by: Fedor Loshakov <loshakov@linux.ibm.com>
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 11:50:58 +01:00
Jan Höppner
895dc80580 Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 17:45:29 +02:00
Jan Höppner
d93645d690 New release s390-tools-2.18.0
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 17:45:29 +02:00
Jan Höppner
c3bb6307b8 gitignore: Add zdev_id and zipl-editenv
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 15:44:16 +02:00
Steffen Maier
6208c0626a dbginfo.sh: collect udev rules from DPM device auto-configuration
Complements v2.5.0 commit fe68ec513d
("zdev: Add support for handling auto-configuration data").

Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:59:56 +02:00
Peter Oberparleiter
3949c62f6f zdev: Add auto-config for PCI and crypto devices
PCI and crypto devices defined using the IBM Z Dynamic Partition Manager
(DPM) will start in an offline/unconfigured state that requires manual
intervention before the associated Linux function can be used. This
results for example in PCI networking interfaces being unavailable in a
distribution installer system.

Fix this by providing a udev rule and initial RAM-disk logic that
automatically enables PCI and crypto devices either during boot, or when
they are defined at run-time. This processing can be suppressed by
specifying the "rd.zdev=no-auto" parameter on the kernel command line.

Auto-configuration is limited to Linux running in DPM LPARs because
PCI-functions and crypto devices defined by DPM are always intended for
use by a single LPAR only.

For Linux running in classic-mode LPARs or virtual machines, leaving PCI
and crypto devices in an offline state may be useful to allow defining a
device as available to multiple systems, where only the system that
intends to make use of the device should enable it.

Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:59:56 +02:00
Peter Oberparleiter
8c6c2ef30e zdev: Add udev rule helper tool
Add an internal tool intended to be used by udev rules to determine
zdev and hypervisor related system information in key=value format.

Supported keys are:

  ZDEV_NEST_LEVEL=n
    Virtualization nesting level of running system

  ZDEV_HYPERVISOR_<n>=LPAR|z/VM|KVM/Linux
    Type of hypervisor that provides virtualization at nesting level <n>

  ZDEV_IS_DPM=0|1
    Indicator if top-level LPAR is managed by Dynamic Partition Manager

  ZDEV_NO_AUTO=0|1
    Indicator if auto-configuration is requested

Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:59:56 +02:00
Joern Siglen
12c84469fd dbginfo.sh: exclude reading page_idle/bitmap sysfs attribute
Due to issues with reading the /sys/kernel/mm/page_idle/bitmap sysfs
attribute that can lead to a system hang, reading this particular
attribute is excluded.

Link: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1904884
Reviewed-by: Mario Held <mario.held@linux.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:59:56 +02:00
Marc Hartmayer
0a8e726d05 zgetdump: return -EINVAL for user space core dumps
zgetdump is for analyzing VM coredumps and not user space coredumps therefore
return an error in case of a user space coredump.

Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:59:56 +02:00
Peter Oberparleiter
533df585fd scripts: Add tool for parsing sclp s390dbf logs
Add new tool named 'sclpdbf'. This script displays the contents of
s390dbf sclp debug logs in human-readable format.

Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:59:56 +02:00
Eduard Shishkin
c4eb2d5fba zipl-editenv: added a manpage for the new zipl-editenv tool
update manpages of zipl(8), zipl.conf(5) w/ zipl environment stuff

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:59:56 +02:00
Eduard Shishkin
35029ad010 zipl: add environment editor
Added a tool to operate with zIPL environment, currently
installed in the boot record. All modifying operations result
in atomic update of the installed environment block, bypassing
the file system driver.

Operations currently supported by zIPL environment editor:
. set/unset environment variables,
. print/reset environment

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:59:56 +02:00
Eduard Shishkin
296079f70a zipl: move logical-to-physical block mapping logic
from disk.c to a dedicated source file fs-map.c, so that the new
zipl-editenv tool will be also able to use it.

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:59:56 +02:00
Eduard Shishkin
4f1c73d592 zipl: add environment interpretation by stage3 of boot
Before starting the kernel:

1. parse environment block (if any) and create a hash table
   of all found pairs (NAME, VALUE);
2. scan the command line, which already contains extra-parameters
   (if any), and for each found ${NAME} replace it with VALUE, as
   found in the hash table by NAME.

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:59:56 +02:00
Eduard Shishkin
1fb859729e zipl: add basic support of environment block by zipl(8)
When installing a boot record for "ipl" and "menu" job, always add
an environment block as a boot component located in bootmap file
at offset alinged on file system block size boundary. When adding,
first try to import environment from a file at location specified
by newly introduced "--environment" zipl option, or by default at
"/etc/ziplenv". If nothing was imported, then add a blank environment
block. Optionally print the content of the environment block.

Store environment block size and address (as of boot component) in
stage3_parms.

Change interface of add_ipl_program(): add 2 additional arguments:
a pointer to bootmap file name and a predicate indicating if we
need to add environment block as a boot component.

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:59:56 +02:00
Eduard Shishkin
bbeb0f8445 zipl: expand interface of disk_write_block_aligned_base()
Provide helper functions disk_write_block_buffer_align()
and add_component_buffer_align() to align offset of the record
on specified block size boundary and to save the offset, where
the record was made at.

This will be used by a later patch.

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:59:56 +02:00
Eduard Shishkin
2ae44cb794 zipl: expand interface of disk_get_blocklist_from_file
. expand interface of disk_get_blocklist_from_file() to get
  block pointers for a specific range of data within a file.
. provide a helper function add_component_file_range() to add a
  specific range of data within a file as a boot component.

This will be used by a later patch.

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:59:56 +02:00
Marc Hartmayer
a0b8033088 zdump: dfi_mem_range_valid: check that unsigned int operation don't wrap
Validate that the addition of the parameters @addr and @len given to
`dfi_mem_range_valid()` does not overflow 64bit unsigned integer type.

This fixes the following segmentation fault:

[#0] 0x2aa000084fc → mem_read(mem=0x2aa00021b68 <l+152>, addr=0xffffffffffffffff, buf=0x3ffffffec64, cnt=0xc)
[#1] 0x2aa00009964 → dfi_mem_read(addr=0xfffffffffffffffa, buf=0x3ffffffec64, cnt=0xc)
[#2] 0x2aa00009c86 → dfi_mem_read_rc(addr=0xfffffffffffffffa, buf=0x3ffffffec64, cnt=0xc)
[#3] 0x2aa0000ba42 → dfi_vmcoreinfo_init()
[#4] 0x2aa0000b496 → dfi_init()
[#5] 0x2aa00005aa6 → do_dump_info()
[#6] 0x2aa00005c82 → main(argc=<optimized out>, argv=0x3fffffff118)

Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:59:56 +02:00
Marc Hartmayer
9cc74839b0 zgetdump: initalize sigact to 0
This fixes the following Valgrind finding:

==28040== Syscall param rt_sigaction(act->sa_flags) points to uninitialised byte(s)
==28040==    at 0x48C98B0: __libc_sigaction (sigaction.c:58)
==28040==    by 0x10D507: sig_handler_init (zgetdump.c:58)
==28040==    by 0x10D507: main (zgetdump.c:179)
==28040==  Address 0x1ffefffc84 is on thread 1's stack
==28040==  in frame #0, created by __libc_sigaction (sigaction.c:43)

Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:59:56 +02:00
Marc Hartmayer
b7b7002855 gitignore: Ignore coverage data
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:59:56 +02:00
Peter Oberparleiter
55e428a4d7 dump2tar: Fix (null) output on help text
Fix the following incorrect help text line:

 -T, --file-timeout (null)  Stop reading file after SEC seconds

Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:59:56 +02:00
Alexander Egorenkov
cb09223a56 zdump/dfi_elf: Fix stack buffer overflow in nt_read()
Sanity check ELF notes descriptor size before reading it. This prevents
stack buffer overflows in case a dump contains invalid ELF notes.
Instead of reading a note's descriptor into a temporary buffer on stack,
read it directly into the buffer given to nt_read() but also provide
a maximum length of the given buffer to nt_read() in order to prevent
overflows.

This problem was found with valgrind and AFL fuzzing + ASAN.

AFL +  ASAN findings:

[root@t83lp49 s390-tools]# ./zdump/zgetdump -iVVVVV ~/zgetdump-fuzzing/findings/crashes/id\:000008\,sig\:06\,src\:000007\,op\:arith8\,pos\:67\,val\:+3
TRACE: DFI initialization
DEBUG: DFI trying s390tape
DEBUG: DFI s390tape returned with rc -19
DEBUG: DFI trying devmem
DEBUG: DFI devmem returned with rc -19
DEBUG: DFI trying s390mv_ext
DEBUG: DFI s390mv_ext returned with rc -19
DEBUG: DFI trying s390mv
DEBUG: DFI s390mv returned with rc -19
DEBUG: DFI trying s390_ext
DEBUG: DFI S390 extended initialization
DEBUG: DFI s390_ext returned with rc -19
DEBUG: DFI trying s390
DEBUG: DFI S390 initialization
DEBUG: DFI s390 returned with rc -19
DEBUG: DFI trying lkcd
DEBUG: DFI lkcd returned with rc -19
DEBUG: DFI trying elf
DEBUG: DFI ELF initialization
DEBUG: DFI ELF e_phnum 11
DEBUG: DFI ELF p_type[0] 0x4
DEBUG: DFI ELF n_type 0x0
AddressSanitizer:DEADLYSIGNAL
=================================================================
==208548==ERROR: AddressSanitizer: stack-overflow on address 0x03ffef05d000 (pc 0x0000010051b0 bp 0x03fff107dc40 sp 0x03ffef05dac8 T0)
    #0 0x10051b0  (/root/s390-tools/zdump/zgetdump+0x10051b0)

SUMMARY: AddressSanitizer: stack-overflow (/root/s390-tools/zdump/zgetdump+0x10051b0)
==208548==ABORTING

valgrind findings:

	==56423== Source and destination overlap in memcpy(0x4a86d38, 0x4a875e0, 4096)
	==56423==    at 0x4839F86: memcpy (in /usr/lib/s390x-linux-gnu/valgrind/vgpreload_memcheck-s390x-linux.so)
	==56423==    by 0x114253: memcpy (string_fortified.h:34)
	==56423==    by 0x114253: nt_read (dfi_elf.c:95)
	==56423==    by 0x1145FF: nt_s390_prefix_read (dfi_elf.c:195)
	==56423==    by 0x1145FF: pt_notes_add (dfi_elf.c:259)
	==56423==    by 0x1145FF: dfi_elf_init (dfi_elf.c:326)
	==56423==    by 0x112A57: dfi_init (dfi.c:1212)
	==56423==    by 0x10D663: do_dump_info (zgetdump.c:127)
	==56423==    by 0x10D663: main (zgetdump.c:182)
	==56423==
	==56423== Invalid write of size 8
	==56423==    at 0x4839E28: memcpy (in /usr/lib/s390x-linux-gnu/valgrind/vgpreload_memcheck-s390x-linux.so)
	==56423==    by 0x114253: memcpy (string_fortified.h:34)
	==56423==    by 0x114253: nt_read (dfi_elf.c:95)
	==56423==    by 0x1145FF: nt_s390_prefix_read (dfi_elf.c:195)
	==56423==    by 0x1145FF: pt_notes_add (dfi_elf.c:259)
	==56423==    by 0x1145FF: dfi_elf_init (dfi_elf.c:326)
	==56423==    by 0x112A57: dfi_init (dfi.c:1212)
	==56423==    by 0x10D663: do_dump_info (zgetdump.c:127)
	==56423==    by 0x10D663: main (zgetdump.c:182)
	==56423==  Address 0x4a86ee0 is 0 bytes after a block of size 912 alloc'd
	==56423==    at 0x483675E: calloc (in /usr/lib/s390x-linux-gnu/valgrind/vgpreload_memcheck-s390x-linux.so)
	==56423==    by 0x10E71D: zg_alloc (zg.c:93)
	==56423==    by 0x114793: nt_prstatus_read (dfi_elf.c:123)
	==56423==    by 0x114793: pt_notes_add (dfi_elf.c:234)
	==56423==    by 0x114793: dfi_elf_init (dfi_elf.c:326)
	==56423==    by 0x112A57: dfi_init (dfi.c:1212)
	==56423==    by 0x10D663: do_dump_info (zgetdump.c:127)
	==56423==    by 0x10D663: main (zgetdump.c:182)

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Suggested-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reported-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:59:56 +02:00
Alexander Egorenkov
28db3523d0 zdump/dfi: Fix illegal memory access in mem_chunk_has_addr()
Verify that the mem chunk_cache pointer is valid before using it.
This prevents potential illegal memory accesses.

This problem was found with AFL fuzzing and ASAN.

./zdump/zgetdump -iVVVVV ~/zgetdump-fuzzing/findings/crashes/id\:000007\,sig\:06\,src\:000007\,op\:flip1\,pos\:37
TRACE: DFI initialization
DEBUG: DFI trying s390tape
DEBUG: DFI s390tape returned with rc -19
DEBUG: DFI trying devmem
DEBUG: DFI devmem returned with rc -19
DEBUG: DFI trying s390mv_ext
DEBUG: DFI s390mv_ext returned with rc -19
DEBUG: DFI trying s390mv
DEBUG: DFI s390mv returned with rc -19
DEBUG: DFI trying s390_ext
DEBUG: DFI S390 extended initialization
DEBUG: DFI s390_ext returned with rc -19
DEBUG: DFI trying s390
DEBUG: DFI S390 initialization
DEBUG: DFI s390 returned with rc -19
DEBUG: DFI trying lkcd
DEBUG: DFI lkcd returned with rc -19
DEBUG: DFI trying elf
DEBUG: DFI ELF initialization
DEBUG: DFI ELF e_phnum 11
DEBUG: DFI ELF p_type[0] 0x6060606
DEBUG: DFI ELF p_type[1] 0x6060606
DEBUG: DFI ELF p_type[2] 0x6060606
DEBUG: DFI ELF p_type[3] 0x6060606
DEBUG: DFI ELF p_type[4] 0x6060606
DEBUG: DFI ELF p_type[5] 0x6060606
DEBUG: DFI ELF p_type[6] 0x6060606
DEBUG: DFI ELF p_type[7] 0x6060606
DEBUG: DFI ELF p_type[8] 0x6060606
DEBUG: DFI ELF p_type[9] 0x6060606
DEBUG: DFI ELF p_type[10] 0x6060606
TRACE: DFI kdump initialization
AddressSanitizer:DEADLYSIGNAL
=================================================================
==206692==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x000001016a12 bp 0x03ffcc57eae0 sp 0x03ffcc57eae0 T0)
==206692==The signal is caused by a UNKNOWN memory access.
==206692==Hint: address points to the zero page.
    #0 0x1016a12 in mem_chunk_has_addr /root/s390-tools/zdump/dfi.c:308
    #1 0x1016a12 in mem_chunk_find /root/s390-tools/zdump/dfi.c:318
    #2 0x1016a12 in dfi_mem_chunk_find /root/s390-tools/zdump/dfi.c:513
    #3 0x1016a12 in dfi_mem_range_valid /root/s390-tools/zdump/dfi.c:208
    #4 0x1016a12 in kdump_init /root/s390-tools/zdump/dfi.c:1100
    #5 0x1016a12 in dfi_init /root/s390-tools/zdump/dfi.c:1253
    #6 0x1006d3d in do_dump_info /root/s390-tools/zdump/zgetdump.c:127
    #7 0x1006d3d in main /root/s390-tools/zdump/zgetdump.c:182
    #8 0x3ff9e0abe03 in __libc_start_main (/lib64/libc.so.6+0x2be03)
    #9 0x1007d7d  (/root/s390-tools/zdump/zgetdump+0x1007d7d)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /root/s390-tools/zdump/dfi.c:308 in mem_chunk_has_addr
==206692==ABORTING

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:59:56 +02:00
Alexander Egorenkov
f15e32cdb1 zdump/dfi: Fix illegal memory access in dfi_cpu_add_from_lc()
Check that a CPU's lowcore address falls within a valid memory region
before accessing it. This prevents potential illegal memory accesses
in case a dump contains invalid CPU lowcore addresses.

This bug was found with AFL fuzzing and ASAN.

Starting program: /root/s390-tools/zdump/zgetdump -iVVVVV /root/zgetdump-fuzzing/findings/crashes/id:000004,sig:06,src:000005,op:flip32,pos:3055
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
TRACE: DFI initialization
DEBUG: DFI trying s390tape
DEBUG: DFI s390tape returned with rc -19
DEBUG: DFI trying devmem
DEBUG: DFI devmem returned with rc -19
DEBUG: DFI trying s390mv_ext
DEBUG: DFI s390mv_ext returned with rc -19
DEBUG: DFI trying s390mv
DEBUG: DFI s390mv returned with rc -19
DEBUG: DFI trying s390_ext
DEBUG: DFI S390 extended initialization
DEBUG: DFI s390_ext returned with rc -19
DEBUG: DFI trying s390
DEBUG: DFI S390 initialization
 INFO: DFI S390 version 5
DEBUG: DFI S390 mem_size 0x00000000000dbba0
DEBUG: DFI add vol mem chunk start 0x0000000000000000 size 0x00000000000dbba0 volnr 0

[snip]

TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000
TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000
TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000
TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000
TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000
TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000
TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000
TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000
TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000
TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000
TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000
TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000
TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000
TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000
TRACE: DFI virt mem read addr 0x00000000000000ff size 0x0000000000002000
TRACE: DFI virt mem read addr 0x00000000ffffff00 size 0x0000000000002000

Program received signal SIGSEGV, Segmentation fault.
0x000000000100fbb0 in mem_read (cnt=<optimized out>, buf=0x3ffffffc7d0, addr=4294967040, mem=0x104b218 <l+152>) at dfi.c:339
339                     size = MIN(cnt - copied, mem_chunk->end - addr + 1);
Missing separate debuginfos, use: dnf debuginfo-install fuse-libs-2.9.9-11.fc34.s390x glibc-2.33-20.1.ibm.fc34.s390x libasan-11.0.1-0.3.1.ibm.fc34.s390x libgcc-11.0.1-0.3.1.ibm.fc34.s390x libstdc++-11.0.1-0.3.1.ibm.fc34.s390x zlib-1.2.11-26.fc34.s390x
(gdb) bt

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:59:56 +02:00
Steffen Maier
094057e265 zfcpdbf: fix missing "FCP rsp IU all" fields if PAY record wrapped away
Had a confusing decoded trace record:

Timestamp      : ...
Area           : SCSI
...
Tag            : rsl_err
...
SCSI result    : 0x00000002
SCSI opcode    : 1a...
FCP rsp inf cod: 0x00
FCP rsp IU     : 00000000 00000000 00000a02 000000ff
                 00000012 00000000
                       ^^

and was wondering where that sense data would be or if the
corresponding PAY record "fcp_riu" was lost due to trace area wrapping.
So the fix here adds the following two lines to the same trace record:

FCP rsp IU len : 42
FCP rsp IU all : record not available anymore.

Similarly, the following LUN reset Task Management Function response
was missing the last two lines regarding the full FCP response IU
and its optional part with the FCP response info:

Timestamp      : ...
Area           : SCSI
...
Tag            : lr_okay
...
FCP rsp inf cod: 0x00
FCP rsp IU     : 00000000 00000000 00000100 00000000
                 00000000 00000008
                                ^^
FCP rsp IU len : 32
FCP rsp IU all : record not available anymore.

As of today, depending on the kernel version we have
either fcp_sns or fcp_riu PAY trace records. See Linux kernel v4.14 commit
12c3e5754c80 ("scsi: zfcp: fix payload with full FCP_RSP IU in SCSI trace
records").
Always print non-zero payload length independent of payload type.
Actually this also fixes a regression for wrapped away fcp_sns.
If there is no fcp_sns it either wrapped away or it's a kernel with fcp_riu.
Only print fcp_riu if it contains more content than the preceding
unconditional fixed-size field "FCP rsp IU".

Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Reviewed-by: Fedor Loshakov <loshakov@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:58:17 +02:00
Alexander Egorenkov
025a2198a4 zdump/dfi_s390: Fix use of uninitialized stack value in mem_chunks_add_ext()
If the while loop in mem_chunks_add_ext() is never executed, then
the stack variable containing the dump segment header will never be
initialized.

clang's static code analyzer reports the following problem:

$ make CC="clang --analyze" -C zdump

dfi_s390.c:157:6: warning: Branch condition evaluates to a garbage value [core.uninitialized.Branch]
        if (!dump_segm.stop_marker)
            ^~~~~~~~~~~~~~~~~~~~~~

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reported-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:53:14 +02:00
Alexander Egorenkov
2b938b78aa zdump: Introduce multi-level message logging
Use util_log from libutil to output various log messages that can be helpful
during problem analysis.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:53:14 +02:00
Alexander Egorenkov
de36fc5259 zdump/dfi: Fix format string specifiers in dfi_info_print()
Replace the incorrect %d format specifier with %u one for unsigned integer
types.

This issue was found with AFL fuzzing.

$ ./zdump/zgetdump -i ~/input.bin
General dump info:
  Dump format........: s390
  Version............: -2147483647
  System arch........: s390x (64 bit)
  CPU count (online).: 32768
  Dump memory range..: 1 MB

Memory map:
  0000000000000000 - 00000000000f423f (1 MB)

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:53:14 +02:00
Alexander Egorenkov
e3e5b6422a zdump/dfi_s390: Fix out-of-bounds array access in df_s390_cpu_info_add()
Verify that a s390 dump header contains a valid CPU count value.

This bug was found with an input file produced by AFL + ASAN.

$ ./zdump/zgetdump -i ~/input.bin
=================================================================
==3928488==ERROR: AddressSanitizer: global-buffer-overflow on address 0x000001043e90 at pc 0x000001025dca bp 0x03ffe96fe128 sp 0x03ffe96fe120
READ of size 4 at 0x000001043e90 thread T0
    #0 0x1025dc9 in df_s390_cpu_info_add /root/s390-tools/zdump/df_s390.c:57
    #1 0x101bb59 in dfi_s390_init_gen /root/s390-tools/zdump/dfi_s390.c:169
    #2 0x101bb59 in dfi_s390_init_gen /root/s390-tools/zdump/dfi_s390.c:156
    #3 0x1015d23 in dfi_init /root/s390-tools/zdump/dfi.c:1216
    #4 0x1006a0d in do_dump_info /root/s390-tools/zdump/zgetdump.c:127
    #5 0x1006a0d in main /root/s390-tools/zdump/zgetdump.c:182
    #6 0x3ffb93abe03 in __libc_start_main (/lib64/libc.so.6+0x2be03)
    #7 0x10077bd  (/root/s390-tools/zdump/zgetdump+0x10077bd)

0x000001043e91 is located 0 bytes to the right of global variable 'l' defined in 'dfi_s390.c:30:3' (0x1042e80) of size 4113
SUMMARY: AddressSanitizer: global-buffer-overflow /root/s390-tools/zdump/df_s390.c:57 in df_s390_cpu_info_add
Shadow bytes around the buggy address:
  0x10000000208780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000000208790: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100000002087a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100000002087b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100000002087c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x100000002087d0: 00 00[01]f9 f9 f9 f9 f9 00 00 00 00 00 00 00 00
  0x100000002087e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100000002087f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000000208800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000000208810: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000000208820: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==3928488==ABORTING

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:53:14 +02:00
Joern Siglen
38343be0fa dbginfo.sh: update the order of collection steps
We found situations, where the debug commands from dbginfo.sh
did overwrite some debug files (e.g. OSA s390dbf) - so we change
the collection order

Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:53:14 +02:00
Alexander Egorenkov
957e612720 zdump/dfi_vmcoreinfo: Fix illegal memory access in dfi_vmcoreinfo_init()
Before reading data in dfi_vmcoreinfo_init(), check the validity
of the memory range. Otherwise this can result in a segmentation fault when
zgetdump is given a very small dump, e.g. S390 DASD single-volume dump of
size 0x10 bytes.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:53:14 +02:00
Jan Höppner
1d2316caef zdump/dfi_vmcoreinfo: Fix potential illegal memory access in os_info_get()
Before reading data in os_info_get(), check the validity of the memory
range. Otherwise this can result in a segmentation fault when zgetdump is
given a very small dump, e.g. S390 DASD single-volume dump of size 0x10
bytes.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:53:13 +02:00
Alexander Egorenkov
64539853ca zdump/dfi: Fix potential illegal memory access in kdump_init()
Before reading data at addresses 0x10418 and 0x10420 in kdump_init(),
validate the validity of the memory range. Otherwise this can result in
a segmentation fault when zgetdump is given a very small dump, e.g.
S390 DASD single-volume dump of size 0x1000 bytes.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:53:13 +02:00
Alexander Egorenkov
686c331b69 zdump/dfi_vmcoreinfo: Sanity checks for n_namesz in ELF Notes header
The dfi_vmcoreinfo_init() function might be called on a dump of a non-ELF
format because the DFI goes through all supported dump formats when first
trying to identify of what dump format the given input is. Therefore,
we must be very careful in interpreting read data and ensure that it
makes sense before accessing or using it.

This commit prevents a potential overflow of a stack buffer in
dfi_vmcoreinfo_init() if note.n_namesz is bigger than the stack buffer.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:53:13 +02:00
Joern Siglen
01551f98d5 dbginfo.sh: code rework
- adding new print function for simpler output customizing
- consolidate some output files
- sync structures and use of checks
- some formatting updates

Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:53:13 +02:00
Alexander Egorenkov
0e2c5907e0 zdump/dfi_s390: Fix memory leaks in mem_chunks_add_ext()
The function mem_chunks_add_ext() allocates but does not release memory
if it encounters unexpected errors during dump segment reading.

Allocate memory passed to dfi_mem_chunk_add() right before calling
the function. This way there is no need for a cleanup anymore.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reported-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:53:13 +02:00
Joern Siglen
68ff79e4c3 dbginfo.sh: cleanup 2.x kernel & adding timeout
- clenaup outdated kernel - we no longer have 2.x kenrel in support
- add timeout on command excution - ensure to not miss all data for a
  single command to hang

Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-10-01 14:53:13 +02:00
Ingo Franzki
5b96d86538 zkey-cryptsetup: Support LUKS2 volumes with integrity support enabled
When integrity support is enabled for a LUKS2 volume, then the LUKS2
volume key may include the integrity key concatenated to the secure key
(dependent on the integrity type).

Get the integrity key size from the LUKS2 header (if integrity support
is enabled) and calculate the size of the secure key when performing
operations with the secure key only.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-09-30 17:21:32 +02:00
Alexander Egorenkov
4043137cd7 zdump: Fix handling of PT_LOAD segments with p_filesz < p_memsz in ELF DFI
According to the ELF specification, the file size of a PT_LOAD
memory segment might be less than its memory size. In that case,
the remaining bytes must be filled with zeros. The ELF DFI implementation
didn't handle this case correctly. Such ELF core files might be produced
by the makedumpfile tool.

From elf.5 man page:
------------------------------------------------------
PT_LOAD
       The array element specifies a loadable segment,
       described by p_filesz and p_memsz.  The bytes
       from the file are mapped to the beginning of the
       memory segment.  If the segment's memory size
       p_memsz is larger than the file size p_filesz,
       the "extra" bytes are defined to hold the value
       0 and to follow the segment's initialized area.
       The file size may not be larger than the memory
       size.  Loadable segment entries in the program
       header table appear in ascending order, sorted
       on the p_vaddr member.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-09-30 17:21:32 +02:00
Alexander Egorenkov
735d8f5493 zdump: Fix reading of ELF program headers in ELF DFI
Before attempting to read ELF program headers, the file must be positioned
at the offset of the first program header as specified in the ELF header.

Furthermore, read all ELF program headers with one call to zg_read(). This
has the advantage of not having to restore the file offset every time
after it is changed in pt_notes_add() and other functions which need to
read the same file as well.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-09-30 17:21:32 +02:00
Alexander Egorenkov
28efa7d120 zdump: Disable warnings about unaligned access to packed struct members
This is a false positive because IBM Z architecture supports unaligned
memory accesses.

dfo_s390.c: In function ‘df_s390_dump_init’:
dfo_s390.c:218:29: warning: taking address of packed member of ‘struct df_s390_hdr’ may result in an unaligned pointer value [-Waddress-of-packed-member]
  218 |                 timeval2tod(&dh->tod, dfi_attr_time());
      |                             ^~~~~~~~
dfo_s390.c:219:29: warning: taking address of packed member of ‘struct df_s390_em’ may result in an unaligned pointer value [-Waddress-of-packed-member]
  219 |                 timeval2tod(&em->tod, dfi_attr_time());
      |                             ^~~~~~~~
dfo_s390.c:222:29: warning: taking address of packed member of ‘struct df_s390_em’ may result in an unaligned pointer value [-Waddress-of-packed-member]
  222 |                 timeval2tod(&em->tod, dfi_attr_time_end());
      |                             ^~~~~~~~

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-09-30 17:21:29 +02:00
Eduard Shishkin
ebde75eeda zipl: add an ability to specify components location
When creating a bootmap, look for zipl components (stage3.bin and
zipl helpers) in a directory specified by S390TOOLS_LIBDIR shell
environment variable. If that variable is not set, then look for
them at the default location.

In verbose mode print the name of s390-tools library directory,
where the search was implemented.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-09-30 17:20:52 +02:00
Eduard Shishkin
a645ec0fc0 libutil: make TOOLS_LIBDIR and TOOLS_DATADIR configurable
Add generic functions

util_sysdir();
util_sysdir_path()

and their special cases supplied for users:

util_libdir();
util_libdir_path();
util_datadir();
util_datadir_path()

The function util_sysdir() determines the absolute name of a
s390-tools system directory. It could be data, or library directory.

The function util_sysdir_path() determines the absolute name of a
file installed in the s390-tools system directory.

The function util_libdir() determines the absolute name of a
s390-tools library directory. By default that name is defined
by the compile-time macro TOOLS_LIBDIR (/lib/s390-tools).
Users can specify an override by setting environment variable
S390TOOLS_LIBDIR.

The function util_libdir_path() determines the absolute name of a
file installed in the s390-tools library directory.

The function util_datadir() determines the absolute name of a
s390-tools system data directory. By default the name is defined
by the compile-time macro TOOLS_DATADIR (/usr/share/s390-tools/).
Users can specify an override by setting environment variable
S390TOOLS_DATADIR.

The function util_datadir_path() determines the absolute name of a
file installed in the s390-tools data directory.

The ability to override the setting for TOOLS_LIBDIR and
TOOLS_DATADIR is required for implementing tests on tools that are
not installed in their default system path locations.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-09-30 17:20:52 +02:00
Vineeth Vijayan
761a185938 zconf/lscss: show device number from pmcw
lscss shows device number as 'None' if the corresponding device in the
subchannel is non-operational or not connected. Instead, show the
device-no derived from the new dev_busid attribute which provides the
value of device_id irrespective of the device availability.

i.e the current lscss shows

Device   Subchan.  DevType CU Type Use  PIM PAM POM  CHPIDs
----------------------------------------------------------------------
0.0.0000 0.0.0000  3390/0c 3990/e9      f0  a0  ff   32333435 00000000
none     0.0.00c7                       f0  a0  5f   32333435 00000000
none     0.0.00c8                       f0  a0  5f   32333435 00000000

here the subchannels 0.0.00c7 and 0.0.00c8 do not have an operational
device on them. Hence the device is shown as none.

With this patch,

Device   Subchan.  DevType CU Type Use  PIM PAM POM  CHPIDs
----------------------------------------------------------------------
0.0.0000 0.0.0000  3390/0c 3990/e9      f0  a0  ff   32333435 00000000
0.0.74c8 0.0.00c7                       f0  a0  5f   32333435 00000000
0.0.74c9 0.0.00c8                       f0  a0  5f   32333435 00000000

The device-no is shown as 0.0.74c8; Where the DevType field still
indicates that the device is not present.

Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-09-30 17:20:52 +02:00
Harald Freudenberger
890b15d158 lszcrypt: add support for vfio-ap status field
lszcrypt now evaluates and displays the 'status' in the
'STATUS' column if the vfio provides this sysfs attribute.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-09-30 17:20:52 +02:00
Harald Freudenberger
07677668a3 lszcrypt: online is status and now tracked as status
The 'STATUS' field was within the code used as 'online'
record because it showed the online state. But now it
displays some more info like 'deconfig' and maybe even
more in the future. So now the code also uses a 'status'
record for this info.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-09-30 17:20:52 +02:00
Harald Freudenberger
fde914fd1c lszcrypt: Improved output for deconfig cards and queues
Slight rework of the lszcrypt code with:
- a queue or card in deconfigured mode is displayed
  as 'deconfig' regardless which driver is bound to
  the device.
- a queue or card in 'deconfig' mode does not show
  any counters any more but displays a '-' instead.
- a queue not bound or bound to something else as
  the 'default' zcrypt dd does not show any counters
  but displays a '-' instead.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-09-30 17:20:52 +02:00
Thomas Richter
35c97a07aa vmur/vmur.cpp: Fix error handling on transfer failure
The command

 # vmur punch -r rhcos-live-kernel-s390x -u etpgxku -N kernel.img
 Reader file with spoolid E YO created and transferred to ETPGXKU.
 #

did not indicate an error when executed. However the file was not
transferred and this error message went unnoticed:
RPIMGR032E YOU ARE NOT AUTHORIZED TO CLOSE TO TATAC05.ETPGXKU
HCPCSL007E Invalid userid - ETPGXKU

Fix this by checking the CP return code and print the error message
returned by CP. This is the behavior now:
 # vmur punch -r rhcos-live-kernel-s390x -u etpgxku -N kernel.img
 vmur: CP command failed with rc=7
 RPIMGR032E YOU ARE NOT AUTHORIZED TO CLOSE TO TATAC05.ETPGXKU
 HCPCSL007E Invalid userid - ETPGXKU
 #

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/119
Reported-by: Vance Morris <vmorris@us.ibm.com>
Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Tested-by: Vance Morris <vmorris@us.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-09-30 17:20:52 +02:00
Steffen Maier
45e3f016f4 lszfcp: add linkdown case to host marker of extended output
Complements v2.9.0 commit 4036e80b26 ("lszfcp: add new output marker
for non-good FCP devices (hosts)").

Otherwise "linkdown" shows as "failed" because linkdown happens to be
the one special case that also sets the failed status flag of the
FCP device (host). Linkdown is kind of benign compared to other cases
where the FCP device is in failed status.

Examples:
$ lszfcp -He
0.0.194a host3 linkdown

$ lszfcp -HeV
/sys/devices/css0/0.0.0004/0.0.194a linkdown
/sys/class/fc_host/host3
/sys/class/scsi_host/host3

Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Reviewed-by: Fedor Loshakov <loshakov@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-09-30 16:55:02 +02:00
Alexander Egorenkov
38b520ab4c zdump/dfi_elf: Don't accept ELF input with zero-sized PT_LOAD segments
The DFI memory chunk manager cannot handle PT_LOAD segments of size 0.
This can lead to a NULL pointer access in mem_chunk_find() in case
zgetdump is given an invalid VMCORE ELF file as input which contains
only zero-sized ELF PT_LOAD segments. Instead of crashing, show an error
message and terminate gracefully.

The TELA test dump_with_zero_sized_segments.sh can reproduce this bug.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-09-30 16:55:02 +02:00
Fabrice Fontaine
3b6920271e Makefile: add {CURL,XML2}_CONFIG
Add CURL_CONFIG and XML2_CONFIG to allow the user to configure the
binaries used in check-dep-libkmipclient

This will allow the user to avoid the following build failures raised
since version 2.17.0 and
56fecf1832:

/bin/sh: 1: curl-config: not found
Error: libcurl is not built with the OpenSSL backend
make[2]: *** [Makefile:54: check-dep-libekmfweb] Error 1

Fixes:
 - http://autobuild.buildroot.org/results/cfb46d7547c22f0a23aca2286dc5a1d2c20aadfc

Closes: https://github.com/ibm-s390-linux/s390-tools/pull/121
Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-09-30 16:55:02 +02:00
Steffen Maier
a3146409da dbginfo.sh: collect zipl boot menu entries from boot loader specification
Zipl.conf is collected via /etc/*.conf in CONFIGFILES but BLS snippets
do not appear in /etc/zipl.conf.

Complements v2.5.0 commit d280e5b1fa ("zipl: Add BootLoaderSpec support")

Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-09-30 16:55:02 +02:00
Ingo Franzki
76aa8e4a52 Makefile: Fix order of build of libraries for parallel builds
Some libraries depend on other libraries, so split the libraries
into two groups: base libraries that do not depend on any others, and
the remaining libraries, that may depend on the base libraries.

Ensure that the base libraries are built first, before starting to
build the remaining libraries. The tools are only built once the base
libraries and the remaining libraries have been built.

This fixes a possible build problem with libseckey when parallel build
is used. The libseckey library is used by libekmfweb and the zkey KMIP
plugin (zkey-kmip). With parallel build both are built in parallel,
and thus both trigger the build of libseckey. This can lead to the
situation that libseckey is built twice at the same time, which can lead
to build failures (corrupted archive, etc).

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-09-30 16:54:59 +02:00
Jan Höppner
f5e6f4a8cb gitignore: Add hsavmcore/check-dep-fuse
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-09-30 16:52:38 +02:00
Alexander Egorenkov
80cb1553a3 hsavmcore: Avoid recompilation of overlay during install step
overlay.o was being recompiled during the install step because
it depended on the target check-dep-fuse which is phony and,
therefore, always outdated. The solution is to create an empty file
for the target check-dep-fuse after its successful completion. This
prevents make from rebuilding overlay.o during installation.

Closes: https://github.com/ibm-s390-linux/s390-tools/pull/118
Fixes: 5a7d2a58c8 ("hsavmcore: Fix fuse dependency checking")
Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Suggested-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-27 11:48:45 +02:00
Thomas Richter
706f59b9d9 cpumf/lshwc.c: Fix sparse warning and replace 0 by NULL
Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Suggested-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-27 11:46:39 +02:00
Thomas Richter
02cc902b90 cpumf/lswhc.c: Fix sparse warning and add missing static
Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Suggested-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-27 11:46:39 +02:00
Alexander Egorenkov
ff2fb42868 cpumf/lshwc: Fix compile errors due to use of non-standard __BITS_PER_LONG
Use LONG_BIT provided by C standard in <limits.h>.

Fixes the following compile errors with buildroot:
lshwc.c: In function ‘parse_cpulist’:
lshwc.c:295:15: error: ‘__BITS_PER_LONG’ undeclared (first use in this function)
  295 |    no_a = i % __BITS_PER_LONG;
      |               ^~~~~~~~~~~~~~~

Fixes: 27a562da0a ("cpumf/lshwc: Program to extract complete counter sets")
Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-27 11:46:39 +02:00
Alexander Egorenkov
451bf7fbc6 cpumf/lshwc: Fix compile errors due to use of non-standard 32/64 bit types
Use standard 32- and 64-bit C types.

Fixes the following compile errors with buildroot:
In file included from lshwc.c:41:
lshwc.h:61:2: error: unknown type name ‘__u64’
   61 |  __u64 version;   /* Version of interface */
      |  ^~~~~
lshwc.h:62:2: error: unknown type name ‘__u64’
   62 |  __u64 data_bytes;  /* # of bytes required */
      |  ^~~~~
lshwc.h:63:2: error: unknown type name ‘__u64’
   63 |  __u64 cpumask_len;  /* Length of CPU mask in bytes */
      |  ^~~~~
lshwc.h:64:2: error: unknown type name ‘__u64’
   64 |  __u64 *cpumask;   /* Pointer to CPU mask */
      |  ^~~~~
lshwc.h:65:2: error: unknown type name ‘__u64’
   65 |  __u64 counter_sets;  /* Bit mask of counter set to get */
      |  ^~~~~
lshwc.h:69:2: error: unknown type name ‘__u32’
   69 |  __u32 set;   /* Counter set number */
      |  ^~~~~

Fixes: 27a562da0a ("cpumf/lshwc: Program to extract complete counter sets")
Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-27 11:46:39 +02:00
Ingo Franzki
d2a4a8b0f3 libkmipclient: Fix parsing of hex values for XML and JSON encoding
KMIP values of type BYTE-STRING are represented as hex values when XML
or JSON encoding is used. Do not drop any leading zero bytes, if the
value has them.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-27 11:46:39 +02:00
Jan Höppner
fe5753d34d Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-27 11:46:39 +02:00
149 changed files with 9134 additions and 2989 deletions

13
.editorconfig Normal file
View File

@@ -0,0 +1,13 @@
# Check https://editorconfig.org for details
root = true
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = tab
tab_width = 8
[*.sh]
shell_variant = bash # used by `shfmt`

7
.gitignore vendored
View File

@@ -9,6 +9,10 @@
tags
TAGS
# Ignore coverage data
*.gcda
*.gcno
#
# Ignore generated executables and other generated files
#
@@ -25,6 +29,7 @@ dasdview/dasdview
dump2tar/src/dump2tar
fdasd/fdasd
hmcdrvfs/hmcdrvfs
hsavmcore/check-dep-fuse
hsavmcore/hsavmcore
hyptop/hyptop
ip_watcher/xcec-bridge
@@ -98,7 +103,9 @@ zipl/boot/*.bin
zipl/boot/*.exec
zipl/boot/data.h
zipl/src/chreipl_helper.device-mapper
zdev/src/zdev_id
zipl/src/zipl
zipl/src/zipl-editenv
zipl/src/zipl_helper.device-mapper
zkey/check-dep-zkey
zkey/check-dep-zkey-cryptsetup

View File

@@ -2,6 +2,7 @@ List of all individuals having contributed content to s390-tools
----------------------------------------------------------------
- Alexander Egorenkov
- Alexandra Winter
- Alexey Ishchuk
- Andreas Herrmann
- Andre Wild
@@ -37,6 +38,7 @@ List of all individuals having contributed content to s390-tools
- Fritz Elfert
- Gerald Schaefer
- Gerhard Tonn
- Graham Inggs
- Guevenc Guelce
- Hannes Reinecke
- Hans-Joachim Picht
@@ -73,6 +75,7 @@ List of all individuals having contributed content to s390-tools
- Martin Peschke
- Martin Petermann
- Martin Schwidefsky
- Matthew Rosato
- Maxim Shchetynin
- Melissa Howland
- Michael Ernst
@@ -102,6 +105,7 @@ List of all individuals having contributed content to s390-tools
- Stefan Raspl
- Stefan Reimbold
- Stefan Weinhuber
- Steffen Eiden
- Steffen Maier
- Steffen Thoss
- Susanne Wintenberger
@@ -110,6 +114,7 @@ List of all individuals having contributed content to s390-tools
- Swen Schillig
- Taraka R. Bodireddy
- Thomas Heidrich
- Thomas Huth
- Thomas Richter
- Thomas Spatzier
- Thomas Weber

View File

@@ -1,5 +1,76 @@
Release history for s390-tools (MIT version)
--------------------------------------------
* __v2.20.0 (2021-02-04)__
For Linux kernel version: 5.16
Add new tools / libraries:
- Add EditorConfig configuration
Changes of existing tools:
- s390-tools switches to Fuse 3 as Fuse 2 is deprecated.
Affected tools: cmsfs, hmcdrvfs, hsavmcore, zdsfs, zdump
- chreipl-fcp-mpath: don't compress the manpage before installing it
- cpictl: Report extended version information
- genprotimg: Add extended kernel command line support
- zdev: modify the lsblk output parser in lszdev
- zipl: Add support for longer kernel command lines (now supports up to 64k length)
Bug Fixes:
- cpictl: Suppress messages for unwritable sysfs files
- dbginfo.sh: Fix missing syslog for step create_package
- lshwc: Fix CPU list parameter setup for device driver
- zdev: Check for errors when removing a devtype setting
- zdev: Fix path resolution for multi-mount point file systems
* __v2.19.0 (2021-11-10)__
For Linux kernel version: 5.15
Add new tools / libraries:
- chreipl-fcp-mpath: New toolset that uses multipath information to change
the configured FCP re-IPL path on detecting issues with the current path
Changes of existing tools:
- dbginfo.sh: Add retry timeout and remove possible blocking "blockdev --report"
- dbginfo.sh: Collect config- and debug-data for chreipl-fcp-mpath
- hsci: Add support for multiple MAC addresses
Bug Fixes:
- lshwc: Fix compile error for gcc <8.1
- zdump: Various clean-ups and fixes
- ziomon: Correct throughput calculation in ziorep_printers
- zipl: Fix segmentation fault when setting stage3_parms
* __v2.18.0 (2021-10-01)__
For Linux kernel version: 5.14
Add new tools:
- scripts: Add tool for parsing sclp s390dbf logs
- zdev: Add udev rule helper tool
- zipl-editenv: Add tool to operate with zIPL environment installed in the boot record
Changes of existing tools:
- Makefile: Fix order of build of libraries for parallel builds
- dbginfo.sh: Add collection in area of timedate, coredump and --check option
- dbginfo.sh: Add exception on dump2tar for /sys/kernel/mm/page_idle/bitmap
- dbginfo.sh: Cleanup of outdated sections and general code rework
- dbginfo.sh: Collect zipl boot menu entries from boot loader specification
- lszcrypt: Add support for vfio-ap status field
- lszcrypt: Improved output for deconfig cards and queues
- lszfcp: Add linkdown case to host marker of extended output
- zdev: Add auto-config for PCI and crypto devices
- zdump: Introduce multi-level message logging
- zipl: Add support for environment block interpretation
- zkey-cryptsetup: Support LUKS2 volumes with integrity support enabled
Bug Fixes:
- hsavmcore: Avoid recompilation of overlay during install step
- libkmipclient: Fix parsing of hex values for XML and JSON encoding
- vmur/vmur.cpp: Fix error handling on transfer failure
- zdump: Lots of smaller fixes across the board
* __v2.17.0 (2021-07-07)__
For Linux kernel version: 5.12 / 5.13

View File

@@ -3,16 +3,22 @@ ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/ar
# Include common definitions
include common.mak
LIB_DIRS = libvtoc libutil libzds libdasd libvmdump libccw libvmcp libekmfweb \
libseckey libkmipclient
#
# BASELIBS: Libraries that have no dependency to other libraries in s390-tools
# LIBS: Libraries that can have a dependency to base libraries
# TOOLS: Tools that can have a dependency to base libraries or libraries
#
BASELIB_DIRS = libutil libseckey
LIB_DIRS = libvtoc libzds libdasd libvmdump libccw libvmcp libekmfweb \
libkmipclient
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
ziomon iucvterm hyptop cmsfs-fuse qethqoat zfcpdump zdsfs cpumf \
systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc zpcictl \
genprotimg lsstp hsci hsavmcore
genprotimg lsstp hsci hsavmcore chreipl-fcp-mpath
SUB_DIRS = $(LIB_DIRS) $(TOOL_DIRS)
SUB_DIRS = $(BASELIB_DIRS) $(LIB_DIRS) $(TOOL_DIRS)
all: $(TOOL_DIRS)
clean: $(TOOL_DIRS)
@@ -26,9 +32,10 @@ MAKECMDGOALS = all
endif
#
# We have to build the libraries before the tools are built. Otherwise
# the tools would trigger parallel "make -C" builds for libraries in
# case of "make -j".
# We have to build the base libraries before the other libraries are built,
# and then build the other libraries before the tools are built. Otherwise the
# other libraries and tools would trigger parallel "make -C" builds for the
# base libraries and the other libraries in case of "make -j".
#
# MAKECMDGOALS contains the list of goals, e.g. "clean all". We use
# "foreach" to generate a ";" separated list of "make -C <target>".
@@ -45,7 +52,12 @@ $(TOOL_DIRS): $(LIB_DIRS)
$(MAKE) -C $@ TOPDIR=$(TOPDIR) ARCH=$(ARCH) $(goal) ;)
.PHONY: $(TOOL_DIRS)
$(LIB_DIRS):
$(LIB_DIRS): $(BASELIB_DIRS)
$(foreach goal,$(MAKECMDGOALS), \
$(MAKE) -C $@ TOPDIR=$(TOPDIR) ARCH=$(ARCH) $(goal) ;)
.PHONY: $(LIB_DIRS)
$(BASELIB_DIRS):
$(foreach goal,$(MAKECMDGOALS), \
$(MAKE) -C $@ TOPDIR=$(TOPDIR) ARCH=$(ARCH) $(goal) ;)
.PHONY: $(BASELIB_DIRS)

View File

@@ -109,6 +109,9 @@ Package contents
feature. Those traces are filtered with the zfcpdbf script, i.e. merge
several traces, make it more readable etc.
* sclpdbf:
Display debug data for the sclp kernel component.
* scsi_logging_level:
Create, get or set the logging level for the SCSI logging facility.
@@ -267,6 +270,10 @@ Package contents
can be time consuming and prevent the HSA memory from being reused
by other LPARs.
* chreipl-fcp-mpath:
Use multipath information to change the configured FCP re-IPL path on
detecting issues with the current path.
For more information refer to the following publications:
* "Device Drivers, Features, and Commands" chapter "Useful Linux commands"
@@ -285,7 +292,7 @@ build options:
| __LIBRARY__ | __BUILD OPTION__ | __TOOLS__ |
|----------------|:------------------:|:-------------------------------------:|
| fuse | `HAVE_FUSE` | cmsfs-fuse, zdsfs, hmcdrvfs, zgetdump,|
| fuse3 | `HAVE_FUSE` | cmsfs-fuse, zdsfs, hmcdrvfs, zgetdump,|
| | | hsavmcore |
| zlib | `HAVE_ZLIB` | zgetdump, dump2tar |
| ncurses | `HAVE_NCURSES` | hyptop |
@@ -304,11 +311,11 @@ build options:
This table lists additional build or install options:
| __COMPONENT__ | __OPTION__ | __TOOLS__ |
|------------------|:----------------------------:|:--------------:|
| dracut | `HAVE_DRACUT` | zdev |
| initramfs-tools | `HAVE_INITRAMFS` | zdev |
| | `ZDEV_ALWAYS_UPDATE_INITRD` | zdev |
| __COMPONENT__ | __OPTION__ | __TOOLS__ |
|------------------|:----------------------------:|:-----------------------:|
| dracut | `HAVE_DRACUT` | zdev, chreipl-fcp-mpath |
| initramfs-tools | `HAVE_INITRAMFS` | zdev |
| | `ZDEV_ALWAYS_UPDATE_INITRD` | zdev |
The s390-tools build process uses "pkg-config" if available and hard-coded
compiler and linker options otherwise.
@@ -348,12 +355,12 @@ the different tools are provided:
* cmsfs-fuse/zdsfs/hmcdrvfs/zgetdump:
The tools cmsfs-fuse, zdsfs, hmcdrvfs, and zgetdump depend on FUSE.
FUSE is provided by installing the fuse and libfuse packages and by a
FUSE is provided by installing the fuse3 and libfuse3 packages and by a
kernel compiled with `CONFIG_FUSE_FS`. For compiling the s390-tools package
the fuse-devel package is required.
The cmsfs-fuse tool requires FUSE version 2.8.1 or newer for full
the fuse3-devel package is required.
The cmsfs-fuse tool requires FUSE version 3.0 or newer for full
functionality.
For further information about FUSE see: http://fuse.sourceforge.net
For further information about FUSE see: https://github.com/libfuse/libfuse
* hyptop:
The ncurses-devel package is required to build hyptop.
@@ -449,7 +456,7 @@ the different tools are provided:
`HAVE_JSONC=0`, or `HAVE_LIBCURL=0` to the make invocation.
* hsavmcore:
For building the hsavmcore tool you need fuse version 2.6 and optionally
For building the hsavmcore tool you need fuse version 3.0 and optionally
systemd which is enabled by default, to disable systemd support,
add `HAVE_SYSTEMD=0` to the make invocation.
Tip: you may skip the hsavmcore build by adding `HAVE_FUSE=0`
@@ -462,3 +469,14 @@ the different tools are provided:
(libxml2-devel.rpm), and libcurl version 7.59 or newer (libcurl-devel.rpm).
Tip: you may skip the libkmipclient build by adding `HAVE_OPENSSL=0`,
`HAVE_JSONC=0`, `HAVE_LIBXML2=0`, or `HAVE_LIBCURL=0` to the make invocation.
* chreipl-fcp-mpath:
For a complete list and documentation of the requirements, installation and
uninstallation, please see
[chreipl-fcp-mpath/README.md](chreipl-fcp-mpath/README.md).
Summarized: chreipl-fcp-mpath requires GNU Bash, GNU Core Utilities,
util-linux, udev, and multipath-tools. When using `HAVE_DRACUT=1` with the
make invocation, it also requires dracut. When using `ENABLE_DOC=1` with the
make invocation to build a man page and render the README.md as HTML, make
further requires pandoc and GNU awk for the build process.

View File

@@ -32,7 +32,7 @@ Usage: $cmd [-t LAST_GIT_TAG]
Add all new authors since last release to the $authors_file file. Without
the -t option the tool uses the last available git tag as last release.
The tool should be called form the s390-tools master branch.
The tool runs on the s390-tools master branch.
OPTIONS
-t, --tag LAST_GIT_TAG Use git tag LAST_GIT_TAG as starting point
@@ -116,7 +116,7 @@ echo "$cmd: Adding new authors since tag: $release_tag_last"
# Print authors list without header
tail -n +4 $authors_file_path
# Add the new authors
git log --format="- %an" $release_tag_last..
git log --format="- %an" $release_tag_last..master
# Then sort everything and remove duplicates
} | sort | uniq > $authors_file_tmp
# Create new AUTHORS file with header ...

12
chreipl-fcp-mpath/.gitignore vendored Normal file
View File

@@ -0,0 +1,12 @@
# build artifacts
/chreipl-fcp-mpath-common.sh
/chreipl-fcp-mpath-is-ipl-tgt
/chreipl-fcp-mpath-is-ipl-vol
/chreipl-fcp-mpath-is-reipl-zfcp
/chreipl-fcp-mpath-record-volume-identifier
/chreipl-fcp-mpath-try-change-ipl-path
/dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf
/README.html
/README.pdf
/chreipl-fcp-mpath.md
/chreipl-fcp-mpath.7

255
chreipl-fcp-mpath/Makefile Normal file
View File

@@ -0,0 +1,255 @@
# SPDX-License-Identifier: MIT
#
# chreipl-fcp-mpath: use multipath information to change FCP IPL target
# (C) Copyright IBM Corp. 2021
#
# Uses the following system-utilities (and shell-builtins):
# Utilities list in GNU Make Conventions:
# https://www.gnu.org/software/make/manual/make.html#Utilities-in-Makefiles
# Those necessary for sourced Makefiles:
# - ../common.mak
# - chreipl-fcp-mpath.mak
# bash:
# - bash
# If $(ENABLE_DOC) is `1`:
# GNU awk:
# - gawk
override SHELL := /bin/bash
override .SHELLFLAGS := -O globstar -O nullglob -O extglob -c
# Include common s390-tools definitions
include ../common.mak
# Include common chreipl-fcp-mpath definitions
include chreipl-fcp-mpath.mak
# Local setting: .make.config
# You may create a file named like this in the same directory as this
# Makefile, and customize the build this way (e.g. re-define variables
# set in `chreipl-fcp-mpath.mak`, or define a `CHREIPLZFCPMP_POST_INSTALL`
# that is automatically called after each installation)
ifneq ($(wildcard .make.config),)
include $(wildcard .make.config)
endif
#
## Build
#
.PHONY: chreipl-fcp-mpath chreipl-fcp-mpath-clean
chreipl-fcp-mpath:
chreipl-fcp-mpath-clean:
all: chreipl-fcp-mpath
clean: chreipl-fcp-mpath-clean
# common function used in the helper scripts
CHREIPL_FCP_MPATH_COMMON := \
chreipl-fcp-mpath-common.sh
CHREIPL_FCP_MPATH_UDEV_HELPER := \
chreipl-fcp-mpath-is-ipl-tgt \
chreipl-fcp-mpath-is-ipl-vol \
chreipl-fcp-mpath-is-reipl-zfcp \
chreipl-fcp-mpath-record-volume-identifier \
chreipl-fcp-mpath-try-change-ipl-path
$(CHREIPL_FCP_MPATH_UDEV_HELPER) $(CHREIPL_FCP_MPATH_COMMON): $(MAKEFILE_LIST)
$(CHREIPL_FCP_MPATH_UDEV_HELPER) $(CHREIPL_FCP_MPATH_COMMON): % : %.in
$(call chreiplzfcpmp-sed-buildvar-replace,$(<),$(@))
chmod a+x $(@)
$(CHREIPL_FCP_MPATH_UDEV_HELPER): $(CHREIPL_FCP_MPATH_COMMON)
.PHONY: chreipl-fcp-mpath-udev-helper-clean
chreipl-fcp-mpath-udev-helper-clean:
rm -f $(CHREIPL_FCP_MPATH_UDEV_HELPER) $(CHREIPL_FCP_MPATH_COMMON)
udev/rules.d/70-chreipl-fcp-mpath.rules: $(CHREIPL_FCP_MPATH_UDEV_HELPER)
chreipl-fcp-mpath: udev/rules.d/70-chreipl-fcp-mpath.rules
chreipl-fcp-mpath-clean: chreipl-fcp-mpath-udev-helper-clean
dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf: $(MAKEFILE_LIST)
dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf: % : %.in
$(call chreiplzfcpmp-sed-buildvar-replace,$(<),$(@))
.PHONY: chreipl-fcp-mpath-dracut-clean
chreipl-fcp-mpath-dracut-clean:
rm -f dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf
chreipl-fcp-mpath: dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf
chreipl-fcp-mpath-clean: chreipl-fcp-mpath-dracut-clean
ifeq ($(ENABLE_DOC),1)
.PHONY: chreipl-fcp-mpath-doc
chreipl-fcp-mpath-doc: README.html chreipl-fcp-mpath.7
ifeq ($(ENABLE_DOC_PDF),1)
chreipl-fcp-mpath-doc: README.pdf
README.pdf: PANDOCFLAGS += -M title="chreipl-fcp-mpath" -M subtitle="README"
endif
README.html: PANDOCFLAGS += -M title="chreipl-fcp-mpath" -M subtitle="README"
chreiplzfcpmp-doc-man-meta = \
-M title="CHREIPL-FCP-MPATH" \
-V header="Administrator Manual" \
-V section="7" \
-V footer="s390-tools $(S390_TOOLS_RELEASE)"
chreipl-fcp-mpath.7: PANDOCFLAGS += $(chreiplzfcpmp-doc-man-meta)
.INTERMEDIATE: chreipl-fcp-mpath.md
chreipl-fcp-mpath.md: README.md
gawk -- '/NOT-IN-MAN \{/,/NOT-IN-MAN \}/ { next } { print }' $(<) > $(@)
.PHONY: chreipl-fcp-mpath-doc-clean
chreipl-fcp-mpath-doc-clean:
rm -f README.html README.pdf chreipl-fcp-mpath.md chreipl-fcp-mpath.7
chreipl-fcp-mpath: chreipl-fcp-mpath-doc
chreipl-fcp-mpath-clean: chreipl-fcp-mpath-doc-clean
endif
#
## Install
#
.PHONY: chreipl-fcp-mpath-install
# The content of `CHREIPLZFCPMP_POST_INSTALL` (bash script) is automatically
# called *after* installing chreipl-fcp-mpath during `make install`. If not
# defined (the default), nothing happens. You may define this on the make
# command line, or by creating a `.make.config` and defining the variable in
# there.
chreipl-fcp-mpath-install:
$(CHREIPLZFCPMP_POST_INSTALL)
install: chreipl-fcp-mpath-install
# install udev rules
INSTDIRS += $(UDEVRULESDIR)
$(DESTDIR)$(UDEVRULESDIR): install_dirs
.PHONY: chreipl-fcp-mpath-install-udev-rules
chreipl-fcp-mpath-install-udev-rules: | $(DESTDIR)$(UDEVRULESDIR)
chreipl-fcp-mpath-install-udev-rules: udev/rules.d/70-chreipl-fcp-mpath.rules
$(INSTALL_DATA) -t $(DESTDIR)$(UDEVRULESDIR) \
udev/rules.d/70-chreipl-fcp-mpath.rules
chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-udev-rules
# install udev helper programs
INSTDIRS += $(UDEVDIR)
$(DESTDIR)$(UDEVDIR): install_dirs
.PHONY: chreipl-fcp-mpath-install-udev-helper
chreipl-fcp-mpath-install-udev-helper: | $(DESTDIR)$(UDEVDIR)
chreipl-fcp-mpath-install-udev-helper: $(CHREIPL_FCP_MPATH_UDEV_HELPER)
$(INSTALL_EXEC) -t $(DESTDIR)$(UDEVDIR) $(CHREIPL_FCP_MPATH_UDEV_HELPER)
chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-udev-helper
# install common library files
INSTDIRS += $(CHREIPLZFCPMPDIR)
$(DESTDIR)$(CHREIPLZFCPMPDIR): install_dirs
.PHONY: chreipl-fcp-mpath-install-libfiles
chreipl-fcp-mpath-install-libfiles: | $(DESTDIR)$(CHREIPLZFCPMPDIR)
chreipl-fcp-mpath-install-libfiles: $(CHREIPL_FCP_MPATH_COMMON)
$(INSTALL_DATA) -t $(DESTDIR)$(CHREIPLZFCPMPDIR) \
$(CHREIPL_FCP_MPATH_COMMON)
chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-libfiles
ifeq ($(HAVE_DRACUT),1)
# install dracut config files
INSTDIRS += $(DRACUTCONFDIR)
$(DESTDIR)$(DRACUTCONFDIR): install_dirs
.PHONY: chreipl-fcp-mpath-install-dracut-config
chreipl-fcp-mpath-install-dracut-config: | $(DESTDIR)$(DRACUTCONFDIR)
chreipl-fcp-mpath-install-dracut-config: dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf
$(INSTALL_DATA) -t $(DESTDIR)$(DRACUTCONFDIR) \
dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf
chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-dracut-config
endif
ifeq ($(ENABLE_DOC),1)
# chreipl-fcp-mpath: install man page
INSTDIRS += $(MANDIR)
$(DESTDIR)$(MANDIR)/man7: install_dirs
.PHONY: chreipl-fcp-mpath-install-man-page
chreipl-fcp-mpath-install-man-page: | $(DESTDIR)$(MANDIR)/man7
chreipl-fcp-mpath-install-man-page: chreipl-fcp-mpath.7
$(INSTALL_DATA) -t $(DESTDIR)$(MANDIR)/man7 \
chreipl-fcp-mpath.7
chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-man-page
endif
#
## Utility
#
# Utilities for the debug feature of chreipl-fcp-mpath-common.sh.
#
# When `chreipl-fcp-mpath` is built with D=1 (default is D=0), each run
# of one of the helper scripts will create a debug log in $(DEBUGOUTDIR)
# (default: /run/udev) which among other things contains the complete shell
# trace of that script run, with some added information that would not be
# inspectable otherwise with just the trace.
#
# There is currently no way of enabling/disabling this at runtime.
#
# chreipl-fcp-mpath-common.sh defines debug log file name as
# "chreiplzfcpmp-${debug_trace_tag}-${SEQNUM:-0}.XXXXXXXXXX" where SEQNUM is a
# udev rule environment variable and each X is replaced with some [[:alnum:]]
# by mktemp. For a definition of `debug_trace_tag`, please see the comments
# in the source.
#
# The following targets can be used for some simple access and filtering of the
# logs during development.
DEBUG_LOG_GLOB = $(DEBUGOUTDIR)/chreiplzfcpmp-[[:digit:]][[:digit:]][[:alpha:]][[:alpha:]][[:alpha:]][[:alpha:]]-+([[:digit:]]).[[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]]
# display all debug log files on the system
.PHONY: chreipl-fcp-mpath-debug-logs
chreipl-fcp-mpath-debug-logs:
@ls -1d $(DEBUG_LOG_GLOB)
# display only debug log files of script runs that exited with status 0 (= good)
#
# XXX: `sed -n -e '$p'` is used instead of `tail -n1` to prevent an other
# dependency just for that (both invocations do the same thing).
.PHONY: chreipl-fcp-mpath-debug-logs-filter-good
chreipl-fcp-mpath-debug-logs-filter-good:
@for lg in $(DEBUG_LOG_GLOB); do \
sed -e '/^+ trap_exit$$/,/^+ trap - EXIT$$/d' "$${lg}" \
| sed -n -e '$$p' \
| grep -q -e '^+ exit 0$$' || continue; \
ls -d "$${lg}"; \
done
# display only debug log files of script runs that didn't exit with status 0
# (= bad)
.PHONY: chreipl-fcp-mpath-debug-logs-filter-bad
chreipl-fcp-mpath-debug-logs-filter-bad:
@for lg in $(DEBUG_LOG_GLOB); do \
sed -e '/^+ trap_exit$$/,/^+ trap - EXIT$$/d' "$${lg}" \
| sed -n -e '$$p' \
| grep -q -e '^+ exit 0$$' && continue; \
ls -d "$${lg}"; \
done
.PHONY: chreipl-fcp-mpath-debug-logs-clean
chreipl-fcp-mpath-debug-logs-clean:
rm -f $(DEBUG_LOG_GLOB)

268
chreipl-fcp-mpath/README.md Normal file
View File

@@ -0,0 +1,268 @@
<!-- markdown documentation: https://github.github.com/gfm/ -->
NAME
====
chreipl-fcp-mpath - use multipath information for re-IPL path failover on a
running Linux instance
DESCRIPTION
===========
The IPL process of Linux on Z or LinuxONE from an FCP-attached SCSI volume uses
exactly one path to the volume. If this path is unavailable, the IPL fails.
The **chreipl-fcp-mpath** toolset monitors **udev** events about paths to the
re-IPL volume. If the currently configured re-IPL path becomes unavailable, the
toolset checks for operational paths to the same volume. If available, it
reconfigures the re-IPL settings to use an operational path.
Thus, re-IPL from an FCP-attached SCSI volume can be successful despite path
failures on a running Linux instance if at least one path to the re-IPL volume
remains operational.
**Chreipl-fcp-mpath** requires **udev**, **multipathd** and **dm-multipath**.
Once installed, the toolset runs automatically and autonomously. No user
intervention is possible or required.
Other than installing the toolset, there is no user interface for
**chreipl-fcp-mpath**.
Requirements
------------
The **chreipl-fcp-mpath** tool has the following requirements on the
Linux instance that is being monitored:
- The Linux instance must have started successfully, during IPL.
- The running Linux instance must use **dm-multipath** and **multipathd** for
the configured re-IPL volume - a volume that contains a zipl boot record
and has one of its paths used in the re-IPL configuration.
- **udev** must run.
- The toolset must observe at least one event about the configured re-IPL
path. Examples for such events are: the SCSI disk comes online, or a path
of the corresponding multipath device goes down or comes back online.
- The WWID of the re-IPL volume must not change while the Linux instance is
running.
- When the configured re-IPL path becomes unavailable while the Linux
instance is running, at least one operational path to the re-IPL volume
must be available, or must become available. If no such path is available
when the Linux instance is rebooted, the re-IPL path is not changed.
- The tool assumes that any manually reconfigured re-IPL device is valid and
operational.
The tool treats a newly configured re-IPL device like the initially
configured re-IPL device. In particular, if the newly configured re-IPL
device fulfills the requirements of the tool, re-IPL path failover takes
place if the configured re-IPL path becomes unavailable.
Caution with Manual Changes to the Configured re-IPL Target
-----------------------------------------------------------
**chreipl-fcp-mpath** is designed to accept operator-inititated changes of the
re-IPL device. However, concurrent changes by the operator and tool driven
changes can result in the operator change being overwritten.
To avoid this problem, change the re-IPL device only during steady-state
operations, when no path events happen. Alternatively, make sure that no events
are processed while you change the device. See [EXAMPLES](#examples) for one
way to suspend event processing.
MESSAGES
========
During monitoring and event processing, **chreipl-fcp-mpath** writes messages
to the syslog.
When the configured re-IPL path is changed to a different path to the same
volume (priority *daemon.notice*):
> Changed re-IPL path to: \<device-bus-id\>:\<wwpn\>:\<lun\>.
When a path event indicates that the last available path has become
non-operational (priority *daemon.alert*):
> The re-IPL device cannot be changed because no operational path to the
> re-IPL volume remains. The next re-IPL might fail unless you re-attach or
> enable at least one valid path to the re-IPL volume.
When changing the configured re-IPL device failed because of an error with the
used Linux kernel interface (priority *daemon.crit*):
> Changing the re-IPL device failed. The current re-IPL settings might be
> inconsistent. Check and correct the settings (see the README.md of
> chreipl-fcp-mpath) to make sure that the current re-IPL device is valid.
A failure to change the re-IPL device can indicate an inconsistent setting that
cannot be corrected automatically by **chreipl-fcp-mpath**. As a result, the
next re-IPL might fail or might not use the intended re-IPL device.
You can use the following tools to check and correct the current settings:
- **lsreipl** to confirm that the intended re-IPL device is configured;
- **chreipl** to change the re-IPL device;
- **lszfcp** to inspect the state of available paths to the re-IPL device.
<!-- NOT-IN-MAN { -->
SOFTWARE REQUIREMENTS
=====================
**chreipl-fcp-mpath** integrates into s390-tools's build and install
infrastructure. Use **make** to build it. No explicit dependency management is
in place, but the toolset has some software dependencies besides the
requirements in section [Requirements](#requirements):
- GNU Bash;
- GNU Core Utilities (mktemp, readlink, sync, truncate);
- util-linux (flock, hexdump, logger);
- udev / systemd-udev;
- multipath-tools.
To make use of the optional dracut configuration you need: dracut.
To build and install the documentation (man page) you need:
- pandoc;
- GNU Core Utilities (date);
- GNU awk.
INSTALLATION
============
If your distribution includes a packaged version of **chreipl-fcp-mpath**,
either as a separate package or as part of a **s390-tools** package, install
that package. Otherwise, you can either install it from source as part of
**s390-tools** or separately.
To install **chreipl-fcp-mpath** as part of **s390-tools**, use **make** on the
top-level directory of your **s390-tools** distribution. Installing the entire
distribution might overwrite other already installed tools.
To install the tool separately, change into the **chreipl-fcp-mpath**
directory, and use **make** there.
You need *root* privileges to install the tool into the root file system.
Calling **make** runs the build steps. Calling **make install** runs the build
steps and copies the resulting components to their final destination.
**s390-tools** offers more options and targets to customize the build (see
**make help**).
**chreipl-fcp-mpath** has the following optional build options:
| Option | Values | Default | Effect
| :----- | :----: | :-----: | :-----
| HAVE_DRACUT | 0, 1 | 0 | Install a dracut configuration file that includes **chreipl-fcp-mpath** in the initial ramdisks built with **dracut**.
| ENABLE_DOC | 0, 1 | 0 | Build and install a man page for **chreipl-fcp-mpath**.
Specify any options as arguments for both the **make** and **make install**
command as shown in the following example:
~ # cd chreipl-fcp-mpath/
~ # make HAVE_DRACUT=1 ENABLE_DOC=1
~ # make HAVE_DRACUT=1 ENABLE_DOC=1 install
After the installation, reload the udev rules database:
~ # udevadm control --reload
*The toolset is now active on your running Linux instance.*
If you use the *HAVE_DRACUT=1* option, also rebuild your
initial ramdisk, to immediately include the toolset instead of
waiting for the next kernel update.
How to rebuild the initial ramdisk and the naming scheme for the
resulting file or files depends on your distribution.
The following example applies to Fedora and to Red Hat Enterprise Linux:
~ # dracut --force /boot/initramfs-"$(uname -r)".img "$(uname -r)"
For SUSE Linux Enterprise Server run for example:
~ # dracut --hostonly --force /boot/initrd-"$(uname -r)" "$(uname -r)"
These commands replace the initial ramdisk for the currently running kernel.
If your distribution uses **zipl** as its boot loader, run **zipl** to refresh
the boot record to find the new initial ramdisk.
~ # zipl
With dracut and documentation enabled, **make install** deploys the following
files to these default locations:
/usr/lib/chreipl-fcp-mpath/chreipl-fcp-mpath-common.sh
/usr/lib/dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf
/usr/lib/udev/chreipl-fcp-mpath-is-ipl-tgt
/usr/lib/udev/chreipl-fcp-mpath-is-ipl-vol
/usr/lib/udev/chreipl-fcp-mpath-is-reipl-zfcp
/usr/lib/udev/chreipl-fcp-mpath-record-volume-identifier
/usr/lib/udev/chreipl-fcp-mpath-try-change-ipl-path
/usr/lib/udev/rules.d/70-chreipl-fcp-mpath.rules
/usr/share/man/man7/chreipl-fcp-mpath.7
UNINSTALL
=========
If your distribution includes a separately from **s390-tools** packaged version
of **chreipl-fcp-mpath**, uninstall that package.
For installations without distribution packaging, you cannot uninstall
**chreipl-fcp-mpath** with **make**.
Instead, remove the toolset by deleting the installed files as listed in
[INSTALLATION](#installation)), reload the udev rules database, and rebuild all
modified initial ramdisks as described in [INSTALLATION](#installation)).
<!-- NOT-IN-MAN } -->
EXAMPLES
========
Manual Changes to the Configured re-IPL Device
----------------------------------------------
As outlined in [DESCRIPTION](#description), be cautious when manually changing
the configured re-IPL device. Assure that your reconfiguration actions do not
collide with concurrent automatic event processing by **chreipl-fcp-mpath**.
You can avoid such collisions, by stopping event processing, making your
changes, and then re-enabling event processing. You need *root* privileges for
running the commands in the following example:
~ # udevadm settle
~ # udevadm control --stop-exec-queue
~ # chreipl ...
~ # udevadm control --start-exec-queue
Listing messages with journalctl
--------------------------------
If your Linux instance includes **journalctl**, use the following command to
list all messages that are issued by **chreipl-fcp-mpath**:
~ # journalctl -t chreipl-fcp-mpath
To list only messages that were issued since the last IPL, use this command:
~ # journalctl -t chreipl-fcp-mpath -b
REPORTING BUGS
==============
Use the **Issues** functionality on GitHub to report any bugs in
**chreipl-fcp-mpath**:
[s390-tools Issues](<https://github.com/ibm-s390-linux/s390-tools/issues> "Link to the s390-tools Issues page").
SEE ALSO
========
**chreipl**(8), **dracut**(8), **journalctl**(1), **lsreipl(8)**,
**lszfcp**(8), **multipath**(8), **multipathd**(8), **udev**(7),
**udevadm**(8), **zipl**(8)

View File

@@ -0,0 +1,446 @@
# SPDX-License-Identifier: MIT
#
# chreipl-fcp-mpath: use multipath information to change FCP IPL target
# (C) Copyright IBM Corp. 2021
#
# Uses the following system-utilities (and shell-builtins):
# GNU coreutils:
# - mktemp
# - readlink
# - sync
# util-linux:
# - flock
# - logger
# Makes use of udev event environment variables:
# SEQNUM
# (1) expand failed globs to an empty string
# (2) extended pattern matching to strip leading/trailing whitespaces
shopt -s nullglob extglob
# (1) don't overwrite existing files using redirects (e.g.: `>`)
set -o noclobber
# make sure any state files created are only writeable by the owning user
umask 027
# create log if DEBUG is enabled (with Make: D=1)
#
# Each script importing this library and expecting a debug log to be created
# must declare a *trace tag* in a variable `debug_trace_tag`. This is used as
# identifier in the log file name. The format is:
#
# [[:digit:]][[:digit:]][[:alpha:]][[:alpha:]][[:alpha:]][[:alpha:]]
# \ /\ /
# --------\ /-------- -------------------\ /-------------------
# \/ \/
# relative position of some unique abbreviation for the script
# execution in the name, excluding any common prefix
# udev rules
if '@DEBUG@' && [ -v debug_trace_tag ] && tlg="$(
mktemp -p '@debugoutdir@' \
"chreiplzfcpmp-${debug_trace_tag}-${SEQNUM:-0}.XXXXXXXXXX" \
2>/dev/null)"
then
readonly tlg
exec >|"${tlg}" 2>&1
set -x
set
else
unset tlg
fi
declare -gr ID_FILE='@chreiplzfcpmp-id-file@'
declare -gr FW_LOCK_FILE='@chreiplzfcpmp-fwlock-file@'
declare -gA TRAP_EXIT_FN=()
declare -gf trap_exit 1>/dev/null
function trap_exit() {
local fn
for fn in "${TRAP_EXIT_FN[@]}"; do
"${fn}"
done
trap - EXIT
}
trap trap_exit EXIT
# Output variables:
# id_file_unlock_exclusive_create() - call to unlock when finished with
# critical section
#
# XXX: `id_file_lock_*` can't be taken recursively
function id_file_lock_exclusive_create() {
declare -g ID_FILE_LOCK=""
# prevent concurrent file creation
#
# First, open the file defined in ${ID_FILE} for writing; this will
# succeed and create the file only if it doesn't exist already. If the
# file already exist, the first open attempt will fail and we fall
# back to opening it only for reading; this will always succeed if the
# file already exists (the reason why the first attempty failed). In
# both cases store the corresponding file descriptor in
# ${ID_FILE_LOCK}.
#
# XXX: This should be race free.
# open() with O_EXCL... is atomic (we set `noclobber` as shell
# option); at least as long as we talk about a local FS.
if ! { exec {ID_FILE_LOCK}>"${ID_FILE}"; } 2>/dev/null; then
{ exec {ID_FILE_LOCK}<"${ID_FILE}"; } 2>/dev/null \
|| return 1
fi
declare -gf id_file_unlock_exclusive_create 1>/dev/null
function id_file_unlock_exclusive_create() {
if [ -v ID_FILE_LOCK ]; then
sync "${ID_FILE}" 2>/dev/null
# release file and implicitly the lock, if taken
exec {ID_FILE_LOCK}>&-
unset ID_FILE_LOCK
fi
unset "TRAP_EXIT_FN[id_file_unlock_exclusive_create]"
}
TRAP_EXIT_FN+=(
[id_file_unlock_exclusive_create]=id_file_unlock_exclusive_create
)
flock --exclusive --timeout 5 "${ID_FILE_LOCK}" || return 2
return 0
}
# Output variables:
# id_file_unlock_exclusive_no_create() - call to unlock when finished with
# critical section
#
# XXX: `id_file_lock_*` can't be taken recursively
function id_file_lock_exclusive_no_create() {
declare -g ID_FILE_LOCK=""
# Open the file defined in ${ID_FILE} for reading, and store the
# corresponding file descriptor in ${ID_FILE_LOCK}.
#
# XXX: return code is used in `chreipl-fcp-mpath-try-change-ipl-path`
{ exec {ID_FILE_LOCK}<"${ID_FILE}"; } 2>/dev/null || return 1
declare -gf id_file_unlock_exclusive_no_create 1>/dev/null
function id_file_unlock_exclusive_no_create() {
if [ -v ID_FILE_LOCK ]; then
sync "${ID_FILE}" 2>/dev/null
# release file and implicitly the lock, if taken
exec {ID_FILE_LOCK}<&-
unset ID_FILE_LOCK
fi
unset "TRAP_EXIT_FN[id_file_unlock_exclusive_no_create]"
}
TRAP_EXIT_FN+=(
[id_file_unlock_exclusive_no_create]=id_file_unlock_exclusive_no_create
)
flock --exclusive --timeout 5 "${ID_FILE_LOCK}" || return 2
return 0
}
# Output variables:
# id_file_unlock_shared_no_create() - call to unlock when finished with
# critical section
#
# XXX: `id_file_lock_*` can't be taken recursively
function id_file_lock_shared_no_create() {
declare -g ID_FILE_LOCK=""
# Open the file defined in ${ID_FILE} for reading, and store the
# corresponding file descriptor in ${ID_FILE_LOCK}.
{ exec {ID_FILE_LOCK}<"${ID_FILE}"; } 2>/dev/null || return 1
declare -gf id_file_unlock_shared_no_create 1>/dev/null
function id_file_unlock_shared_no_create() {
if [ -v ID_FILE_LOCK ]; then
# release file and implicitly the lock, if taken
exec {ID_FILE_LOCK}<&-
unset ID_FILE_LOCK
fi
unset "TRAP_EXIT_FN[id_file_unlock_shared_no_create]"
}
TRAP_EXIT_FN+=(
[id_file_unlock_shared_no_create]=id_file_unlock_shared_no_create
)
flock --shared --timeout 5 "${ID_FILE_LOCK}" || return 2
return 0
}
# Output variables:
# firmware_unlock_exclusive() - call to unlock when finished with critical section
#
# XXX: `firmware_lock_*` can't be taken recursively
function firmware_lock_exclusive() {
declare -g FIRMWARE_LOCK=""
# Open the file defined in ${FW_LOCK_FILE} for reading, and store the
# corresponding file descriptor in ${FIRMWARE_LOCK} (it doesn't matter
# whether this is a normal file or directory). This file descriptor
# will only be used for locking - not for actual I/O.
{ exec {FIRMWARE_LOCK}<"${FW_LOCK_FILE}"; } 2>/dev/null || return 1
declare -gf firmware_unlock_exclusive 1>/dev/null
function firmware_unlock_exclusive() {
if [ -v FIRMWARE_LOCK ]; then
# release file and implicitly the lock, if taken
exec {FIRMWARE_LOCK}<&-
unset FIRMWARE_LOCK
fi
unset "TRAP_EXIT_FN[firmware_unlock_exclusive]"
}
TRAP_EXIT_FN+=([firmware_unlock_exclusive]=firmware_unlock_exclusive)
flock --exclusive --timeout 5 "${FIRMWARE_LOCK}" || return 2
return 0
}
# Output variables:
# firmware_unlock_shared() - call to unlock when finished with critical section
#
# XXX: `firmware_lock_*` can't be taken recursively
function firmware_lock_shared() {
declare -g FIRMWARE_LOCK=""
# Open the file defined in ${FW_LOCK_FILE} for reading, and store the
# corresponding file descriptor in ${FIRMWARE_LOCK} (it doesn't matter
# whether this is a normal file or directory). This file descriptor
# will only be used for locking - not for actual I/O.
{ exec {FIRMWARE_LOCK}<"${FW_LOCK_FILE}"; } 2>/dev/null || return 1
declare -gf firmware_unlock_shared 1>/dev/null
function firmware_unlock_shared() {
if [ -v FIRMWARE_LOCK ]; then
# release file and implicitly the lock, if taken
exec {FIRMWARE_LOCK}<&-
unset FIRMWARE_LOCK
fi
unset "TRAP_EXIT_FN[firmware_unlock_shared]"
}
TRAP_EXIT_FN+=([firmware_unlock_shared]=firmware_unlock_shared)
flock --shared --timeout 5 "${FIRMWARE_LOCK}" || return 2
return 0
}
# Output variables:
# IPL_TYPE
# IPL_BUSID
# IPL_WWPN
# IPL_LUN
function firmware_get_ipl_information() {
declare -g IPL_TYPE="" IPL_BUSID="" IPL_WWPN="" IPL_LUN=""
# Take lock so we don't see any intermediate state from other helpers
# running in parallel
firmware_lock_shared || return 5
{ read -r IPL_TYPE _ < /sys/firmware/reipl/reipl_type; } 2>/dev/null \
|| return 1
{ read -r IPL_BUSID _ < /sys/firmware/reipl/fcp/device; } 2>/dev/null \
|| return 2
{ read -r IPL_WWPN _ < /sys/firmware/reipl/fcp/wwpn; } 2>/dev/null \
|| return 3
{ read -r IPL_LUN _ < /sys/firmware/reipl/fcp/lun; } 2>/dev/null \
|| return 4
firmware_unlock_shared
# show read values in debug log if enabled
if '@DEBUG@'; then
declare -p IPL_TYPE IPL_BUSID IPL_WWPN IPL_LUN 1>&2
fi
return 0
}
# Input:
# 1: absolute canonical path to the scsi device in sysfs, e.g.:
# /sys/devices/css0/0.0.0014/0.0.1700/host1/rport-1:0-0/target1:0:0/1:0:0:1075789848
# Output variables:
# SDEV_LUN
function sdev_get_lun() {
local sdev="${1}" sdev_lun_str
# bash uses `intmax_t` as width for integer variables, and glibc
# defines this either as `long int` on 64 bit systems, or
# `long long int` on other.
local -i sdev_lun=0 fcp_lun=0
sdev_lun_str="${sdev##*:}"
# e.g.: 1075789848
[[ "${sdev_lun_str}" == +([[:digit:]]) ]] || return 1
# "cast" to integer
sdev_lun="${sdev_lun_str}"
# convert the Linux integer LUN format to the hexadecimal 64 bit T10
# LUN representation format used by many s390x interfaces
(( fcp_lun = (((sdev_lun >> 0) & 0xffff) << 48)
| (((sdev_lun >> 16) & 0xffff) << 32)
| (((sdev_lun >> 32) & 0xffff) << 16)
| (((sdev_lun >> 48) & 0xffff) << 0) ))
# the '0x' prefix is part of the length
printf -v SDEV_LUN "%#018llx" "${fcp_lun}"
# show read values in debug log if enabled
if '@DEBUG@'; then
declare -p SDEV_LUN 1>&2
fi
return 0
}
# Input:
# 1: path to the scsi device in sysfs, e.g.:
# /sys/devices/css0/0.0.0014/0.0.1700/host1/rport-1:0-0/target1:0:0/1:0:0:1075789848
# , or a symlink pointing to the scsi device, e.g.:
# /sys/class/block/sds/device
# Output variables:
# SDEV_BUSID
# SDEV_WWPN
# SDEV_LUN
function sdev_get_fcp_addressing() {
local sdev="${1}" fcp_lun rport rport_wwpn zfcp_dev
declare -g SDEV_BUSID="" SDEV_WWPN="" SDEV_LUN=""
sdev="$(readlink -se "${sdev}")" || return 1
# get the LUN for this SDEV
#
# sets ${SDEV_LUN}
sdev_get_lun "${sdev}" || return 2
# get the WWPN of the remote port this SDEV is attached to
printf -v rport "%s" "${sdev}"/../../fc_remote_ports/rport-*:*-*
# e.g.: /sys/devices/css0/0.0.0016/0.0.1740/host0/rport-0:0-1/fc_remote_ports/rport-0:0-1
[ "${rport}" != "" ] || return 3
# XXX: This works even if the rport is currently in a bad
# state, so e.g. when it has just gone down because of a
# cable pull.
{ read -r rport_wwpn _ < "${rport}"/port_name; } 2>/dev/null \
|| return 4
# The Linux kernel doesn't guarantee the same format as in
# /sys/firmware/..., so make sure it is the one we expect.
[[ "${rport_wwpn}" =~ ^0x[[:xdigit:]]{1,16}$ ]] || return 5
# the '0x' prefix is part of the length
printf -v rport_wwpn "%#018llx" "${rport_wwpn}"
# get the Device Bus-ID of the device via which this SDEV is attached
zfcp_dev="$(readlink -se "${sdev}"/../../../..)" || return 6
# e.g.: /sys/devices/css0/0.0.0016/0.0.1740
zfcp_dev="${zfcp_dev##*/}"
# shellcheck disable=2034
SDEV_BUSID="${zfcp_dev}"
# shellcheck disable=2034
SDEV_WWPN="${rport_wwpn}"
return 0
}
# Input:
# 1: path to the scsi device in sysfs
# Output variables:
# SDEV_WWID
function sdev_get_wwid() {
local sdev="${1}"
local -a wwid
declare -g SDEV_WWID=""
# read the volume identifier without stripping any content
#
# XXX: we can read the WWID file, even if the SDEV is currently not
# operational (e.g.: due to the path has gone away), as long as
# the VPD PG 83 is still cached in the kernel; and the page gets
# only released on SDEV device release.
{ readarray -d "" -t wwid < "${sdev}"/wwid; } 2>/dev/null \
|| return 1
if '@DEBUG@'; then declare -p wwid 1>&2; fi
# test whether we read something
#
# This strips all leading spaces from the beginning of the read WWID
# (until the first non-space or NUL character), and checks whether the
# result is empty.
# Hence, we return early if the WWID consists of only whitespace.
#
# XXX: there could be unexpected characters in the returned ID.
# `scsi_id` from the udev helpers sanitizes the strings it reads
# from the devices, so they can be used in environment variables
# without much danger.
# But we don't export anything here, so it should be fine.
[ "${wwid[0]/#*([[:space:]])}" != "" ] || return 2
# shellcheck disable=2034
SDEV_WWID="${wwid[0]}"
return 0
}
# Input:
# 1: path to the scsi device in sysfs
# Return Value:
# == 0: SDEV referenced by `1` in good state
# != 0: otherwise
function sdev_test_path_state() {
local sdev="${1}" state zfcp_failed zfcp_in_recovery rport port_state
sdev="$(readlink -se "${sdev}")" || return 1
{ read -r state _ < "${sdev}"/state; } 2>/dev/null || return 2
{ read -r zfcp_failed _ < "${sdev}"/zfcp_failed; } 2>/dev/null \
|| return 3
{ read -r zfcp_in_recovery _ < "${sdev}"/zfcp_in_recovery; } 2>/dev/null \
|| return 4
printf -v rport "%s" "${sdev}"/../../fc_remote_ports/rport-*:*-*
# e.g.: /sys/devices/css0/0.0.0016/0.0.1740/host0/rport-0:0-1/fc_remote_ports/rport-0:0-1
[ "${rport}" != "" ] || return 5
{ read -r port_state _ < "${rport}"/port_state; } 2>/dev/null \
|| return 6
if '@DEBUG@'; then
declare -p state zfcp_failed zfcp_in_recovery port_state 1>&2
fi
[ "${state}" = "running" ] || return 7
[ "${zfcp_failed}" = "0" ] || return 8
[ "${zfcp_in_recovery}" = "0" ] || return 9
{ [ "${port_state}" = "Online" ] \
|| [ "${port_state}" = "Marginal" ]; } || return 10
return 0
}
# Input:
# *: all input parameters are used as quoted message
function log_note() {
logger -p 'daemon.notice' -t 'chreipl-fcp-mpath' "${*}" &>/dev/null
}
# Input:
# *: all input parameters are used as quoted message
function log_crit() {
logger -p 'daemon.crit' -t 'chreipl-fcp-mpath' "${*}" &>/dev/null
}
# Input:
# *: all input parameters are used as quoted message
function log_alert() {
logger -p 'daemon.alert' -t 'chreipl-fcp-mpath' "${*}" &>/dev/null
}

View File

@@ -0,0 +1,56 @@
#!/bin/bash
# SPDX-License-Identifier: MIT
#
# chreipl-fcp-mpath: use multipath information to change FCP IPL target
# (C) Copyright IBM Corp. 2021
#
# Uses the following system-utilities (and shell-builtins):
# Those necessary for sourced library:
# - chreipl-fcp-mpath-common.sh
# Find out whether the device in udev event environment variable ${DEVPATH}
# represents the device we want to re-IPL from. We do this by comparing
# Device-Bus-ID/Target-WWPN/LUN of the individual SDEVs to the parameters set
# in `/sys/firmware/reipl/fcp/`.
#
# Makes use of udev event environment variables:
# DM_UUID
# SUBSYSTEM
# DEVPATH
# shellcheck disable=SC2034
declare -gr debug_trace_tag=05iilt
# shellcheck disable=SC1091
source '@chreiplzfcpmp-lib@' || exit 127
firmware_get_ipl_information || exit 1
if [[ "${DM_UUID}" == mpath-* ]]; then
# Assume Multipath Device Mapper Device;
# e.g.: DEVPATH = /devices/virtual/block/dm-0
declare sdev
# depends on `nullglob` from `chreipl-fcp-mpath-common.sh`
for sdev in /sys/"${DEVPATH}"/slaves/sd*/device; do
sdev_get_fcp_addressing "${sdev}" || continue
[ "${SDEV_LUN}" = "${IPL_LUN}" ] || continue
[ "${SDEV_WWPN}" = "${IPL_WWPN}" ] || continue
[ "${SDEV_BUSID}" = "${IPL_BUSID}" ] || continue
exit 0
done
unset sdev
elif [ "${SUBSYSTEM}" = block ]; then
# Assume SCSI Disk;
# e.g.: DEVPATH = /devices/css0/0.0.0014/0.0.1700/host0/rport-0:0-0/target0:0:0/0:0:0:1074806808/block/sds
sdev_get_fcp_addressing /sys/"${DEVPATH}"/device || exit 2
[ "${SDEV_LUN}" = "${IPL_LUN}" ] || exit 3
[ "${SDEV_WWPN}" = "${IPL_WWPN}" ] || exit 4
[ "${SDEV_BUSID}" = "${IPL_BUSID}" ] || exit 5
exit 0
fi
exit 6

View File

@@ -0,0 +1,86 @@
#!/bin/bash
# SPDX-License-Identifier: MIT
#
# chreipl-fcp-mpath: use multipath information to change FCP IPL target
# (C) Copyright IBM Corp. 2021
#
# Uses the following system-utilities (and shell-builtins):
# Those necessary for sourced library:
# - chreipl-fcp-mpath-common.sh
# Find out whether the device in environment variable ${DEVPATH} represents the
# _volume_ that we IPL'ed from. We do this by comparing its WWID to the one
# recorded in `@chreiplzfcpmp-id-file@`.
#
# Makes use of udev event environment variables:
# DM_UUID
# SUBSYSTEM
# DEVPATH
# shellcheck disable=SC2034
declare -gr debug_trace_tag=11iilv
# shellcheck disable=SC1091
source '@chreiplzfcpmp-lib@' || exit 127
function id_file_read_ipl_information() {
local -a records
declare -g REC_WWID="" REC_BUSID="" REC_WWPN="" REC_LUN=""
# lock file before reading ID, so we don't see any intermediate state
id_file_lock_shared_no_create || return 1
{ readarray -d "" -t -u "${ID_FILE_LOCK}" records; } 2>/dev/null \
|| return 2
if '@DEBUG@'; then declare -p records 1>&2; fi
id_file_unlock_shared_no_create
[ "${#records[@]}" = "4" ] || return 3
# check that none of the array fields contains whitespace only
[ "${records[0]/#*([[:space:]])}" != "" ] || return 4
[ "${records[1]/#*([[:space:]])}" != "" ] || return 5
[ "${records[2]/#*([[:space:]])}" != "" ] || return 6
[ "${records[3]/#*([[:space:]])}" != "" ] || return 7
REC_WWID="${records[0]}"
REC_BUSID="${records[1]}"
REC_WWPN="${records[2]}"
REC_LUN="${records[3]}"
return 0
}
id_file_read_ipl_information || exit 1
if [[ "${DM_UUID}" == mpath-* ]]; then
# Assume Multipath Device Mapper Device;
# e.g.: DEVPATH = /devices/virtual/block/dm-0
declare sdev found=false
for sdev in /sys/"${DEVPATH}"/slaves/sd*/device; do
if sdev_get_wwid "${sdev}"; then
found=true
break
fi
done
unset sdev
"${found}" || exit 2
elif [ "${SUBSYSTEM}" = block ]; then
# Assume SCSI Disk;
# e.g.: DEVPATH = /devices/css0/0.0.0014/0.0.1700/host0/rport-0:0-0/target0:0:0/0:0:0:1074806808/block/sds
sdev_get_wwid /sys/"${DEVPATH}"/device || exit 3
fi
# set by `sdev_get_wwid` and `id_file_read_ipl_information`
[ "${SDEV_WWID}" = "${REC_WWID}" ] || exit 4
firmware_get_ipl_information || exit 5
# set by `firmware_get_ipl_information` and `id_file_read_ipl_information`
[ "${IPL_BUSID}" = "${REC_BUSID}" ] || exit 6
[ "${IPL_WWPN}" = "${REC_WWPN}" ] || exit 7
[ "${IPL_LUN}" = "${REC_LUN}" ] || exit 8
exit 0

View File

@@ -0,0 +1,25 @@
#!/bin/bash
# SPDX-License-Identifier: MIT
#
# chreipl-fcp-mpath: use multipath information to change FCP IPL target
# (C) Copyright IBM Corp. 2021
#
# Uses the following system-utilities (and shell-builtins):
# Those necessary for sourced library:
# - chreipl-fcp-mpath-common.sh
# Find out whether ReIPL is gonna happen from a SCSI volume attached via zFCP
# shellcheck disable=SC2034
declare -gr debug_trace_tag=00iriz
# shellcheck disable=SC1091
source '@chreiplzfcpmp-lib@' || exit 127
declare reipl_type
{ read -r reipl_type _ < /sys/firmware/reipl/reipl_type; } 2>/dev/null || exit 1
if '@DEBUG@'; then declare -p reipl_type 1>&2; fi
[ "${reipl_type}" = "fcp" ] || exit 2
exit 0

View File

@@ -0,0 +1,73 @@
#!/bin/bash
# SPDX-License-Identifier: MIT
#
# chreipl-fcp-mpath: use multipath information to change FCP IPL target
# (C) Copyright IBM Corp. 2021
#
# Uses the following system-utilities (and shell-builtins):
# Those necessary for sourced library:
# - chreipl-fcp-mpath-common.sh
# GNU coreutils:
# - truncate
# util-linux:
# - hexdump
# Record the identification of the volume we want to re-IPL from
#
# Makes use of udev event environment variables:
# DM_UUID
# SUBSYSTEM
# DEVPATH
# shellcheck disable=SC2034
declare -gr debug_trace_tag=10rvid
# shellcheck disable=SC1091
source '@chreiplzfcpmp-lib@' || exit 127
function id_file_record_ipl_information() {
local sdev_wwid="${1}" ipl_busid="${2}" ipl_wwpn="${3}" ipl_lun="${4}"
# lock file before writing ID, so noone sees any intermediate state
id_file_lock_exclusive_create || return 1
# reset ID without removing the file (necessary for the locking to work
# properly, since the FD we use for locking is on this file/inode)
truncate --no-create --size=0 "${ID_FILE}" || return 3
echo -ne "${sdev_wwid}\x00${ipl_busid}\x00${ipl_wwpn}\x00${ipl_lun}\x00" \
>>"${ID_FILE}" || return 4
if '@DEBUG@'; then hexdump -vC "${ID_FILE}" 1>&2; fi
id_file_unlock_exclusive_create
return 0
}
if [[ "${DM_UUID}" == mpath-* ]]; then
# Assume Multipath Device Mapper Device;
# e.g.: DEVPATH = /devices/virtual/block/dm-0
declare sdev
for sdev in /sys/"${DEVPATH}"/slaves/sd*/device; do
if sdev_get_wwid "${sdev}"; then
break
fi
done
unset sdev
elif [ "${SUBSYSTEM}" = block ]; then
# Assume SCSI Disk;
# e.g.: DEVPATH = /devices/css0/0.0.0014/0.0.1700/host0/rport-0:0-0/target0:0:0/0:0:0:1074806808/block/sds
sdev_get_wwid /sys/"${DEVPATH}"/device
fi
# shellcheck disable=SC2153
[ "${SDEV_WWID}" != "" ] || exit 1
firmware_get_ipl_information || exit 2
# shellcheck disable=SC2153
id_file_record_ipl_information \
"${SDEV_WWID}" "${IPL_BUSID}" "${IPL_WWPN}" "${IPL_LUN}" \
|| exit 3
exit 0

View File

@@ -0,0 +1,158 @@
#!/bin/bash
# SPDX-License-Identifier: MIT
#
# chreipl-fcp-mpath: use multipath information to change FCP IPL target
# (C) Copyright IBM Corp. 2021
#
# Uses the following system-utilities (and shell-builtins):
# Those necessary for sourced library:
# - chreipl-fcp-mpath-common.sh
# GNU coreutils:
# - truncate
# util-linux:
# - hexdump
# Try to change the current re-IPL target to a dfferent, operational path to
# the same volume.
#
# Makes use of udev event environment variables:
# DM_UUID
# SUBSYSTEM
# DEVPATH
# CHREIPL_FCP_MPATH_IS_TGT
# shellcheck disable=SC2034
declare -gr debug_trace_tag=15tcip
# shellcheck disable=SC1091
source '@chreiplzfcpmp-lib@' || exit 127
function apply_ipl_information() {
local sdev_wwid="${1}"
local sdev_busid="${2}" sdev_wwpn="${3}" sdev_lun="${4}"
local ipl_type="${5}" ipl_busid="${6}" ipl_wwpn="${7}" ipl_lun="${8}"
local -a records
local try_update_id_file=true
[ "${ipl_type}" = "fcp" ] || return 1
[[ "${sdev_busid}" =~ ^[[:xdigit:]]{1,3}\.[[:xdigit:]]\.[[:xdigit:]]{1,4}$ ]] \
|| return 2
[[ "${sdev_wwpn}" =~ ^0x[[:xdigit:]]{16}$ ]] || return 3
[[ "${sdev_lun}" =~ ^0x[[:xdigit:]]{16}$ ]] || return 4
# After updating the firmware re-IPL information below we also try to
# update the information stored in the ID file (necessary, so it
# contains the correct Device-Bus-ID/WWPN/LUN after the update). For
# the update of the ID file we try to grab an exclusive lock, so there
# are no overlapping reads/writes.
#
# In case we can't get the lock because the ID file is missing, but we
# have a direct TGT match, we may still try to change the re-IPL
# information, but skip the ID file update.
#
# "direct match" means, the event subject is either the SDEV that is
# currently set as re-IPL target, or it is the dm-multipath device that
# currently contains the re-IPL target.
if ! id_file_lock_exclusive_no_create; then
# rc == 1 --> could not read ${ID_FILE}
[ "${PIPESTATUS[0]}" -eq 1 ] || return 5
# if true, we are dealing with a direct TGT match
[ "${CHREIPL_FCP_MPATH_IS_TGT}" = "true" ] || return 6
try_update_id_file=false
fi
# If we have a direct match (see in the comment above), we know
# that we have a path to the current re-IPL volume - no matter of the
# WWID. Otherwise, we got here by comparing the WWID of the event
# subject with the one recorded in the ID file; in this case we try to
# make sure the information is still up-to-date.
if [ "${CHREIPL_FCP_MPATH_IS_TGT}" != "true" ]; then
# last bail to make sure we don't overwrite user choices..
#
# XXX: this will *NOT* prevent the race completely, but at least
# make it less likely
{ readarray -d "" -t -u "${ID_FILE_LOCK}" records; } 2>/dev/null \
|| return 7
if '@DEBUG@'; then declare -p records 1>&2; fi
[ "${#records[@]}" = "4" ] || return 8
[ "${records[0]}" = "${sdev_wwid}" ] || return 9
[ "${records[1]}" = "${ipl_busid}" ] || return 10
[ "${records[2]}" = "${ipl_wwpn}" ] || return 11
[ "${records[3]}" = "${ipl_lun}" ] || return 12
fi
# Take lock so we don't see any intermediate state from other helpers
# running in parallel
firmware_lock_exclusive || return 13
if ! { echo "${sdev_busid}" >| /sys/firmware/reipl/fcp/device \
&& echo "${sdev_wwpn}" >| /sys/firmware/reipl/fcp/wwpn \
&& echo "${sdev_lun}" >| /sys/firmware/reipl/fcp/lun; };
then
log_alert "Changing the re-IPL device failed. The current re-IPL settings might be inconsistent. Check and correct the settings (see the README.md of chreipl-fcp-mpath) to make sure that the current re-IPL device is valid."
return 14
fi
firmware_unlock_exclusive
if [ "${sdev_busid}" != "${ipl_busid}" ] \
|| [ "${sdev_wwpn}" != "${ipl_wwpn}" ] \
|| [ "${sdev_lun}" != "${ipl_lun}" ]; then
log_note "Changed re-IPL path to: ${sdev_busid}:${sdev_wwpn}:${sdev_lun}."
fi
# Try to update the information in the ID file if we have gotten the
# lock for it.
if ${try_update_id_file}; then
# reset ID without removing the file
truncate --no-create --size=0 "${ID_FILE}" || return 15
echo -ne "${sdev_wwid}\x00${sdev_busid}\x00${sdev_wwpn}\x00${sdev_lun}\x00" \
>>"${ID_FILE}" || return 16
id_file_unlock_exclusive_no_create
if '@DEBUG@'; then hexdump -vC "${ID_FILE}" 1>&2; fi
fi
return 0
}
declare -g SDEV=""
if [[ "${DM_UUID}" == mpath-* ]]; then
# Assume Multipath Device Mapper Device;
# e.g.: DEVPATH = /devices/virtual/block/dm-0
for sdev in /sys/"${DEVPATH}"/slaves/sd*/device; do
if sdev_test_path_state "${sdev}"; then
SDEV="${sdev}"
break
fi
done
# No path of the multipath-device that represents the IPL volume is
# online.
if [ "${SDEV}" = "" ]; then
log_crit "The re-IPL device cannot be changed because no operational path to the re-IPL volume remains. The next re-IPL might fail unless you re-attach or enable at least one valid path to the re-IPL volume."
fi
elif [ "${SUBSYSTEM}" = block ]; then
# Assume SCSI Disk;
# e.g.: DEVPATH = /devices/css0/0.0.0014/0.0.1700/host0/rport-0:0-0/target0:0:0/0:0:0:1074806808/block/sds
if sdev_test_path_state /sys/"${DEVPATH}"/device; then
SDEV=/sys/"${DEVPATH}"/device
fi
fi
[ "${SDEV}" != "" ] || exit 0
sdev_get_wwid "${SDEV}" || exit 0
sdev_get_fcp_addressing "${SDEV}" || exit 0
firmware_get_ipl_information || exit 0
# shellcheck disable=SC2153
apply_ipl_information \
"${SDEV_WWID}" "${SDEV_BUSID}" "${SDEV_WWPN}" "${SDEV_LUN}" \
"${IPL_TYPE}" "${IPL_BUSID}" "${IPL_WWPN}" "${IPL_LUN}" || exit 0
exit 0

View File

@@ -0,0 +1,93 @@
# SPDX-License-Identifier: MIT
#
# chreipl-fcp-mpath: use multipath information to change FCP IPL target
# (C) Copyright IBM Corp. 2021
#
# Uses the following system-utilities (and shell-builtins):
# Utilities list in GNU Make Conventions:
# https://www.gnu.org/software/make/manual/make.html#Utilities-in-Makefiles
# GNU coreutils:
# - mktemp
# If $(ENABLE_DOC) is `1`:
# Pandoc:
# - pandoc
# GNU coreutils:
# - date
#
## Paths and Build Variables
#
# Install the configuration file for dracut, to automatically pull in the
# toolset into the initial ramdisk, when built with it.
HAVE_DRACUT = 0
# Build documentation; requires: Pandoc
ENABLE_DOC = 0
# https://www.gnu.org/software/make/manual/make.html#Directory-Variables
CHREIPLZFCPMPDIR = $(USRLIBDIR)/chreipl-fcp-mpath
UDEVDIR = $(USRLIBDIR)/udev
UDEVRULESDIR = $(UDEVDIR)/rules.d
UDEVRUNDIR = /run/udev
DRACUTDIR = $(USRLIBDIR)/dracut
DRACUTCONFDIR = $(DRACUTDIR)/dracut.conf.d
DEBUGOUTDIR = $(UDEVRUNDIR)
INSTALL_EXEC = $(INSTALL) -g $(GROUP) -o $(OWNER) --preserve-timestamps
INSTALL_DATA = $(INSTALL_EXEC) --mode=0644
# used for data exchange and synchronization across the different helpers
chreiplzfcpmp-id-file = $(UDEVRUNDIR)/chreiplzfcpmp-ipl-volume-id
# file used to implement mutual exclusion when accessing firmware IPL info:
# - this should be something that is (practically) always available, so we
# dont have to worry about fallbacks or error-handling;
# - at the same time, it should not be used by anything else with flock(2) to
# hold a lock for long periods.
chreiplzfcpmp-fwlock-file = /sys/firmware/reipl
.DELETE_ON_ERROR:
# export build-time definitions to the scripts/built-components
define chreiplzfcpmp-sed-buildvar-replace =
tmpout=$$(mktemp -p ./ .make.tmp.XXXXXXXXXXXXXXXX) && { \
$(SED) -E \
-e 's|@DEBUG@|$(if $(filter 1,$(D)),true,false)|g' \
-e 's|@chreiplzfcpmp-id-file@|$(chreiplzfcpmp-id-file)|g' \
-e 's|@chreiplzfcpmp-fwlock-file@|$(chreiplzfcpmp-fwlock-file)|g' \
-e 's|@chreiplzfcpmp-lib@|$(CHREIPLZFCPMPDIR)/chreipl-fcp-mpath-common.sh|g' \
-e 's|@debugoutdir@|$(DEBUGOUTDIR)|g' \
-e 's|@udevdir@|$(UDEVDIR)|g' \
-e 's|@udevrulesdir@|$(UDEVRULESDIR)|g' \
$(1) > $${tmpout} \
&& mv $${tmpout} $(2) \
|| { rm $${tmpout}; false; } \
; }
endef
.PHONY: clean-mk-temp
clean: clean-mk-temp
clean-mk-temp:
rm -f .make.tmp.[[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]]
# Definitions for generating documentation when $(ENABLE_DOC) is set to `1`
PANDOCFLAGS = --fail-if-warnings
ALL_PANDOCFLAGS = --preserve-tabs --tab-stop=8 --strip-comments \
--standalone --self-contained \
-M date="$(shell date +'%Y-%m-%d')" \
$(PANDOCFLAGS)
$(eval $(call cmd_define, PANDOC," PANDOC ",pandoc))
%.html : ALL_PANDOCFLAGS += -t html
%.html : %.md
$(PANDOC) $(ALL_PANDOCFLAGS) -f gfm -o $(@) $(<)
%.pdf : ALL_PANDOCFLAGS += -t latex --toc
%.pdf : %.md
$(PANDOC) $(ALL_PANDOCFLAGS) -f gfm -o $(@) $(<)
%.7 : ALL_PANDOCFLAGS += -t man
%.7 : %.md
$(PANDOC) $(ALL_PANDOCFLAGS) -f gfm -o $(@) $(<)

View File

@@ -0,0 +1,16 @@
# SPDX-License-Identifier: MIT
#
# chreipl-fcp-mpath: use multipath information to change FCP IPL target
# (C) Copyright IBM Corp. 2021
add_dracutmodules+=" bash multipath udev-rules "
install_items+=" @udevrulesdir@/70-chreipl-fcp-mpath.rules "
install_items+=" @chreiplzfcpmp-lib@ "
install_items+=" @udevdir@/chreipl-fcp-mpath-is-ipl-tgt "
install_items+=" @udevdir@/chreipl-fcp-mpath-is-ipl-vol "
install_items+=" @udevdir@/chreipl-fcp-mpath-is-reipl-zfcp "
install_items+=" @udevdir@/chreipl-fcp-mpath-record-volume-identifier "
install_items+=" @udevdir@/chreipl-fcp-mpath-try-change-ipl-path "
install_items+=" flock hexdump logger mktemp readlink sync truncate "

View File

@@ -0,0 +1,101 @@
# SPDX-License-Identifier: MIT
#
# chreipl-fcp-mpath: use multipath information to change FCP IPL target
# (C) Copyright IBM Corp. 2021
# Did the event affect a multipath or scsi disk device?
ACTION=="change", KERNEL=="dm-[0-9]*", SUBSYSTEM=="block", \
ENV{DM_UUID}=="mpath-*", ENV{DM_ACTION}=="PATH_FAILED", \
GOTO="chreipl_fcp_mpath_path_change"
ACTION=="change", KERNEL=="dm-[0-9]*", SUBSYSTEM=="block", \
ENV{DM_UUID}=="mpath-*", ENV{DM_ACTION}=="PATH_REINSTATED", \
GOTO="chreipl_fcp_mpath_path_change"
ACTION=="add", KERNEL=="sd[a-z]*", SUBSYSTEM=="block", \
GOTO="chreipl_fcp_mpath_path_change"
GOTO="chreipl_fcp_mpath_end"
LABEL="chreipl_fcp_mpath_path_change"
# Is this system IPL'ed (IOW, are we on s390x)? And do we ReIPL via zFCP?
#
# udev(7): If no absolute path is given, the program is expected to live
# in /usr/lib/udev; otherwise, the absolute path must be
# specified.
TEST!="/sys/firmware/ipl", GOTO="chreipl_fcp_mpath_end"
PROGRAM!="chreipl-fcp-mpath-is-reipl-zfcp", GOTO="chreipl_fcp_mpath_end"
# Consider the following scenarios.
# Either:
#
# (A) We recognized a new SCSI Disk. This might represent:
# (a) the path we want to ReIPL from;
# (b) an alternative path to the volume we want to ReIPL from;
# (c) a path to some unrelated volume.
#
# Or:
#
# (B) We recognized a PATH_ event for a multipath device. This might represent:
# the path we want to ReIPL from:
# (a) went away;
# (b) came back online;
# an alternative path to the volume we want to ReIPL from:
# (c) went away;
# (d) came back online;
# (e) some unrelated multipath device saw an event.
# Test whether the affected device is, or contains, the current IPL target.
#
# This covers scenarios:
# (A) (a),
# (B) (a)/(b)/(c)/(d)
PROGRAM!="chreipl-fcp-mpath-is-ipl-tgt", \
ENV{CHREIPL_FCP_MPATH_IS_TGT}="false", \
GOTO="chreipl_fcp_mpath_not_direct_match"
ENV{CHREIPL_FCP_MPATH_IS_TGT}="true"
# Record the WWID, Device-Bus-ID, Remote WWPN, and LUN of the ReIPL target
# (see `chreipl-fcp-mpath-is-ipl-vol` for usecases). This information
# might change, depending on whether the machine operator changes the ReIPL
# target to a different volume.
#
# XXX: Because the kernel doesn't generate any events upon changing of
# the ReIPL target, the chreipl-fcp-mpath toolset can't take any
# actions until the next path event for the new target is
# generated. Following that, we assume that when the machine
# operator changes the ReIPL target, the new target is reachable
# and in a good state at this point in time.
PROGRAM!="chreipl-fcp-mpath-record-volume-identifier", \
GOTO="chreipl_fcp_mpath_try_change_ipl_path"
GOTO="chreipl_fcp_mpath_try_change_ipl_path"
# If the even subject is not a direct match (not the sdev that is the current
# ReIPL target, and not a mpath device that contains the current ReIPL target)
LABEL="chreipl_fcp_mpath_not_direct_match"
# While this sdev/mpath device doesn't directly correspond to the path
# currently set as ReIPL target, it might still point to the same volume.
#
# For mpath devices this can happen if the original ReIPL target is completely
# gone from the machine, and so there is no way we can successfully, directly
# compare the ReIPL parameters to the sdevs of the mpath device.
#
# For cases like these we recorded the volume identifier, which we now can
# compare, and so still decide whether we are addressing the correct volume.
#
# This covers scenarios:
# (A) (b)/(c),
# (B) (c)/(d)/(e)
#
# XXX: we recorded WWID, Device-Bus-ID, Remote WWPN, LUN of the ReIPL target at
# the time; if the latter three don't match the current ReIPL setting
# anymore, we have to assume that someone changed the ReIPL target
# manually, and we cannot use the WWID anymore since we can't possibly
# know whether that stayed the same when the change was done.
PROGRAM!="chreipl-fcp-mpath-is-ipl-vol", GOTO="chreipl_fcp_mpath_end"
# We are here because of scenarios:
# (A) (a)/(b),
# (B) (a)/(b)/(c)/(d)
LABEL="chreipl_fcp_mpath_try_change_ipl_path"
RUN{program}+="chreipl-fcp-mpath-try-change-ipl-path"
LABEL="chreipl_fcp_mpath_end"

View File

@@ -16,17 +16,18 @@ check_dep:
$(call check_dep, \
"cmsfs-fuse", \
"fuse.h", \
"fuse-devel or libfuse-dev", \
"HAVE_FUSE=0")
"fuse3-devel or libfuse3-dev", \
"HAVE_FUSE=0", \
"-DFUSE_USE_VERSION=30")
all: check_dep cmsfs-fuse
ifneq ($(shell sh -c 'command -v pkg-config'),)
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse)
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse)
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse3)
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse3)
else
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse
FUSE_LDLIBS = -lfuse
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse3
FUSE_LDLIBS = -lfuse3
endif
ALL_CFLAGS += -DHAVE_SETXATTR $(FUSE_CFLAGS)
LDLIBS += $(FUSE_LDLIBS) -lm

View File

@@ -80,9 +80,6 @@ Allow access by other users
\fB\-o\fR allow_root
Allow access by root
.TP
\fB\-o\fR nonempty
Allow mounts over non\-empty file/dir
.TP
\fB\-o\fR default_permissions
Enable permission checking by kernel
.TP

View File

@@ -9,7 +9,7 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#define FUSE_USE_VERSION 26
#define FUSE_USE_VERSION 30
#include <assert.h>
#include <ctype.h>
#include <errno.h>
@@ -1516,7 +1516,7 @@ static void walk_dir_block(struct fst_entry *fst, struct walk_file *walk,
decode_edf_name(file, fst->name, fst->type);
if (!file_unlinked(file)) {
cache_fst_addr(walk->addr, file);
walk->filler(walk->buf, file, NULL, 0);
walk->filler(walk->buf, file, NULL, 0, 0);
}
}
}
@@ -1728,8 +1728,11 @@ static off_t get_file_size_logical(struct fst_entry *fst)
return total;
}
static int cmsfs_getattr(const char *path, struct stat *stbuf)
static int cmsfs_getattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi)
{
(void) fi;
int mask = (cmsfs.allow_other) ? 0444 : 0440;
struct fst_entry fst;
@@ -1783,13 +1786,15 @@ static int cmsfs_getattr(const char *path, struct stat *stbuf)
}
static int cmsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
off_t offset, struct fuse_file_info *fi,
enum fuse_readdir_flags flags)
{
struct walk_file walk;
struct fst_entry fst;
(void) offset;
(void) fi;
(void) flags;
/*
* Offset is ignored and 0 passed to the filler fn so the whole
@@ -1800,8 +1805,8 @@ static int cmsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
if (strcmp(path, "/") != 0)
return -ENOENT;
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, ".", NULL, 0, 0);
filler(buf, "..", NULL, 0, 0);
memset(&walk, 0, sizeof(walk));
/* readdir is possible without open so fi->fh is not set */
@@ -2683,13 +2688,16 @@ static int cmsfs_statfs(const char *path, struct statvfs *buf)
return 0;
}
static int cmsfs_utimens(const char *path, const struct timespec ts[2])
static int cmsfs_utimens(const char *path, const struct timespec ts[2],
struct fuse_file_info *fi)
{
struct fst_entry fst;
off_t fst_addr;
struct tm tm;
int rc;
(void) fi;
if (cmsfs.readonly)
return -EACCES;
@@ -2825,7 +2833,8 @@ error:
return rc;
}
static int cmsfs_rename(const char *path, const char *new_path)
static int cmsfs_rename(const char *path, const char *new_path,
unsigned int flags)
{
struct fst_entry fst, fst_new;
off_t fst_addr, fst_addr_new;
@@ -2835,6 +2844,8 @@ static int cmsfs_rename(const char *path, const char *new_path)
struct file *f;
int rc;
(void) flags;
if (cmsfs.readonly)
return -EACCES;
@@ -3232,13 +3243,16 @@ static void update_fst(struct file *f, off_t addr)
unhide_null_blocks(f);
}
static int cmsfs_truncate(const char *path, off_t size)
static int cmsfs_truncate(const char *path, off_t size,
struct fuse_file_info *fi)
{
struct fst_entry fst;
off_t fst_addr, len;
struct file *f;
int rc = 0;
(void) fi;
if (cmsfs.readonly)
return -EROFS;

View File

@@ -5,7 +5,7 @@ COMMON_INCLUDED = true
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
VERSION = 2
RELEASE = 17
RELEASE = 20
PATCHLEVEL = 0
DISTRELEASE = build-$(shell date +%Y%m%d)
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
@@ -182,6 +182,7 @@ USRSBINDIR = $(INSTALLDIR)/usr/sbin
USRBINDIR = $(INSTALLDIR)/usr/bin
BINDIR = $(INSTALLDIR)/sbin
LIBDIR = $(INSTALLDIR)/lib
USRLIBDIR = $(INSTALLDIR)/usr/lib
USRLIB64DIR = $(INSTALLDIR)/usr/lib64
SYSCONFDIR = $(INSTALLDIR)/etc
MANDIR = $(INSTALLDIR)/usr/share/man
@@ -206,10 +207,10 @@ INSTDIRS = $(USRSBINDIR) $(USRBINDIR) $(BINDIR) $(LIBDIR) $(MANDIR) \
$(TOOLS_LIBDIR) $(TOOLS_DATADIR) \
$(ZFCPDUMP_DIR) $(SYSTEMDSYSTEMUNITDIR) \
$(USRLIB64DIR) $(USRINCLUDEDIR) $(ZKEYKMSPLUGINDIR) \
$(SOINSTALLDIR)
$(SOINSTALLDIR) $(USRLIBDIR)
OWNER = $(shell id -un)
GROUP = $(shell id -gn)
export INSTALLDIR BINDIR LIBDIR USRLIB64DIR MANDIR OWNER GROUP
export INSTALLDIR BINDIR LIBDIR USRLIBDIR USRLIB64DIR MANDIR OWNER GROUP
# Special defines for zfcpdump
ZFCPDUMP_IMAGE = zfcpdump-image

View File

@@ -17,6 +17,7 @@
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <linux/limits.h>
#include <stdarg.h>
#include <stdbool.h>
@@ -45,15 +46,15 @@
#define CPUS_POSSIBLE "/sys/devices/system/cpu/possible"
#define CPUS_KERNELMAX "/sys/devices/system/cpu/kernel_max"
#define MAXCTRS 512
#define IOCTLSLEEP 60U
static const unsigned int ioctlsleep = 60;
static unsigned int read_interval = ioctlsleep, cfvn, csvn, authorization;
static unsigned int read_interval = IOCTLSLEEP, cfvn, csvn, authorization;
static unsigned long loop_count = 1;
static unsigned char *ioctlbuffer;
static bool allcpu;
static unsigned int max_possible_cpus; /* No of possible CPUs */
struct ctrname { /* List of defined counters */
static struct ctrname { /* List of defined counters */
char *name; /* Counter name */
bool hitcnt; /* Counter number read from ioctl() */
unsigned long total; /* Total counter value */
@@ -240,7 +241,7 @@ static char *show_ctrset(unsigned long set)
/* Parse CPU list and counter sets */
static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
{
__u64 *words = start->cpumask;
uint64_t *words = start->cpumask;
unsigned long i, no_a, no_b;
char *cp, *tokens[16]; /* Used to parse command line params */
char cpubuf[256];
@@ -275,8 +276,8 @@ static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
show_ctrset(noton));
}
for (i = 0; i < ARRAY_SIZE(tokens) && (tokens[i] = strtok(parm, ",")) != 0;
++i, parm = 0) {
for (i = 0; i < ARRAY_SIZE(tokens) && (tokens[i] = strtok(parm, ","));
++i, parm = NULL) {
cp = strchr(tokens[i], '-'); /* Range character? */
if (cp) {
no_a = getnumber(tokens[i], *cp);
@@ -292,19 +293,13 @@ static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
/* Convert the CPU list to a bitmask for kernel cpumask_t */
for (i = 0, no_b = 0; i < max_possible_cpus; ++i) {
if (check[i].cpu_req) {
no_a = i % __BITS_PER_LONG;
no_b = i / __BITS_PER_LONG;
no_a = i % LONG_BIT;
no_b = i / LONG_BIT;
words[no_b] |= 1ULL << no_a;
}
}
/* no_b is highest used index, swap array */
start->cpumask_len = (no_b + 1) * 8;
for (no_a = 0; no_a < no_b; ++no_a, --no_b) {
__u64 tmp = words[no_a];
words[no_a] = words[no_b];
words[no_b] = tmp;
}
/* no_b is highest used index */
start->cpumask_len = (no_b + 1) * CHAR_BIT;
start->version = S390_HWCTR_START_VERSION;
}
@@ -326,7 +321,7 @@ static bool check_setpossible(void)
}
parm = cpubuf;
for (i = 0; i < ARRAY_SIZE(tokens) && (tokens[i] = strtok(parm, ","));
++i, parm = 0) {
++i, parm = NULL) {
cp = strchr(tokens[i], '-');
if (cp) { /* Range */
no_a = getnumber(tokens[i], *cp);
@@ -525,7 +520,7 @@ static int test_read(struct s390_hwctr_read *read)
}
/* Iterate over all counters in each set */
for (unsigned int k = 0; k < sp->no_cnts; ++k) {
__u64 value;
uint64_t value;
void *addr = base + offset;
size_t idx = ctrset_offset(sp->set) + k;
@@ -608,8 +603,8 @@ static int do_it(char *s)
int rc;
memset(&start, 0, sizeof(start));
rc = max_possible_cpus / sizeof(__u64);
start.cpumask = alloca(max_possible_cpus / sizeof(__u64));
rc = max_possible_cpus / sizeof(uint64_t);
start.cpumask = alloca(max_possible_cpus / sizeof(uint64_t));
memset(start.cpumask, 0, rc);
parse_cpulist(s, &start);
errno = 0;

View File

@@ -13,6 +13,7 @@
#ifndef LSHWC_H
#define LSHWC_H
#include <stdint.h>
#include <sys/ioctl.h>
enum {
@@ -58,27 +59,27 @@ enum {
*/
struct s390_hwctr_start { /* Set CPUs to operate on */
__u64 version; /* Version of interface */
__u64 data_bytes; /* # of bytes required */
__u64 cpumask_len; /* Length of CPU mask in bytes */
__u64 *cpumask; /* Pointer to CPU mask */
__u64 counter_sets; /* Bit mask of counter set to get */
uint64_t version; /* Version of interface */
uint64_t data_bytes; /* # of bytes required */
uint64_t cpumask_len; /* Length of CPU mask in bytes */
uint64_t *cpumask; /* Pointer to CPU mask */
uint64_t counter_sets; /* Bit mask of counter set to get */
};
struct s390_hwctr_setdata { /* Counter set data */
__u32 set; /* Counter set number */
__u32 no_cnts; /* # of counters stored in cv[] */
__u64 cv[0]; /* Counter values (variable length) */
uint32_t set; /* Counter set number */
uint32_t no_cnts; /* # of counters stored in cv[] */
uint64_t cv[0]; /* Counter values (variable length) */
};
struct s390_hwctr_cpudata { /* Counter set data per CPU */
__u32 cpu_nr; /* Counter set number */
__u32 no_sets; /* # of counters sets in data[] */
uint32_t cpu_nr; /* Counter set number */
uint32_t no_sets; /* # of counters sets in data[] */
struct s390_hwctr_setdata data[0];
};
struct s390_hwctr_read { /* Structure to get all ctr sets */
__u64 no_cpus; /* Total # of CPUs data taken from */
uint64_t no_cpus; /* Total # of CPUs data taken from */
struct s390_hwctr_cpudata data[0];
};

View File

@@ -110,6 +110,7 @@ static struct util_opt dump2tar_opts[] = {
{
.option = { "file-timeout", required_argument, NULL, 'T' },
.desc = "Stop reading file after SEC seconds",
.argument = "SEC",
},
{
.option = { "file-max-size", required_argument, NULL, 'M' },

View File

@@ -28,13 +28,23 @@ static inline void __noreturn load_psw(struct psw_t psw)
;
}
static unsigned long get_kernel_cmdline_size(void)
{
unsigned long size = *(volatile unsigned long *)MAX_COMMAND_LINE_SIZE;
if (size != 0)
return size;
return LEGACY_COMMAND_LINE_SIZE;
}
void __noreturn start(void)
{
volatile struct stage3b_args *args = &loader_parms;
volatile struct memblob *kernel = &args->kernel;
volatile struct memblob *cmdline = &args->cmdline;
volatile struct memblob *initrd = &args->initrd;
volatile struct psw_t psw = args->psw;
struct psw_t psw = args->psw;
/* set up ASCII and line-mode */
sclp_setup(SCLP_LINE_ASCII_INIT);
@@ -42,14 +52,14 @@ void __noreturn start(void)
if (kernel->size < IMAGE_LOAD_ADDRESS)
panic(EINTERNAL, "Invalid kernel\n");
if (cmdline->size > COMMAND_LINE_SIZE)
panic(EINTERNAL, "Command line is too large\n");
/* move the kernel and cut the kernel header */
memmove((void *)IMAGE_LOAD_ADDRESS,
(void *)(kernel->src + IMAGE_LOAD_ADDRESS),
kernel->size - IMAGE_LOAD_ADDRESS);
if (cmdline->size > get_kernel_cmdline_size())
panic(EINTERNAL, "Command line is too large\n");
/* move the kernel cmdline */
memmove((void *)COMMAND_LINE,
(void *)cmdline->src,

View File

@@ -248,19 +248,6 @@ gint pv_component_align(PvComponent *component, const gchar *tmp_path,
g_assert_not_reached();
}
/* Convert uint64_t address to byte array */
static void uint64_to_uint8_buf(uint8_t dst[8], uint64_t addr)
{
uint8_t *p = (uint8_t *)&addr;
g_assert(dst);
for (gint i = 0; i < 8; i++) {
/* cppcheck-suppress objectIndex */
dst[i] = p[i];
}
}
int64_t pv_component_update_ald(const PvComponent *comp, EVP_MD_CTX *ctx,
GError **err)
{
@@ -273,11 +260,8 @@ int64_t pv_component_update_ald(const PvComponent *comp, EVP_MD_CTX *ctx,
do {
uint64_t cur_be = GUINT64_TO_BE(cur);
uint8_t addr_buf[8];
uint64_to_uint8_buf(addr_buf, cur_be);
if (EVP_DigestUpdate(ctx, addr_buf, sizeof(addr_buf)) != 1) {
if (EVP_DigestUpdate(ctx, &cur_be, sizeof(cur_be)) != 1) {
g_set_error(err, PV_CRYPTO_ERROR,
PV_CRYPTO_ERROR_INTERNAL,
_("EVP_DigestUpdate failed"));

View File

@@ -440,7 +440,7 @@ static int check_signature_algo_match(const EVP_PKEY *pkey, const X509 *subject,
static X509_CRL *load_crl_from_bio(BIO *bio)
{
g_autoptr(X509_CRL) crl = PEM_read_bio_X509_CRL(bio, NULL, 0, NULL);
g_autoptr(X509_CRL) crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL);
gint rc;
if (crl)

View File

@@ -16,17 +16,17 @@ check_dep:
$(call check_dep, \
"hmcdrvfs", \
"fuse.h", \
"fuse-devel or libfuse-dev", \
"fuse3-devel or libfuse3-dev", \
"HAVE_FUSE=0")
ifneq ($(shell sh -c 'command -v pkg-config'),)
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse)
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse)
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse3)
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse3)
else
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse
FUSE_LDLIBS = -lfuse
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse3
FUSE_LDLIBS = -lfuse3
endif
ALL_CFLAGS += -DFUSE_USE_VERSION=26 -D_LARGEFILE_SOURCE $(FUSE_CFLAGS)
ALL_CFLAGS += -DFUSE_USE_VERSION=30 -D_LARGEFILE_SOURCE $(FUSE_CFLAGS)
LDLIBS += $(FUSE_LDLIBS) -lpthread -lrt -ldl -lm
OBJECTS = hmcdrvfs.o

View File

@@ -111,9 +111,6 @@ allow access by other users
.B -o allow_root
allow access by root
.TP
.B -o nonempty
allow mounts over non-empty file/dir
.TP
.B -o default_permissions
enable permission checking by kernel
.TP

View File

@@ -990,7 +990,7 @@ static int hmcdrv_cache_dir(const char *dir, fuse_fill_dir_t filler, void *buf)
hmcdrv_cache_refresh(path, &st, symlink);
if ((filler != NULL) &&
(filler(buf, fname, &st, 0) != 0))
(filler(buf, fname, &st, 0, 0) != 0))
filler = NULL; /* stop filling */
#ifdef DEBUG
strftime(symlink, sizeof(symlink),
@@ -1109,7 +1109,8 @@ static struct hmcdrv_fuse_file *hmcdrv_file_get(const char *path)
*
* Note: The most important function which FUSE calls (very often).
*/
static int hmcdrv_fuse_getattr(const char *path, struct stat *stbuf)
static int hmcdrv_fuse_getattr(const char *path, struct stat *stbuf,
struct fuse_file_info *UNUSED(fi))
{
struct hmcdrv_fuse_file *fp;
int rc = 0;
@@ -1175,12 +1176,13 @@ static int hmcdrv_fuse_opendir(const char *UNUSED(path),
*/
static int hmcdrv_fuse_readdir(const char *path, void *buf,
fuse_fill_dir_t filler, off_t UNUSED(offset),
struct fuse_file_info *UNUSED(fi))
struct fuse_file_info *UNUSED(fi),
enum fuse_readdir_flags UNUSED(flags))
{
int ret;
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, ".", NULL, 0, 0);
filler(buf, "..", NULL, 0, 0);
pthread_mutex_lock(&hmcdrv_ctx.mutex);
ret = hmcdrv_cache_dir(path, filler, buf);
@@ -1232,7 +1234,8 @@ static int hmcdrv_fuse_read(const char *path, char *buf, size_t size,
* Return: value to be passed in the private_data field of fuse_context to
* all file operations and as a parameter to the destroy() method
*/
static void *hmcdrv_fuse_init(struct fuse_conn_info *UNUSED(conn))
static void *hmcdrv_fuse_init(struct fuse_conn_info *UNUSED(conn),
struct fuse_config *UNUSED(cfg))
{
pthread_mutexattr_t attr;

View File

@@ -23,11 +23,11 @@ else # HAVE_FUSE
# FUSE
#
ifneq ($(shell sh -c 'command -v pkg-config'),)
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse)
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse)
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse3)
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse3)
else
FUSE_CFLAGS = -I/usr/include/fuse
FUSE_LDLIBS = -lfuse
FUSE_CFLAGS = -I/usr/include/fuse3
FUSE_LDLIBS = -lfuse3
endif
#
@@ -67,8 +67,10 @@ check-dep-fuse:
$(call check_dep, \
"hsavmcore", \
"fuse.h", \
"fuse-devel or libfuse-dev", \
"HAVE_FUSE=0")
"fuse3-devel or libfuse3-dev", \
"HAVE_FUSE=0", \
"-DFUSE_USE_VERSION=30")
touch check-dep-fuse
install: all
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 hsavmcore \
@@ -81,6 +83,6 @@ install: all
endif # HAVE_FUSE
clean:
rm -f hsavmcore $(objects)
rm -f hsavmcore $(objects) check-dep-fuse
.PHONY: all install clean

View File

@@ -15,7 +15,7 @@ sudo reboot
## Dependencies
```shell
sudo dnf install -y fuse fuse-devel systemd-devel
sudo dnf install -y fuse3 fuse3-devel systemd-devel
```
## Build hsavmcore

View File

@@ -18,7 +18,7 @@ sudo reboot
## Dependencies
```shell
sudo zypper install -y fuse fuse-devel systemd-devel
sudo zypper install -y fuse3 fuse3-devel systemd-devel
```
## Build hsavmcore

View File

@@ -11,7 +11,7 @@
## Dependencies
```shell
sudo apt-get install -y make gcc kdump-tools fuse libfuse-dev libsystemd-dev
sudo apt-get install -y make gcc kdump-tools fuse3 libfuse3-dev libsystemd-dev
```
## Build hsavmcore

View File

@@ -15,7 +15,7 @@
#include <fcntl.h>
#include <unistd.h>
#define FUSE_USE_VERSION 26
#define FUSE_USE_VERSION 30
#include <fuse.h>
#include "lib/util_log.h"
@@ -31,8 +31,11 @@ struct vmcore_overlay {
bool fuse_debug;
};
static int vmcore_fuse_getattr(const char *path, struct stat *stbuf)
static int vmcore_fuse_getattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi)
{
(void)fi;
struct vmcore_overlay *overlay = fuse_get_context()->private_data;
int ret = 0;
@@ -54,18 +57,20 @@ static int vmcore_fuse_getattr(const char *path, struct stat *stbuf)
static int vmcore_fuse_readdir(const char *path, void *buf,
fuse_fill_dir_t filler, off_t offset,
struct fuse_file_info *fi)
struct fuse_file_info *fi,
enum fuse_readdir_flags flags)
{
(void)offset;
(void)fi;
(void)flags;
if (strcmp(path, ROOT_DIR) != 0)
return -ENOENT;
/* We have only one file */
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, VMCORE_FILE, NULL, 0);
filler(buf, ".", NULL, 0, 0);
filler(buf, "..", NULL, 0, 0);
filler(buf, VMCORE_FILE, NULL, 0, 0);
return 0;
}

430
hsci/hsci
View File

@@ -11,11 +11,36 @@
hsdev=""
ndev=""
hsci=""
hsdev_mac=""
hscibr=""
hscibp=""
hsci_mac=""
hsif_pnetid=""
netif_pnetid=""
hsci_pnetid=""
##############################################################################
# Concept:
# --------
# | hsci |
# --------
# / \
# -------- --------
# | ndev | | hsdev |
# -------- --------
#
# Detail (bridge w/ bridgeports):
# --------
# | hsci |
# --------
# |
# ----------------------
# | |hsci-bp| |
# | hsci-br --------- |
# | |
# -------- -------- |
# | ndev | | hsdev | |
# ----------------------
function usage {
cat <<-EOD
Usage: hsci COMMAND [OPTION]
@@ -42,50 +67,53 @@ function prereqs_check {
fi
}
function get_pnetid {
local netdev=$1
local pnetid=""
#### ROCE:
if [ -e /sys/class/net/$netdev/device/util_string ]; then
pnetids="$(cat /sys/class/net/$netdev/device/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
else
#### OSA /HiperSockets:
if [ -e /sys/class/net/$netdev/device/chpid ]; then
chpid="$(cat /sys/class/net/$netdev/device/chpid | tr [:upper:] [:lower:])"
pnetids="$(cat /sys/devices/css0/chp0.$chpid/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
fi
fi
if [ "$pnetids" != "" ]; then
port_if="$(cat /sys/class/net/$netdev/dev_port)"
(( idx=16*$port_if+1 ))
(( end=$idx+15 ))
pnetid="$(echo "$pnetids" | cut -c $idx-$end | tr -d ' ')"
fi
echo $pnetid
}
function check_pnetids {
# get PNETID of the HS
local hsif_pnetids=""
local netif_pnetids=""
if [ -e /sys/class/net/$hsdev/device/util_string ]; then
hsif_pnetids="$(cat /sys/class/net/$hsdev/device/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
if [ "$hsdev" != "" ]; then
hsif_pnetid="$(get_pnetid $hsdev)"
else
if [ -e /sys/class/net/$hsdev/device/chpid ]; then
chpid="$(cat /sys/class/net/$hsdev/device/chpid | tr [:upper:] [:lower:])"
hsif_pnetids="$(cat /sys/devices/css0/chp0.$chpid/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
fi
hsif_pnetid=""
fi
if [ "$hsif_pnetids" != "" ]; then
port_hsif="$(cat /sys/class/net/$hsdev/dev_port)"
(( idx=16*$port_hsif+1 ))
(( end=$idx+15 ))
hsif_pnetid="$(echo "$hsif_pnetids" | cut -c $idx-$end | tr -d ' ')"
fi
# get PNETID of the NET_DEV
if [ -e /sys/class/net/$ndev/device/util_string ]; then
netif_pnetids="$(cat /sys/class/net/$ndev/device/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
if [ "$ndev" != "" ]; then
netif_pnetid="$(get_pnetid $ndev)"
else
if [ -e /sys/class/net/$ndev/device/chpid ]; then
chpid="$(cat /sys/class/net/$ndev/device/chpid | tr [:upper:] [:lower:])"
netif_pnetids="$(cat /sys/devices/css0/chp0.$chpid/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
fi
fi
if [ "$netif_pnetids" != "" ]; then
port_netif="$(cat /sys/class/net/$ndev/dev_port)"
(( idx=16*$port_netif+1 ))
(( end=$idx+15 ))
netif_pnetid="$(echo "$netif_pnetids" | cut -c $idx-$end | tr -d ' ')"
netif_pnetid=""
fi
#Check PNETIDs
if [ "$hsif_pnetid" != "" ] && [ "$netif_pnetid" != "" ] && [ "$netif_pnetid" != "$hsif_pnetid" ]; then
echo "Error: $hsdev and $ndev have different PNETIDs! They are $hsif_pnetid and $netif_pnetid respectively" >&2
return 1
fi
if [ "$hsif_pnetid" != "" ] && [ "$netif_pnetid" != "" ] && [ "$netif_pnetid" == "$hsif_pnetid" ]; then
hsci_pnetid=$hsif_pnetid
else
if [ "$hsif_pnetid" != "" ]; then
hsci_pnetid=$hsif_pnetid
else
hsci_pnetid=$netif_pnetid
fi
return 0
fi
}
@@ -96,11 +124,11 @@ function verify_precon {
echo "Error: $hsdev does not exist" >&2
return 1
fi
if [ "$(cat /sys/class/net/$hsdev/device/card_type)" != "HiperSockets" ]; then
if [ "$(cat /sys/class/net/$hsdev/device/card_type 2>/dev/null)" != "HiperSockets" ]; then
echo "Error: $hsdev is not a HiperSockets device" >&2
return 1
fi
if [ "$(cat /sys/class/net/$hsdev/device/layer2)" != "1" ]; then
if [ "$(cat /sys/class/net/$hsdev/device/layer2 2>/dev/null)" != "1" ]; then
echo "Error: $hsdev is not in layer 2 mode" >&2
return 1
fi
@@ -108,7 +136,7 @@ function verify_precon {
echo "Error: Missing vnic-characteristics support" >&2
return 1
fi
if [ "$(cat /sys/class/net/$hsdev/device/vnicc/bridge_invisible)" == "n/a" ]; then
if [ "$(cat /sys/class/net/$hsdev/device/vnicc/bridge_invisible 2>/dev/null)" == "n/a" ]; then
echo "Error: $hsdev does not support vnicc" >&2
return 1
fi
@@ -121,8 +149,10 @@ function verify_precon {
return 1
fi
if [ $(ip link show $hsdev | grep master | wc -l) -ne 0 ]; then
echo "Error: $hsdev is already a bridge port" >&2
return 1
if [ $(ip link show $hsdev | grep "master $hsci" | wc -l) -eq 0 ]; then
echo "Error: $hsdev is already a subordinate to another master" >&2
return 1
fi
fi
#Pre-verify net_dev
@@ -130,17 +160,15 @@ function verify_precon {
echo "Error: $ndev does not exist" >&2
return 1
fi
if [ "$(cat /sys/class/net/$ndev/device/card_type)" == "HiperSockets" ]; then
echo "Error: $ndev is also a HiperSockets device" >&2
return 1
fi
if [ $(ip link show $ndev | grep UP | wc -l) -eq 0 ]; then
echo "Error: $ndev is not in state UP" >&2
return 1
fi
if [ $(ip link show $ndev | grep master | wc -l) -ne 0 ]; then
echo "Error: $ndev is already a bridge port" >&2
return 1
if [ $(ip link show $ndev | grep "master $hsci" | wc -l) -eq 0 ]; then
echo "Error: $ndev is already a subordinate to another master" >&2
return 1
fi
fi
#Check PNETIDs
@@ -153,10 +181,12 @@ function verify_precon {
}
function clean_up {
ip link del $hsci >/dev/null 2>&1
bridge link set dev $hsdev learning_sync off self >/dev/null 2>&1
echo 0 > /sys/class/net/$hsdev/device/vnicc/bridge_invisible >/dev/null 2>&1
bridge fdb del $hsdev_mac dev $ndev >/dev/null 2>&1
ip link del $hsci >/dev/null 2>&1
bridge fdb del $hsci_mac dev $hsdev self local >/dev/null 2>&1
bridge fdb del $hsci_mac dev $ndev self local >/dev/null 2>&1
ip link del $hscibr >/dev/null 2>&1
}
##############################################################################
@@ -172,22 +202,33 @@ function add_hsci {
hsdev=$1
ndev=$2
hsci_postfix="$(readlink /sys/class/net/$hsdev/device/cdev0 | tail -c5)"
hscibr=hsci$hsci_postfix-br
hscibp=hsci$hsci_postfix-bp
hsci=hsci$hsci_postfix
#### Verify preconditions
verify_precon
if [ $? -ne 0 ]; then
return 1
fi
hsci_postfix="$(readlink /sys/class/net/$hsdev/device/cdev0 | tail -c5)"
hsci=hsci$hsci_postfix
echo "Adding $hsci with a HiperSockets dev $hsdev and an external dev $ndev"
#### Create bridge
ip link add name $hsci type bridge stp_state 0 >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Could not create a bridge" >&2
return 1
#### Create bridge (idempotent)
if [ ! -e /sys/class/net/$hscibr ]; then
# ageing_time of $hscibr defaults to 30000 (300 secs)
ip link add name $hscibr type bridge stp_state 0 >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Could not create a bridge" >&2
return 1
fi
else
ip link set dev $hscibr type bridge stp_state 0 >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: $hscibr is not a bridge" >&2
return 1
fi
fi
#### Prepare hsdev
@@ -196,19 +237,24 @@ function add_hsci {
echo 1 > /sys/class/net/$hsdev/device/vnicc/bridge_invisible
#### Create bridge ports
ip link set dev $ndev master $hsci >/dev/null 2>&1
ip link set dev $ndev master $hscibr >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Could not set master for $ndev" >&2
clean_up
return 1
fi
ip link set dev $hsdev master $hsci >/dev/null 2>&1
ip link set dev $hsdev master $hscibr >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Could not set master for $hsdev" >&2
clean_up
return 1
fi
# Do not learn from ndev, but do learn from hsci-bp:
# - First define hsdev and ndev as _isolated_ bridgeports
# - Then turn on learning_sync on self on hsdev
# - Then define hsci-bp as non-isolated veth bridgeport
# no forwarding between ndev and hsdev -> isolated on
# ndev is default for outgoing unknown targets -> flood on
# no need to learn external LAN targets into fdb -> learning off
@@ -230,29 +276,102 @@ function add_hsci {
clean_up
return 1
fi
# NOTE: Although not required, BCs will be sent out on hsdev.
# NOTE: We need to receive BCs on hsdev, as z/OS HSCI does ARP requests on HS.
hsdev_mac="$(cat /sys/class/net/$hsdev/address)"
echo "Set $hsdev MAC $hsdev_mac on $ndev and $hsci"
# set HS MAC on OSA as secondary MAC
bridge fdb add $hsdev_mac dev $ndev >/dev/null 2>&1
ip link set dev $hscibr up >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to set HS MAC on OSA as secondary MAC" >&2
echo "Error: Failed to set $hscibr up" >&2
clean_up
return 1
fi
# set HS MAC (common MAC) on HSCI as primary MAC
ip link set address $hsdev_mac dev $hsci >/dev/null 2>&1
#### Turn on device for bridge notification
#### Toggle is required to learn full list of HS targets,
#### not only future changes.
bridge link set dev $hsdev learning_sync off self >/dev/null 2>&1
bridge link set dev $hsdev learning_sync on self >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to set HiperSockets MAC (common MAC) on HSCI as primary MAC" >&2
echo "Error: Failed to turn on device for bridge notification" >&2
clean_up
return 1
fi
# define veth pair for hsci (idempotent)
if [ ! -e /sys/class/net/$hsci ]; then
ip link add dev $hsci type veth peer name $hscibp >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Could not create veth pair $hsci - $hscibp " >&2
clean_up
return 1
fi
else
if [ $hsci@$hscibp: != "$(ip -o -d link show dev $hsci | awk '/veth/ {print $2}' )" ]; then
echo "Error: $hsci@$hscibp is not a veth" >&2
clean_up
return 1
fi
fi
ip link set dev $hscibp master $hscibr >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to add $hscibp to $hscibr" >&2
clean_up
return 1
fi
bridge link set dev $hscibp isolated off learning on flood on mcast_flood on >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to set bridge parameters for $hscibp" >&2
clean_up
return 1
fi
#### Set a static forwarding rule for hsci MAC, so hsci can be used as a
#### single-MAC network interface without being subject to
#### ageing and re-learning
#### Wait for systemd to change the MAC of hsci, if it wants to:
sleep 1
hsci_mac="$(cat /sys/class/net/$hsci/address)"
#### (idempotent)
if [ $(bridge fdb show dev $hscibp | grep "$hsci_mac master $hscibr static" | wc -l) -eq 0 ]; then
bridge fdb add $hsci_mac dev $hscibp master static
if [ $? -ne 0 ]; then
echo "Error: Failed to set $hsci_mac to $hscibr fdb" >&2
clean_up
return 1
fi
fi
# Bridge-to-device learning will set this MAC on hsdev and ndev.
# Old kernel code doesn't do hsci bridge-to-device learning.
# In this case: Set hsci_mac as local MAC of hsdev and ndev,
# so at least the single-MAC scenario works.
if [ $(bridge fdb show dev $hsdev | grep "$hsci_mac self permanent" | wc -l) -eq 0 ]; then
echo "Warning: $hsci will support only its current static MAC address. Please upgrade your kernel to the latest level." >&2
bridge fdb add $hsci_mac dev $hsdev self local
if [ $? -ne 0 ]; then
echo "Error: Failed to add $hsci_mac to $hsdev" >&2
clean_up
return 1
fi
fi
if [ $(bridge fdb show dev $ndev | grep "$hsci_mac self permanent" | wc -l) -eq 0 ]; then
bridge fdb add $hsci_mac dev $ndev self local
if [ $? -ne 0 ]; then
echo "Error: Failed to add $hsci_mac to $ndev" >&2
clean_up
return 1
fi
fi
#### Set veth pair to UP
ip link set dev $hscibp up >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to set $hscibp up" >&2
clean_up
return 1
fi
ip link set dev $hsci up >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to set $hsci up" >&2
@@ -260,14 +379,7 @@ function add_hsci {
return 1
fi
# Turn on device for bridge notification
bridge link set dev $hsdev learning_sync on self >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to turn on device for bridge notification" >&2
clean_up
return 1
fi
echo "Successfully added HSCI interface $hsci"
echo "Added HSCI interface $hsci"
return 0
}
@@ -286,51 +398,97 @@ function del_hsci {
echo "Error: $hsci does not exit" >&2
return 1
fi
if [ $(ip link show | grep "master $hsci" | wc -l) -eq 0 ]; then
echo "Error: $hsci is not an active HSCI interface" >&2
return 1
hsci_mac="$(cat /sys/class/net/$hsci/address)"
#### Find hscibp and hscibr
hscibp="$(ip -o link show dev $hsci | awk '{print $2}')"
if [[ $hscibp != *@* ]]; then
# $hsci has no HSCI veth peer
echo "Warning: $hsci may have been created by an older version of hsci" >&2
mvp=1
hscibp=""
hscibr=$hsci
else
mvp=0
hscibp=${hscibp##*@}
hscibp=${hscibp%:}
echo "$hsci is paired with $hscibp" >&2
hscibr="$(ip link show dev $hscibp | awk '{for(x=1;x<NF;x++) if($x~/master/) print $(x+1)}')"
fi
bports="$(ip link show | grep "master $hsci" | awk '{print $2}')"
#### Find hsdev and ndev
hsdev=""
ndev=""
bports="$(ip link show | grep "master $hscibr" | awk '{print $2}')"
for bport in $bports; do
bport=${bport%:}
if [[ $bport == *@* ]]; then
bport=${bport%@*}
fi
if [ $(bridge -d link show dev $bport | grep "learning_sync on" | wc -l) -ne 0 ]; then
hsdev=$bport
else
ndev=$bport
bport=${bport%@*}
if [ $(bridge -d link show dev $bport | grep "isolated on" | wc -l) -ne 0 ]; then
if [ $(bridge -d link show dev $bport | grep "learning_sync on" | wc -l) -ne 0 ]; then
hsdev=$bport
else
ndev=$bport
fi
fi
done
if [ "$hsdev" == "" ]; then
echo "Error: $hsci has no active HiperSockets port" >&2
return 1
fi
echo "Deleting HSCI interface $hsci with the HiperSockets $hsdev and the external $ndev"
bridge link set dev $hsdev learning_sync off self >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to turn off learning_sync on $hsdev" >&2
return 1
fi
echo 0 > /sys/class/net/$hsdev/device/vnicc/bridge_invisible
hsdev_mac="$(cat /sys/class/net/$hsdev/address)"
echo "Deleting $hsev MAC $hsdev_mac on $ndev"
bridge fdb del $hsdev_mac dev $ndev >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to delete $hsev MAC $hsdev_mac on $ndev" >&2
return 1
if [ "$ndev" == "" ]; then
echo "Error: $hsci has no active external port" >&2
fi
echo "Deleting HSCI interface $hsci with HiperSockets interface $hsdev and external interface $ndev"
#### Delete veth before resetting learning_sync and deleting bridge,
#### so fdb entries are cleaned up (synced)!
ip link del $hsci >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to delete $hsci" >&2
return 1
fi
echo "Successfully deleted device $hsci"
# Bridge-to-device learning will remove learned MACs from hsdev and ndev.
# Old kernel code doesn't do hsci bridge-to-device learning.
# In this case: Remove the hsci_mac that was added during 'add' from
# hsdev and ndev.
if [ "$hsdev" != "" ] && [ $mvp -eq 0 ]; then
if [ $(bridge fdb show dev $hsdev | grep "$hsci_mac self permanent" | wc -l) -ne 0 ]; then
echo "Warning: It seems your kernel does not support all hsci features, please upgrade." >&2
bridge fdb del $hsci_mac dev $hsdev self local
if [ $? -ne 0 ]; then
echo "Error: Failed to delete $hsci_mac from $hsdev" >&2
fi
fi
fi
# In the mvp case hsci_mac == hs_mac and was only set on ndev.
if [ "$ndev" != "" ]; then
if [ $(bridge fdb show dev $ndev | grep "$hsci_mac self permanent" | wc -l) -ne 0 ]; then
bridge fdb del $hsci_mac dev $ndev self local
if [ $? -ne 0 ]; then
echo "Error: Failed to delete $hsci_mac from $ndev" >&2
fi
fi
fi
#### Reset learning_sync
if [ "$hsdev" != "" ]; then
bridge link set dev $hsdev learning_sync off self >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to turn off learning_sync on $hsdev" >&2
fi
fi
#### Delete bridge
if [ "$hscibr" != "" ]; then
ip link del $hscibr >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to delete $hscibr" >&2
fi
fi
if [ "$hsdev" != "" ]; then
echo 0 > /sys/class/net/$hsdev/device/vnicc/bridge_invisible
fi
echo "Deleted $hsci"
return 0
}
@@ -338,19 +496,63 @@ function del_hsci {
## Show HSCI
##############################################################################
function list_active {
hsdev=$1
local ext=""
function print_row {
if [ $mvp -eq 0 ]; then
printf '%-8s %-16s %-15s %-15s\n' "$hsci" "$hsci_pnetid" "$hsdev" "$ndev"
else
printf '%-8s %-16s %-15s %-15s (v1)\n' "$hsci" "$hsci_pnetid" "$hsdev" "$ndev"
fi
}
hsci="$(ip link show dev $hsdev | awk '{for(x=1;x<NF;x++) if($x~/master/) print $(x+1)}')"
ext="$(ip link show | grep "master $hsci" | grep --invert-match $hsdev | awk '{print $2}')"
# remove trailing ':'
ndev="${ext%:}"
function list_active {
hsci=""
hsdev=$1
ndev=""
hscibp=""
mvp=1
hsci_pnetid="$(get_pnetid $hsdev)"
hscibr="$(ip link show dev $hsdev | awk '{for(x=1;x<NF;x++) if($x~/master/) print $(x+1)}')"
if [ "$hscibr" == "" ]; then
print_row
return 0
fi
#### find ndev (the other isolated subordinate)
bports="$(ip link show | grep "master $hscibr" | awk '{print $2}')"
for bport in $bports; do
bport=${bport%:}
bport=${bport%@*}
if [ $(ip -d link show dev $bport | grep "isolated on" | wc -l) -ne 0 ]; then
if [ $bport != $hsdev ]; then
ndev=$bport
fi
else
hscibp=$bport
mvp=0
fi
done
check_pnetids
printf '%-8s %-16s %-15s %-15s\n' "$hsci" "$hsci_pnetid" "$hsdev" "$ndev"
if [ $mvp -ne 0 ]; then
hsci=$hscibr
print_row
return 0
fi
#### find hsci (veth-peer of non-isolated subordinate of hscibr)
hsci="$(ip -o link show dev $hscibp | awk '{print $2}')"
if [[ $hsci != *@* ]]; then
echo "Error: $hscibp has no HSCI veth peer" >&2
print_row
return 1
fi
hsci=${hsci##*@}
hsci=${hsci%:}
print_row
return 0
}
@@ -358,13 +560,14 @@ function print_header {
if [ $header -eq 0 ]; then
echo "HSCI PNET_ID HiperSockets External "
echo "------------------------------------------------------------"
header=1
fi
}
function list_one {
local hsnetdev=$1
if [ $(bridge -d link show dev $hsnetdev | grep "learning_sync on" | wc -l) -ne 0 ]; then
if [ $(bridge -d link show dev $hsnetdev 2>/dev/null | grep "learning_sync on" | wc -l) -ne 0 ]; then
print_header
list_active $hsnetdev
fi
@@ -433,4 +636,3 @@ while true; do
esac
shift
done

View File

@@ -23,10 +23,11 @@
#define INITRD_SIZE _AC(0x10410, UL)
#define OLDMEM_BASE _AC(0x10418, UL)
#define OLDMEM_SIZE _AC(0x10420, UL)
#define MAX_COMMAND_LINE_SIZE _AC(0x10430, UL)
#define COMMAND_LINE _AC(0x10480, UL)
/* Parameter sizes */
#define COMMAND_LINE_SIZE 896
#define LEGACY_COMMAND_LINE_SIZE 896
#ifndef __ASSEMBLER__

View File

@@ -20,6 +20,10 @@ void util_hexdump(FILE *fh, const char *tag, const void *data, int cnt);
void util_hexdump_grp(FILE *fh, const char *tag, const void *data, int group,
int cnt, int indent);
void util_print_indented(const char *str, int indent);
const char *util_libdir(void);
const char *util_libdir_path(const char *filename);
const char *util_datadir(void);
const char *util_datadir_path(const char *filename);
static inline void util_ptr_vec_free(void **ptr_vec, int count)
{

View File

@@ -52,6 +52,7 @@
#define TOOLS_LIBDIR STRINGIFY (S390_TOOLS_LIBDIR)
#define TOOLS_SYSCONFDIR STRINGIFY (S390_TOOLS_SYSCONFDIR)
#define TOOLS_BINDIR STRINGIFY (S390_TOOLS_BINDIR)
#define TOOLS_DATADIR STRINGIFY (S390_TOOLS_DATADIR)
#define __noreturn __attribute__((noreturn))
#define __packed __attribute__((packed))

View File

@@ -96,7 +96,7 @@ int dasd_sys_ese(char *devnode)
return (rc == 1) ? 1 : 0;
}
int dasd_get_pm_from_chpid(char *busid, unsigned int chpid, int *mask)
static int dasd_get_pm_from_chpid(char *busid, unsigned int chpid, int *mask)
{
unsigned int val;
int count, i;

View File

@@ -47,6 +47,8 @@ detect-openssl-version.dep:
echo "}" >> $(TMPFILE)
mv $(TMPFILE) $@
CURL_CONFIG ?= curl-config
check-dep-libekmfweb: detect-openssl-version.dep
$(call check_dep, \
"libekmfweb", \
@@ -64,8 +66,8 @@ check-dep-libekmfweb: detect-openssl-version.dep
"curl/curl.h", \
"libcurl-devel", \
"HAVE_LIBCURL=0" \
`curl-config --cflags` `curl-config --libs`)
curl-config --ssl-backends | grep OpenSSL >/dev/null 2>&1 || { echo "Error: libcurl is not built with the OpenSSL backend"; exit 1; }
`$(CURL_CONFIG) --cflags` `$(CURL_CONFIG) --libs`)
$(CURL_CONFIG) --ssl-backends | grep OpenSSL >/dev/null 2>&1 || { echo "Error: libcurl is not built with the OpenSSL backend"; exit 1; }
touch check-dep-libekmfweb
skip-libekmfweb-openssl:
@@ -83,8 +85,8 @@ ekmfweb.o: check-dep-libekmfweb ekmfweb.c utilities.h cca.h $(rootdir)include/ek
utilities.o: check-dep-libekmfweb utilities.c utilities.h $(rootdir)include/ekmfweb/ekmfweb.h
cca.o: check-dep-libekmfweb cca.c cca.h utilities.h $(rootdir)include/ekmfweb/ekmfweb.h
libekmfweb.so.$(VERSION): ALL_CFLAGS += -fPIC `curl-config --cflags`
libekmfweb.so.$(VERSION): LDLIBS = -ljson-c -lcrypto -lssl `curl-config --libs` -ldl
libekmfweb.so.$(VERSION): ALL_CFLAGS += -fPIC `$(CURL_CONFIG) --cflags`
libekmfweb.so.$(VERSION): LDLIBS = -ljson-c -lcrypto -lssl `$(CURL_CONFIG) --libs` -ldl
libekmfweb.so.$(VERSION): ALL_LDFLAGS += -shared -Wl,--version-script=libekmfweb.map \
-Wl,-z,defs,-Bsymbolic -Wl,-soname,libekmfweb.so.$(VERM)
libekmfweb.so.$(VERSION): ekmfweb.o utilities.o cca.o $(libs)

View File

@@ -50,6 +50,9 @@ detect-openssl-version.dep:
echo "}" >> $(TMPFILE)
mv $(TMPFILE) $@
CURL_CONFIG ?= curl-config
XML2_CONFIG ?= xml2-config
check-dep-libkmipclient: detect-openssl-version.dep
$(call check_dep, \
"libkmipclient", \
@@ -67,14 +70,14 @@ check-dep-libkmipclient: detect-openssl-version.dep
"libxml/tree.h", \
"libxml2-devel", \
"HAVE_LIBXML2=0", \
`xml2-config --cflags` `xml2-config --libs`)
`$(XML2_CONFIG) --cflags` `$(XML2_CONFIG) --libs`)
$(call check_dep, \
"libkmipclient", \
"curl/curl.h", \
"libcurl-devel", \
"HAVE_LIBCURL=0" \
`curl-config --cflags` `curl-config --libs`)
curl-config --ssl-backends | grep OpenSSL >/dev/null 2>&1 || { echo "Error: libcurl is not built with the OpenSSL backend"; exit 1; }
`$(CURL_CONFIG) --cflags` `$(CURL_CONFIG) --libs`)
$(CURL_CONFIG) --ssl-backends | grep OpenSSL >/dev/null 2>&1 || { echo "Error: libcurl is not built with the OpenSSL backend"; exit 1; }
touch check-dep-libkmipclient
skip-libkmipclient-openssl:
@@ -104,8 +107,8 @@ tls.o: check-dep-libkmipclient tls.c kmip.h utils.h $(rootdir)include/kmipclient
names.o: check-dep-libkmipclient names.c names.h utils.h $(rootdir)include/kmipclient/kmipclient.h
utils.o: check-dep-libkmipclient utils.c names.h utils.h $(rootdir)include/kmipclient/kmipclient.h
libkmipclient.so.$(VERSION): ALL_CFLAGS += -fPIC `xml2-config --cflags` `curl-config --cflags`
libkmipclient.so.$(VERSION): LDLIBS = -ljson-c -lcrypto -lssl `xml2-config --libs` `curl-config --libs`
libkmipclient.so.$(VERSION): ALL_CFLAGS += -fPIC `$(XML2_CONFIG) --cflags` `$(CURL_CONFIG) --cflags`
libkmipclient.so.$(VERSION): LDLIBS = -ljson-c -lcrypto -lssl `$(XML2_CONFIG) --libs` `$(CURL_CONFIG) --libs`
libkmipclient.so.$(VERSION): ALL_LDFLAGS += -shared -Wl,--version-script=libkmipclient.map \
-Wl,-z,defs,-Bsymbolic -Wl,-soname,libkmipclient.so.$(VERM)
libkmipclient.so.$(VERSION): kmip.o request.o response.o attribute.o key.o ttlv.o json.o \

View File

@@ -125,7 +125,7 @@ int kmip_parse_hex(const char *str, bool has_prefix, unsigned char **val,
{
unsigned char *buf;
BIGNUM *b = NULL;
int len, rc;
int len;
if (str == NULL)
return -EINVAL;
@@ -133,18 +133,20 @@ int kmip_parse_hex(const char *str, bool has_prefix, unsigned char **val,
if (has_prefix && strncmp(str, "0x", 2) != 0)
return -EBADMSG;
rc = BN_hex2bn(&b, str + (has_prefix ? 2 : 0));
if (rc <= 0)
len = BN_hex2bn(&b, str + (has_prefix ? 2 : 0));
if (len <= 0)
return -EBADMSG;
if (len < (int)strlen(str) - (has_prefix ? 2 : 0))
return -EBADMSG;
len = BN_num_bytes(b);
len = len / 2 + (len % 2 > 0 ? 1 : 0);
buf = calloc(1, len);
if (buf == NULL) {
BN_free(b);
return -ENOMEM;
}
if (BN_bn2bin(b, buf) != len) {
if (BN_bn2binpad(b, buf, len) != len) {
BN_free(b);
free(buf);
return -EIO;

View File

@@ -9,6 +9,8 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <err.h>
#include <limits.h>
#include <string.h>
#include "lib/util_base.h"
@@ -91,3 +93,91 @@ void util_print_indented(const char *str, int indent)
printf("\n");
free(desc_ptr);
}
/**
* Determines the absolute name of an s390-tools system directory
* (it could be data, or library directory)
*/
static const char *util_sysdir(const char *env_var, const char *default_dir)
{
return secure_getenv(env_var) ?: default_dir;
}
/**
* Determines the absolute name of a file installed in the s390-tools
* system directory
*/
static const char *util_sysdir_path(const char *filename, const char *dirname)
{
static char libdir_pathname[PATH_MAX];
int ret;
ret = snprintf(libdir_pathname, sizeof(libdir_pathname),
"%s/%s", dirname, filename);
if (ret < 0 || ret >= (int)sizeof(libdir_pathname))
errx(EXIT_FAILURE,
"Could not compose absolute pathname of %s and %s",
dirname, filename);
return libdir_pathname;
}
/**
* Determines the absolute name of a s390-tools library directory
*
* Resources are handled by the library
*
* @returns Pointer to a buffer, which contains the null-terminated name
*/
const char *util_libdir(void)
{
return util_sysdir("S390TOOLS_LIBDIR", TOOLS_LIBDIR);
}
/**
* Determines the absolute name of a file installed in the s390-tools
* library directory by its relative name.
*
* Resources are handled by the library. A second call of this function
* overwrites previously returned data. Care must be taken when attempting
* to do a second call.
*
* @param[in] filename Null-terminated file name relative to the s390-tools
* library directory
* @returns Pointer to a buffer of PATH_MAX size, which contains the
* null-terminated absolute name
*/
const char *util_libdir_path(const char *filename)
{
return util_sysdir_path(filename, util_libdir());
}
/**
* Determines the absolute name of a s390-tools data directory
*
* Resources are handled by the library
*
* @returns Pointer to a buffer which contains the null-terminated name
*/
const char *util_datadir(void)
{
return util_sysdir("S390TOOLS_DATADIR", TOOLS_DATADIR);
}
/**
* Determines the absolute name of a file installed in the s390-tools
* data directory by its relative name.
*
* Resources are handled by the library. A second call of this function
* overwrites previously returned data. Care must be taken when attempting
* to do a second call.
*
* @param[in] filename Null-terminated file name relative to the s390-tools
* data directory
* @returns Pointer to a buffer of PATH_MAX size, which contains the
* null-terminated absolute name
*/
const char *util_datadir_path(const char *filename)
{
return util_sysdir_path(filename, util_datadir());
}

View File

@@ -1,6 +1,7 @@
include ../common.mak
SCRIPTS = dbginfo.sh zfcpdbf zipl-switch-to-blscfg scsi_logging_level
SCRIPTS = dbginfo.sh zfcpdbf zipl-switch-to-blscfg scsi_logging_level
SCRIPTS += sclpdbf
MAN_PAGES = dbginfo.sh.1 zfcpdbf.1 zipl-switch-to-blscfg.1
all:
@@ -19,7 +20,7 @@ install:
sed -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' cpictl > \
$(DESTDIR)$(TOOLS_LIBDIR)/cpictl
chown $(OWNER):$(GROUP) $(DESTDIR)$(TOOLS_LIBDIR)/cpictl
chmod 775 $(DESTDIR)$(TOOLS_LIBDIR)/cpictl
chmod 755 $(DESTDIR)$(TOOLS_LIBDIR)/cpictl
@for i in $(MAN_PAGES); \
do \

View File

@@ -24,6 +24,9 @@ readonly SYSTEM_NAME_PATH="/sys/firmware/cpi/system_name"
readonly SYSPLEX_NAME_PATH="/sys/firmware/cpi/sysplex_name"
readonly CPI_SET="/sys/firmware/cpi/set"
# Location of os-release file - can be specified externally for testing purpose
readonly OS_RELEASE=${CPI_OS_RELEASE:-"/etc/os-release"}
declare LEVEL
declare TYPE
declare NAME
@@ -37,6 +40,16 @@ readonly EXIT_FAILURE=1
readonly EXIT_ARG_TOO_LONG=3
readonly EXIT_INVALID_CHARS=4
# Distro-IDs as supported by SE/HMC firmware
readonly DISTRO_GENERIC=0
readonly DISTRO_RHEL=1
readonly DISTRO_SLES=2
readonly DISTRO_UBUNTU=3
readonly DISTRO_FEDORA=4
readonly DISTRO_OPENSUSE=5
readonly DISTRO_DEBIAN=6
readonly DISTRO_RHCOS=7
print_help_and_exit()
{
cat <<EndHelp
@@ -49,7 +62,8 @@ Configure the Control-Program-Information (CPI) settings.
sysplex name with values taken from environment
variables
-h, --help Print this help, then exit
-L, --level LEVEL Set and commit OS level to LEVEL (format xx.yy.zzABCD)
-L, --level LEVEL Set and commit OS level to LEVEL. Format: 0x<level> or
[[[flags:]distro_id:distro_version:]kernel_version]
-N, --name SYSTEM Set and commit the system name to SYSTEM
-S, --sysplex SYSPLEX Set and commit the sysplex name to SYSPLEX
-T, --type TYPE Set and commit OS type to TYPE
@@ -109,7 +123,7 @@ fail_with()
cpi_commit()
{
echo 1 > "$CPI_SET"
echo 1 > "$CPI_SET" 2> /dev/null
}
do_length_check()
@@ -129,15 +143,228 @@ cpi_set_bit()
LEVEL=$(printf '0x%x' $((LEVEL | (1 << (63 - $1)) )) )
}
#
# split_version - Split generic version string into array of sub-versions
#
# @version: Version string
# @delim: Characters that delimit sub-versions in version string
# @num: Number of sub-versions
#
# Print @num sub-versions of @version where each sub-version is delimited by
# any of the characters in @delim. Print 0 in place of non-decimal or missing
# sub-versions.
#
# Examples:
# version=10 delim=. num=3 => 10 0 0
# version=4.8 delim=. num=2 => 4 8
#
split_version()
{
local version="$1" delim="$2" num="$3"
local list i subver
IFS="$delim" read -r -a list <<< "$version"
for (( i=0; i<num; i++ )) ; do
subver="${list[i]:-0}"
# Handle non-number sub-versions
[[ "$subver" =~ ^[0-9]+$ ]] || subver=0
# Force decimal interpretation in case of leading zeroes
subver=$(( 10#$subver ))
printf "%s " "$subver"
done
}
#
# split_kver - Split Linux kernel version string into array of sub-versions
#
# @version: Linux kernel version string
# @num: Number of sub-versions
#
# Print @num sub-versions of the specified kernel @version. Print 0 in place
# of non-decimal or missing sub-versions.
#
# Examples:
# version=2.4-13 num=4 => 2 4 0 13
# version=3.0.93_3.0.101-0.8.2_0.8.1 num=6 => 3 0 93 3 0 101
# version=4.12.14-lp150.11.4 num=5 => 4 12 14 0 11
#
split_kver()
{
local version="$1" num="$2"
local main extra
# Separate extra version to handle short main version (e.g. 2.4-13)
IFS="-_" read -r main extra <<< "$version"
split_version "$main" "." $(( num > 3 ? 3 : num ))
[[ "$num" -gt 3 ]] && split_version "$extra" ".-_" $(( num - 3 ))
}
#
# bytes_to_word - Convert byte array to hexadecimal word
#
# @bytes: List of numbers representing byte values
#
# Print a big-endian hexadecimal representation of the word that results from
# combining the specified byte values.
#
bytes_to_word()
{
printf "0x"
printf "%02x" "$@"
}
#
# get_system_level - Print system level word for specified distribution version
#
# @distro: Distro ID (ID value from /etc/os-release)
# @ver_str: Distro version string (VERSION_ID from /etc/os-release)
# @kver_str: Kernel version string (output of 'uname -r')
# @flags: Optional statistics flags
#
# Print a 64 bit hexadecimal system level in a format as understood by firmware.
#
# The format is 0xabccddeeeeffgghh, where
# - a=statistics flags
# - b=distro id
# - c=distro major version
# - d=distro minor version(s)
# - e=kernel sublevel 2
# - f=kernel version
# - g=kernel patchlevel
# - h=kernel sublevel 1
#
get_system_level()
{
local distro="$1" ver_str="$2" kver_str="$3" flags="${4:-0}"
local distro_id d_major d_minor d_minor2
local k_ver k_patchlvl k_sublvl k_sublvl2 bytes=()
# Extract list of sub-version numbers from version strings
read -r d_major d_minor d_minor2 <<< "$(split_version "$ver_str" "._-" 3)"
read -r k_ver k_patchlvl k_sublvl k_sublvl2 <<< "$(split_kver "$kver_str" 4)"
# Apply distro-specific logic
case "$distro" in
"rhel")
distro_id=$DISTRO_RHEL
;;
"sles")
distro_id=$DISTRO_SLES
;;
"ubuntu")
distro_id=$DISTRO_UBUNTU
# Encode minor and update version numbers in minor field
(( d_minor=((d_minor & 0xf) * 0x10) + (d_minor2 & 0xf) ))
;;
"fedora")
distro_id=$DISTRO_FEDORA
;;
"opensuse-leap")
distro_id=$DISTRO_OPENSUSE
;;
"debian")
distro_id=$DISTRO_DEBIAN
;;
"rhcos")
distro_id=$DISTRO_RHCOS
;;
*)
distro_id=$DISTRO_GENERIC
# Reset unsupported fields
d_major=0
d_minor=0
k_sublvl2=0
;;
esac
# Assemble byte data
(( bytes[0] = (flags & 0xf) * 0x10 + distro_id ))
(( bytes[1] = d_major ))
(( bytes[2] = d_minor ))
(( bytes[3] = (k_sublvl2 / 256) & 0xff ))
(( bytes[4] = k_sublvl2 & 0xff ))
(( bytes[5] = k_ver ))
(( bytes[6] = k_patchlvl ))
(( bytes[7] = k_sublvl ))
# Print as single hex word
bytes_to_word "${bytes[@]}"
}
get_distro()
{
local line ID="linux" VERSION_ID="0" VERSION="" update
[[ ! -e "$OS_RELEASE" ]] && return
# Only import required variables
while read -r line ; do
if [[ "$line" =~ ^ID= ]] || [[ "$line" =~ ^VERSION_ID= ]] ||
[[ "$line" =~ ^VERSION= ]] ; then
eval "$line"
fi
done <"$OS_RELEASE"
if [[ "$ID" == "ubuntu" ]] ; then
# Extract update version number only found in VERSION, e.g.
# VERSION_ID="18.04" VERSION="18.04.5 LTS"
update="${VERSION/*$VERSION_ID/}"
update="${update%% *}"
VERSION_ID="$VERSION_ID$update"
fi
echo "$ID:$VERSION_ID"
}
cpi_set_oslevel()
{
local kver=$(echo "${1:-$(uname -r)}" | grep -E -o '^[0-9]+[.][0-9]+[.][0-9]+')
local maj=$((${kver%%.*} % 256))
local min=${kver#*.}
min=$((${min%.*} % 256))
local rev=$((${kver##*.} % 256))
local hexlevel=$(printf '0x%02x%02x%02x' $maj $min $rev)
LEVEL=$(printf '0x%016x' $(((LEVEL & 0xFFFFFFFFFF000000) | hexlevel)))
local level="${1:-}"
local flags list distro_id distro_ver kver id ver
if [[ "$level" =~ ^0x ]] && ! [[ "$level" =~ : ]] ; then
# Format: level=0x<hex>
printf -v LEVEL "0x%016x" "$level" 2>/dev/null ||
fail_with "$PRG: Invalid hexadecimal number in $level" \
$EXIT_INVALID_CHARS
return
fi
# Format: level=[[[flags:]distro_id:distro_ver:]kver]
IFS=":" read -r -a list <<< "$level:"
kver="${list[*]: -1: 1}"
distro_ver="${list[*]: -2: 1}"
distro_id="${list[*]: -3: 1}"
flags="${list[*]: -4: 1}"
if [[ -z "$kver" ]] ; then
# Use version of currently running kernel
kver="$(uname -r)"
fi
if [[ -z "$distro_ver" ]] || [[ -z "$distro_id" ]] ; then
# Use distro ID and version from os-release file
IFS=":" read -r id ver <<< "$(get_distro)"
distro_id=${distro_id:-$id}
distro_ver=${distro_ver:-$ver}
fi
if [[ -z "$flags" ]] ; then
# Keep statistics flags from current system level
flags=$(( (LEVEL >> 60) & 0xf ))
fi
LEVEL=$(get_system_level "$distro_id" "$distro_ver" "$kver" "$flags")
}
cpi_set_type()

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
.TH DBGINFO.SH 1 "April 2021" "s390-tools"
.TH DBGINFO.SH 1 "September 2021" "s390-tools"
.SH NAME
dbginfo.sh \- collect runtime, configuration and trace information
@@ -14,8 +14,10 @@ for debugging Linux on IBM Z
This script collects runtime, configuration and trace information that can
be used to debug a Linux on IBM Z instance.
For Linux on z/VM, the script also traces information about the z/VM system.
KVM or DOCKER data ist collected on a host serving this.
The debug information is written to a file
/tmp/DBGINFO\-<date>\-<time>\-<hostname>\-<processorid>.tgz
/<DIRECTORY>/DBGINFO\-<date>\-<time>\-<hostname>\-<processorid>.tgz
where [date] and [time] are the date and time when the debug data was
collected. [hostname] indicates the hostname of the system the data was
collected from. The [processorid] is taken from the processor 0 and indicates
@@ -32,7 +34,12 @@ Print version information, then exit.
.TP
\fB\-d <DIRECTORY>\fP, \fB\-\-directory <DIRECTORY>\fP
Specify the DIRECTORY where the data collection stores the temporary data and the final archive. The specified directory must already exist. If this parameter is not specified, /tmp is used by default.
Specify the DIRECTORY where the data collection stores the temporary data and the final archive.
The specified directory must already exist. If this parameter is not specified, /tmp is used by default.
.TP
\fB\-c\fP, \fB\-\-check\fP
Print online quick check (not saving any data) - can be combind with a preceding -d option.
.SH FILES
A .tgz file of the form
@@ -56,48 +63,57 @@ Copyright IBM Corp. 2002, 2021
.PP
Hardware platform = s390x
.br
Kernel version = 5.4.0 (5.4.0-70-generic)
.br
Runtime environment = z/VM
.br
Kernel version = 4.18.0 (4.18.0-305.el8.s390x)
.br
OS version / distro = Red Hat Enterprise Linux 8.4 (Ootpa)
.br
Date and time of info = 2021-08-26-15-27-58
.PP
1 of 16: Collecting command output
1 of 18: Collecting sysfs
.PP
2 of 16: Collecting z/VM command output
2 of 18: Collecting procfs
.PP
3 of 16: Collecting procfs
3 of 18: Collecting config files
.PP
4 of 16: Collecting sysfs
4 of 18: Collecting command output
.PP
5 of 16: Collecting log files
5 of 18: Collecting hyptop for z/VM - 5s output
.PP
6 of 16: Collecting config files
6 of 18: Collecting z/VM output
.PP
7 of 16: Collecting osa oat output
7 of 18: Collecting network output
.PP
8 of 16: Collecting ethtool output
8 of 18: Collecting osa oat output
.PP
9 of 16: Collecting tc output
9 of 18: Collecting ethtool output
.PP
10 of 16: Collecting bridge output
10 of 18: Collecting Trafic Control output
.PP
11 of 16: Collecting OpenVSwitch output
11 of 18: Collecting bridge output
.PP
12a of 16: Collecting docker container
12b of 16: Collecting docker network
12 of 18: Skip OpenVSwitch: ovs-vsctl not available
.PP
13 of 16: Collecting nvme output
13 of 18: Skip KVM: no virsh command
.PP
14 of 16: Collecting KVM data
14 of 18: Collecting docker output
.PP
15 of 16: Postprocessing
15 of 18: Collecting NVME storage output
.PP
16 of 16: Finalizing: Creating archive with collected data
16 of 18: Collecting log files
.PP
0 logfiles over 50 MB
.PP
17 of 18: Postprocessing
.PP
18 of 18: Finalizing: Creating archive with collected data
.PP
Collected data was saved to:
.br
>> /data\-collection/DBGINFO\-2021\-04\-20\-14\-00\-07\-host\-012345.tgz <<
>> /data\-collection/DBGINFO\-2021\-08\-26\-15\-27\-58\-host\-012345.tgz <<
.br
Review the collected data before sending to your service organization.
Please review all collected data before sending to your service organization.
.SH HINTS
Run the script with root authority.
.br

1172
scripts/sclpdbf Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -887,14 +887,13 @@ sub print_scsi_common
print "FCP rsp inf cod: 0x", substr($rec->[2], 44, 2), "\n";
print "FCP rsp IU : ", payload_format(substr($rec->[2], 114, 48));
if (defined($pay_sns)) {
print "Sense len : ", $payload_length, "\n"
if ($payload_length);
print_payload($payload_length, $pay_sns, "Sense info")
}
if (defined($pay_riu) && ($payload_length > FCP_RESP_WITH_EXT)) {
if ($payload_length && defined($pay_sns)) {
print "Sense len : ", $payload_length, "\n";
print_payload($payload_length, $pay_sns, "Sense info");
} elsif ($payload_length) {
print "FCP rsp IU len : ", $payload_length, "\n";
print_payload($payload_length, $pay_riu, "FCP rsp IU all");
print_payload($payload_length, $pay_riu, "FCP rsp IU all")
if ($payload_length > FCP_RESP_WITH_EXT);
}
print "\n";
}

View File

@@ -1863,7 +1863,6 @@ static void close_ur_device(struct vmur *info)
}
cpcmd_cs(cmd, &response, &cprc, 0);
memcpy(spoolid, &response[9], 4);
free(response);
if (cprc == 439) {
if (info->action == PUNCH)
sprintf(cmd, "PURGE * PUN %s", spoolid);
@@ -1872,7 +1871,10 @@ static void close_ur_device(struct vmur *info)
cpcmd(cmd, NULL, NULL, 0);
ERR_EXIT("User %s spool fileid limit exceeded.\n"
, info->user);
} else if (cprc) {
ERR_EXIT("CP command failed with rc=%i\n%s\n", cprc, response);
}
free(response);
if (info->rdr_specified) {
if (info->node_specified)
printf("Reader file with spoolid %s created and "

View File

@@ -463,7 +463,15 @@ static int fill_io_devid(struct util_rec *rec, char *path)
util_scandir_free(de_vec, count);
return 1;
}
strncpy(buf, "none", sizeof(buf));
if (util_file_read_line(buf, sizeof(buf), "%s/dev_busid",
path) == 0) {
if (cmd.opt_short) {
if (strncmp(buf, "0.0.", PREFIX_ID_LENGTH) != 0)
return 1;
memmove(buf, buf + PREFIX_ID_LENGTH,
(sizeof(buf) - PREFIX_ID_LENGTH));
}
}
fill_device_info(rec, NULL, NULL);
}
if (cmd.opt_uppercase)

View File

@@ -203,6 +203,7 @@ $(readlink -e $HOST_PATH)/-"
read ONLINE < $ADAPTER_PATH/online
read AVAILABILITY < $ADAPTER_PATH/availability
[ -r "$SYSFS/class/fc_host/$SCSI_HOST/port_state" ] && read PORT_STATE < "$SYSFS/class/fc_host/$SCSI_HOST/port_state"
[ -r $ADAPTER_PATH/failed ] && read FAILED < $ADAPTER_PATH/failed
DEFUNCT=${ADAPTER_PATH%/*} # strip devbusid
DEFUNCT=${DEFUNCT##*/} # basename
@@ -212,6 +213,8 @@ $(readlink -e $HOST_PATH)/-"
HOSTMARKER=" defunct"
elif [ "$ONLINE" = "0" ]; then
HOSTMARKER=" offline"
elif [ "$PORT_STATE" = "Linkdown" ]; then
HOSTMARKER=" linkdown"
elif [ "$FAILED" = "1" ]; then
HOSTMARKER=" failed"
elif [ "$AVAILABILITY" != "good" ]; then

View File

@@ -115,6 +115,11 @@ Displays version information and exits.
Here is an explanation of the columns displayed. Please note that some
of the columns show up in verbose mode only.
.TP
.B CARD.DOM
The crypto card number in hexadecimal for a crypto card line or
the crypto card number and the domain id both in hex separated by a single
dot for a queue line.
.TP
.B TYPE and HWTYPE
The HWTYPE is a numeric value showing which type of hardware the zcrypt
device driver presumes that this crypto card is. The currently known values
@@ -145,9 +150,16 @@ may be adjusted on the HMC or SE. The chzcrypt application can also
trigger this state with the --config-on and --config-off options.
.br
lszcrypt shows 'online' when a card or queue is available for
cryptograhic operations. 'offline' is displayed when a card or queue
cryptographic operations. 'offline' is displayed when a card or queue
is switched to (software) offline. If a card is 'deconfigured' via
HMC, SE or chzcrypt the field shows 'deconfig'.
.br
If a queue is not bound to a device driver there is no detailed
information available and thus the status shows only '-'.
.br
If a queue is bound to the vfio-ap device driver it is up to this driver
to give some status information and what exactly this means. So lszcrypt
shows the text retrieved from the underlying sysfs attribute here.
.TP
.B REQUESTS
This is the counter value of successful processed requests on card or queue
@@ -168,7 +180,7 @@ S - APSC available: card/queue can handle requests with the special bit
enabled.
.br
M - Accelerator card/queue with support for RSA ME with up to 4k key size.
.br
.Sr
C - Accelerator card/queue with support for RSA CRT with up to 4k key size.
.br
D - Card/queue is providing CCA functions (this is the CCA Coprocessor mode).

View File

@@ -22,6 +22,8 @@
#include "lib/util_scandir.h"
#include "lib/zt_common.h"
#include "misc.h"
/*
* Private data
*/
@@ -331,13 +333,49 @@ static void show_capability(const char *id_str)
printf("\n");
}
/*
* Read driver entry in dir or in dir/subdir and store driver into buf.
* Returns:
* 0 if there is no driver link (no driver bound to this device or error)
* 1 if one of the cexXcard or cexXqueue driver is bound to this device
* 2 if the vfio is bound to this device
*/
static int read_driver(const char *dir, const char *subdir, char *buf, size_t buflen)
{
char drvlink[PATH_MAX], linktarget[PATH_MAX];
char *p, driver[256];
if (subdir)
snprintf(drvlink, sizeof(drvlink), "%s/%s/driver", dir, subdir);
else
snprintf(drvlink, sizeof(drvlink), "%s/driver", dir);
drvlink[sizeof(drvlink) - 1] = '\0';
memset(linktarget, 0, sizeof(linktarget));
if (readlink(drvlink, linktarget, sizeof(linktarget)) > 0) {
p = strrchr(linktarget, '/');
if (p) {
strncpy(driver, p + 1, sizeof(driver));
driver[sizeof(driver) - 1] = '\0';
strncpy(buf, driver, buflen);
if (misc_regex_match(driver, "cex[0-9](card|queue)"))
return 1;
else if (misc_regex_match(driver, "vfio.ap"))
return 2;
}
}
return 0;
}
/*
* Read subdevice default attributes
*/
static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
const char *sub_dev)
{
long value;
long config = -1, online = -1;
char buf[256];
unsigned long facility;
@@ -346,24 +384,29 @@ static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
else
util_rec_set(rec, "type", buf);
if (util_path_is_readable("%s/%s/online", grp_dev, sub_dev)) {
util_file_read_l(&value, 10, "%s/%s/online", grp_dev, sub_dev);
if (value > 0)
util_rec_set(rec, "online", "online");
else {
/* device is offline, check config (if available) */
if (util_path_is_readable("%s/%s/config", grp_dev, sub_dev)) {
util_file_read_l(&value, 10, "%s/%s/config", grp_dev, sub_dev);
if (value > 0)
util_rec_set(rec, "online", "offline");
else
util_rec_set(rec, "online", "deconfig");
} else
util_rec_set(rec, "online", "offline");
}
if (util_path_is_readable("%s/%s/config", grp_dev, sub_dev))
util_file_read_l(&config, 10, "%s/%s/config", grp_dev, sub_dev);
if (util_path_is_readable("%s/%s/online", grp_dev, sub_dev))
util_file_read_l(&online, 10, "%s/%s/online", grp_dev, sub_dev);
util_rec_set(rec, "status", "-");
if (config == 0) {
util_rec_set(rec, "status", "deconfig");
} else {
/* no online attribute */
util_rec_set(rec, "online", "-");
if (online > 0)
util_rec_set(rec, "status", "online");
else if (online == 0)
util_rec_set(rec, "status", "offline");
else {
/* no online attribute, maybe use status attribute */
if (util_path_is_readable("%s/%s/status",
grp_dev, sub_dev)) {
util_file_read_line(buf, sizeof(buf),
"%s/%s/status",
grp_dev, sub_dev);
util_rec_set(rec, "status", buf);
}
}
}
util_file_read_ul(&facility, 16, "%s/ap_functions", grp_dev);
@@ -376,9 +419,13 @@ static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
else
util_rec_set(rec, "mode", "Unknown");
util_file_read_line(buf, sizeof(buf), "%s/%s/request_count",
grp_dev, sub_dev);
util_rec_set(rec, "requests", buf);
if (config == 0) {
util_rec_set(rec, "requests", "-");
} else {
util_file_read_line(buf, sizeof(buf), "%s/%s/request_count",
grp_dev, sub_dev);
util_rec_set(rec, "requests", buf);
}
}
/*
@@ -387,19 +434,29 @@ static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
static void read_subdev_rec_verbose(struct util_rec *rec, const char *grp_dev,
const char *sub_dev)
{
int i;
int i, drvinfo;
unsigned long facility;
char buf[256], afile[PATH_MAX];
long depth, pending1, pending2;
char buf[256];
long depth, pending1, pending2, config = -1;
if (l.verbose == 0)
return;
util_file_read_l(&pending1, 10, "%s/%s/pendingq_count",
grp_dev, sub_dev);
util_file_read_l(&pending2, 10, "%s/%s/requestq_count",
grp_dev, sub_dev);
util_rec_set(rec, "pending", "%ld", pending1 + pending2);
drvinfo = read_driver(grp_dev, sub_dev, buf, sizeof(buf));
util_rec_set(rec, "driver", drvinfo > 0 ? buf : "-no-driver-");
if (util_path_is_readable("%s/config", grp_dev))
util_file_read_l(&config, 10, "%s/config", grp_dev);
if (config == 0 || drvinfo != 1) {
util_rec_set(rec, "pending", "-");
} else {
util_file_read_l(&pending1, 10, "%s/%s/pendingq_count",
grp_dev, sub_dev);
util_file_read_l(&pending2, 10, "%s/%s/requestq_count",
grp_dev, sub_dev);
util_rec_set(rec, "pending", "%ld", pending1 + pending2);
}
util_file_read_line(buf, sizeof(buf), "%s/hwtype", grp_dev);
util_rec_set(rec, "hwtype", buf);
@@ -412,14 +469,6 @@ static void read_subdev_rec_verbose(struct util_rec *rec, const char *grp_dev,
buf[i] = facility & fac_bits[i].mask ? fac_bits[i].c : '-';
buf[i] = '\0';
util_rec_set(rec, "facility", buf);
snprintf(afile, sizeof(afile), "%s/%s/driver", grp_dev, sub_dev);
afile[sizeof(afile) - 1] = '\0';
memset(buf, 0, sizeof(buf));
if (readlink(afile, buf, sizeof(buf)) > 0)
util_rec_set(rec, "driver", strrchr(buf, '/') + 1);
else
util_rec_set(rec, "driver", "-no-driver-");
}
/*
@@ -467,7 +516,7 @@ static void show_subdevices(struct util_rec *rec, const char *grp_dev)
*/
static void read_rec_default(struct util_rec *rec, const char *grp_dev)
{
long value;
long config = -1, online = -1;
char buf[256];
unsigned long facility;
@@ -486,24 +535,27 @@ static void read_rec_default(struct util_rec *rec, const char *grp_dev)
else
util_rec_set(rec, "mode", "Unknown");
if (util_path_is_readable("%s/online", grp_dev)) {
util_file_read_l(&value, 10, "%s/online", grp_dev);
if (value > 0)
util_rec_set(rec, "online", "online");
else {
if (util_path_is_readable("%s/config", grp_dev)) {
util_file_read_l(&value, 10, "%s/config", grp_dev);
if (value > 0)
util_rec_set(rec, "online", "offline");
else
util_rec_set(rec, "online", "deconfig");
} else
util_rec_set(rec, "online", "offline");
}
if (util_path_is_readable("%s/config", grp_dev))
util_file_read_l(&config, 10, "%s/config", grp_dev);
if (util_path_is_readable("%s/online", grp_dev))
util_file_read_l(&online, 10, "%s/online", grp_dev);
if (config == 0) {
util_rec_set(rec, "status", "deconfig");
} else {
if (online > 0)
util_rec_set(rec, "status", "online");
else if (online == 0)
util_rec_set(rec, "status", "offline");
else
util_rec_set(rec, "status", "-");
}
util_file_read_line(buf, sizeof(buf), "%s/request_count", grp_dev);
util_rec_set(rec, "requests", buf);
if (config == 0) {
util_rec_set(rec, "requests", "-");
} else {
util_file_read_line(buf, sizeof(buf), "%s/request_count", grp_dev);
util_rec_set(rec, "requests", buf);
}
}
/*
@@ -513,15 +565,22 @@ static void read_rec_verbose(struct util_rec *rec, const char *grp_dev)
{
int i;
unsigned long facility;
char buf[256], afile[PATH_MAX];
long depth, pending1, pending2;
char buf[256];
long depth, pending1, pending2, config = -1;
if (l.verbose == 0)
return;
util_file_read_l(&pending1, 10, "%s/pendingq_count", grp_dev);
util_file_read_l(&pending2, 10, "%s/requestq_count", grp_dev);
util_rec_set(rec, "pending", "%ld", pending1 + pending2);
if (util_path_is_readable("%s/config", grp_dev))
util_file_read_l(&config, 10, "%s/config", grp_dev);
if (config == 0) {
util_rec_set(rec, "pending", "-");
} else {
util_file_read_l(&pending1, 10, "%s/pendingq_count", grp_dev);
util_file_read_l(&pending2, 10, "%s/requestq_count", grp_dev);
util_rec_set(rec, "pending", "%ld", pending1 + pending2);
}
util_file_read_line(buf, sizeof(buf), "%s/hwtype", grp_dev);
util_rec_set(rec, "hwtype", buf);
@@ -535,13 +594,8 @@ static void read_rec_verbose(struct util_rec *rec, const char *grp_dev)
buf[i] = '\0';
util_rec_set(rec, "facility", buf);
snprintf(afile, sizeof(afile), "%s/driver", grp_dev);
afile[sizeof(afile) - 1] = '\0';
memset(buf, 0, sizeof(buf));
if (readlink(afile, buf, sizeof(buf)) > 0)
util_rec_set(rec, "driver", strrchr(buf, '/') + 1);
else
util_rec_set(rec, "driver", "-no-driver-");
i = read_driver(grp_dev, NULL, buf, sizeof(buf));
util_rec_set(rec, "driver", i > 0 ? buf : "-no-driver-");
}
/*
@@ -581,10 +635,10 @@ out_free:
*/
static void define_rec_default(struct util_rec *rec)
{
util_rec_def(rec, "card", UTIL_REC_ALIGN_LEFT, 11, "CARD.DOMAIN");
util_rec_def(rec, "card", UTIL_REC_ALIGN_LEFT, 8, "CARD.DOM");
util_rec_def(rec, "type", UTIL_REC_ALIGN_LEFT, 5, "TYPE");
util_rec_def(rec, "mode", UTIL_REC_ALIGN_LEFT, 11, "MODE");
util_rec_def(rec, "online", UTIL_REC_ALIGN_LEFT, 8, "STATUS");
util_rec_def(rec, "status", UTIL_REC_ALIGN_LEFT, 10, "STATUS");
util_rec_def(rec, "requests", UTIL_REC_ALIGN_RIGHT, 8, "REQUESTS");
}

View File

@@ -7,6 +7,7 @@ all:
install: all
$(MAKE) -C src install
$(MAKE) -C man install
$(MAKE) -C udev install
$(MAKE) -C dracut install
$(MAKE) -C initramfs install

View File

@@ -20,7 +20,7 @@ check() {
[ "$_arch" = "s390" -o "$_arch" = "s390x" ] || return 1
# Ensure that required tools are available
require_binaries chzdev lszdev || return 1
require_binaries chzdev lszdev /lib/s390-tools/zdev_id || return 1
return 0
}
@@ -40,11 +40,14 @@ install() {
local _tempfile
# Ensure that required tools are available
inst_multiple chzdev lszdev vmcp
inst_multiple chzdev lszdev vmcp /lib/s390-tools/zdev_id
# Hook to parse zdev kernel parameter
inst_hook cmdline 95 "$moddir/parse-zdev.sh"
# Rule to automatically enable devices when running in DPM
inst_rules "81-dpm.rules"
# Obtain early + root device configuration
_tempfile=$(mktemp --tmpdir dracut-zdev.XXXXXX)
chzdev --export "$_tempfile" --persistent --by-path / --quiet \

View File

@@ -1,6 +1,6 @@
#!/bin/sh
#
# Copyright IBM Corp. 2017
# Copyright IBM Corp. 2017,2021
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
@@ -15,11 +15,14 @@
# where
#
# no-auto: Indicates that firmware-provided I/O configuration data
# should not be applied.
# should not be applied. This also affects automatic
# activation of PCI and crypto devices when running in a DPM
# LPAR.
#
zdev_fw_file="/sys/firmware/sclp_sd/config/data"
zdev_base_args="--force --yes --no-root-update --no-settle --auto-conf --quiet"
zdev_id="/lib/s390-tools/zdev_id"
if [ -e "$zdev_fw_file" ] ; then
zdev_auto=1
@@ -35,4 +38,22 @@ done
if [ $zdev_auto -eq 1 ] ; then
chzdev --import "$zdev_fw_file" $zdev_base_args
# Get information about DPM environment
for line in $($zdev_id) ; do
eval "$line"
done
if [ "$ZDEV_IS_DPM,$ZDEV_NEST_LEVEL,$ZDEV_HYPERVISOR_0" = "1,1,LPAR" ] ; then
# Manually iterate over existing PCI devices - there is a udev rule
# that handles this for PCI devices added at runtime but that doesn't
# work for PCI devices defined before boot because there is no coldplug
# trigger for /sys/bus/pci/slots
for slot in /sys/bus/pci/slots/* ; do
read power < "$slot/power"
if [ "$power" = "0" ] ; then
echo 1 > "$slot/power"
fi
done
fi
fi

View File

@@ -38,6 +38,9 @@ done
copy_exec /sbin/chzdev
copy_exec /sbin/lszdev
copy_exec /sbin/vmcp
copy_exec /lib/s390-tools/zdev_id
cp -p /usr/lib/udev/rules.d/81-dpm.rules "$DESTDIR/usr/lib/udev/rules.d/"
_tempfile=$(mktemp --tmpdir initramfs-zdev.XXXXXX)

View File

@@ -1,6 +1,6 @@
#!/bin/sh
#
# Copyright IBM Corp. 2017
# Copyright IBM Corp. 2017,2021
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
@@ -15,7 +15,9 @@
# where
#
# no-auto: Indicates that firmware-provided I/O configuration data
# should not be applied.
# should not be applied. This also affects automatic
# activation of PCI and crypto devices when running in a DPM
# LPAR.
#
PREREQ="udev"
@@ -36,6 +38,7 @@ esac
zdev_fw_file="/sys/firmware/sclp_sd/config/data"
zdev_base_args="--force --yes --no-root-update --no-settle --auto-conf --quiet"
zdev_id="/lib/s390-tools/zdev_id"
if [ -e "$zdev_fw_file" ] ; then
zdev_auto=1
@@ -64,4 +67,22 @@ if [ $zdev_auto -eq 1 ] ; then
udevadm trigger --type=subsystems --action=add
udevadm trigger --action=add
udevadm settle || true
# Get information about DPM environment
for line in $($zdev_id) ; do
eval "$line"
done
if [ "$ZDEV_IS_DPM,$ZDEV_NEST_LEVEL,$ZDEV_HYPERVISOR_0" = "1,1,LPAR" ] ; then
# Manually iterate over existing PCI devices - there is a udev
# rule that handles this for PCI devices added at runtime but
# that doesn't work for PCI devices defined before boot because
# there is no coldplug trigger for /sys/bus/pci/slots
for slot in /sys/bus/pci/slots/* ; do
read power < "$slot/power"
if [ "$power" = "0" ] ; then
echo 1 > "$slot/power"
fi
done
fi
fi

View File

@@ -73,7 +73,7 @@ lszdev_objects += lcs.o lcs_auto.o
# Generic CCW devtype
lszdev_objects += generic_ccw.o
all: chzdev lszdev
all: chzdev lszdev zdev_id
chzdev_usage.c: chzdev_usage.txt
$(SED) $< >$@ -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/^/"/g' \
@@ -95,16 +95,17 @@ libs = $(rootdir)/libutil/libutil.a
chzdev: $(chzdev_objects) $(libs)
lszdev: $(lszdev_objects) $(libs)
install: chzdev
install: chzdev zdev_id
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR)
$(INSTALL) -c chzdev $(DESTDIR)$(BINDIR)
$(INSTALL) -c lszdev $(DESTDIR)$(BINDIR)
$(INSTALL) -c zdev_id $(DESTDIR)$(TOOLS_LIBDIR)
ifeq ($(HAVE_DRACUT),1)
$(INSTALL) -m 755 zdev-root-update.dracut \
$(DESTDIR)$(TOOLS_LIBDIR)/zdev-root-update
endif
clean:
@rm -f *.o chzdev lszdev chzdev_usage.c lszdev_usage.c gmon.out *.gcda *.gcno
@rm -f *.o chzdev lszdev chzdev_usage.c lszdev_usage.c gmon.out *.gcda *.gcno zdev_id
.PHONY: all install clean

View File

@@ -7,6 +7,7 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -16,6 +17,7 @@
#include "misc.h"
#define LSBLK_CMDLINE "lsblk -P -o NAME,MAJ:MIN,FSTYPE,UUID,MOUNTPOINT,PKNAME 2>/dev/null"
#define LSBLK_CMDLINE2 "lsblk -P -o NAME,MAJ:MIN,FSTYPE,UUID,MOUNTPOINTS,PKNAME 2>/dev/null"
struct blkinfo {
struct devnode *devnode;
@@ -82,6 +84,26 @@ void blkinfo_print(struct blkinfo *blkinfo, int level)
printf("%*sparent=%s\n", level, "", blkinfo->parent);
}
/* Convert each occurrence of '\xnn' in @str to character with hex code <nn>. */
static void hex_unescape(char *str)
{
unsigned int c;
while ((str = strstr(str, "\\x"))) {
if (isxdigit(str[2]) && isxdigit(str[3]) &&
sscanf(str + 2, "%2x", &c) == 1) {
str[0] = (char)c;
/* Move remainder of str including nul behind <c>. */
memmove(str + /* <c> */ 1,
str + /* '\xnn' */ 4,
strlen(str + 4) + /* <nul> */ 1);
}
str++;
}
}
static char *isolate_keyword(char **line_ptr, const char *keyword)
{
char *start, *end;
@@ -102,30 +124,58 @@ static char *isolate_keyword(char **line_ptr, const char *keyword)
return start;
}
static struct blkinfo *blkinfo_from_line(char *line)
static void add_blkinfos_from_line(struct util_list *blkinfos,
char *line)
{
char *name, *majmin, *fstype, *uuid, *mountpoint, *parent;
char *name, *majmin, *fstype, *uuid, *mountpoint, *mountpoints, *parent;
struct blkinfo *blkinfo;
name = isolate_keyword(&line, "NAME=\"");
majmin = isolate_keyword(&line, "MAJ:MIN=\"");
if (!majmin)
majmin = isolate_keyword(&line, "MAJ_MIN=\"");
fstype = isolate_keyword(&line, "FSTYPE=\"");
uuid = isolate_keyword(&line, "UUID=\"");
mountpoint = isolate_keyword(&line, "MOUNTPOINT=\"");
mountpoints = isolate_keyword(&line, "MOUNTPOINTS=\"");
parent = isolate_keyword(&line, "PKNAME=\"");
return blkinfo_new(name, majmin, fstype, uuid, mountpoint, parent);
if (!mountpoints) {
/* Handle old lsblk output format. */
blkinfo = blkinfo_new(name, majmin, fstype, uuid, mountpoint,
parent);
ptrlist_add(blkinfos, blkinfo);
return;
}
/* Restore newline mount point separator encoded as hex. */
hex_unescape(mountpoints);
/* Represent each mount point as a separate blkinfo to support
* resolution of multi-mount point file systems like btrfs
* subvolumes. */
while ((mountpoint = strsep(&mountpoints, "\n"))) {
blkinfo = blkinfo_new(name, majmin, fstype, uuid, mountpoint,
parent);
ptrlist_add(blkinfos, blkinfo);
}
}
static struct util_list *blkinfos_read(void)
{
char *output, *curr, *next;
struct util_list *blkinfos;
struct blkinfo *blkinfo;
if (cached_blkinfos)
return cached_blkinfos;
output = misc_read_cmd_output(LSBLK_CMDLINE, 0, 1);
output = misc_read_cmd_output(LSBLK_CMDLINE2, 0, 1);
if (output && !*output) {
/* No output might indicate no support for new lsblk command-
* line format - fall back to old format. */
free(output);
output = misc_read_cmd_output(LSBLK_CMDLINE, 0, 1);
}
if (!output)
return NULL;
@@ -134,9 +184,7 @@ static struct util_list *blkinfos_read(void)
/* Iterate over each line. */
next = output;
while ((curr = strsep(&next, "\n"))) {
blkinfo = blkinfo_from_line(curr);
if (blkinfo)
ptrlist_add(blkinfos, blkinfo);
add_blkinfos_from_line(blkinfos, curr);
}
free(output);

View File

@@ -2088,12 +2088,18 @@ static exit_code_t devtype_remove_settings(struct devtype *dt, config_t config,
found = strlist_new();
notfound = strlist_new();
if (SCOPE_ACTIVE(config))
remove_settings(dt->active_settings, names, found, notfound, 1);
if (SCOPE_ACTIVE(config)) {
rc = remove_settings(dt->active_settings, names, found,
notfound, 1);
if (rc)
goto out;
}
if (SCOPE_PERSISTENT(config)) {
remove_settings(dt->persistent_settings, names, found,
notfound, 0);
rc = remove_settings(dt->persistent_settings, names, found,
notfound, 0);
if (rc)
goto out;
}
if (!util_list_is_empty(notfound)) {
@@ -2104,6 +2110,7 @@ static exit_code_t devtype_remove_settings(struct devtype *dt, config_t config,
rc = EXIT_SETTING_NOT_FOUND;
}
out:
strlist_free(found);
strlist_free(notfound);

154
zdev/src/zdev_id.c Normal file
View File

@@ -0,0 +1,154 @@
/*
* zdev_id - Determine system characteristics required by zdev udev rules
*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SYSINFO "/proc/sysinfo"
#define CMDLINE "/proc/cmdline"
#define WHITESPACE " \t\n"
static void array_add(char ***array_p, int *num_p, const char *str)
{
char **array = *array_p, *copy;
int num = *num_p + 1;
array = realloc(array, num * sizeof(char *));
copy = strdup(str);
if (!array || !copy)
err(1, "Could not allocate memory");
array[num - 1] = copy;
*array_p = array;
*num_p = num;
}
static void array_free(char **array, int num)
{
int i;
for (i = 0; i < num; i++)
free(array[i]);
free(array);
}
static void process_sysinfo(const char *filename)
{
char *line = NULL, *substr, **cps = NULL;
int is_dpm = 0, num_cps = 0, level, i;
FILE *fd;
size_t n;
fd = fopen(filename, "r");
if (!fd)
err(1, "Could not open sysinfo file '%s'", filename);
while (getline(&line, &n, fd) != -1) {
if (sscanf(line, "LPAR %m[^:]", &substr) == 1) {
if (strcmp(substr, "UUID") == 0) {
/* Heuristic: only DPM LPARs have UUIDs. */
is_dpm = 1;
} else if (strcmp(substr, "Number") == 0) {
array_add(&cps, &num_cps, "LPAR");
}
free(substr);
} else if (sscanf(line, "VM%*d Control Program: %ms ",
&substr) == 1) {
array_add(&cps, &num_cps, substr);
free(substr);
}
}
free(line);
fclose(fd);
/*
* ZDEV_NEST_LEVEL=n
*
* Virtualization nesting level of running system:
* 1: LPAR
* 2: first level VM
* 3: second level VM
*/
printf("ZDEV_NEST_LEVEL=%d\n", num_cps);
/*
* ZDEV_HYPERVISOR_<n>=LPAR|z/VM|KVM/Linux
*
* Type of hypervisor that provides virtualization at nesting level <n>.
*/
for (i = 0; i < num_cps; i++) {
/* Sysinfo lists VMs in reverse order .*/
level = (i == 0) ? i : (num_cps - i);
printf("ZDEV_HYPERVISOR_%d=\"%s\"\n", i, cps[level]);
}
array_free(cps, num_cps);
/*
* ZDEV_IS_DPM=0|1
*
* Indicator if top-level LPAR is managed by Dynamic Partition
* Manager (DPM):
* 0: Classic mode
* 1: DPM mode
*/
printf("ZDEV_IS_DPM=%d\n", is_dpm);
}
static void process_cmdline(const char *filename)
{
char *line = NULL, *substr, *next = NULL, *value;
int no_auto = 0;
size_t n;
FILE *fd;
fd = fopen(filename, "r");
if (!fd)
err(1, "Could not open cmdline file '%s'", filename);
if (getline(&line, &n, fd) == -1)
goto out;
for (substr = strtok_r(line, WHITESPACE, &next); substr;
substr = strtok_r(NULL, WHITESPACE, &next)) {
if (sscanf(substr, "rd.zdev=%ms ", &value) != 1)
continue;
if (strstr(value, "no-auto"))
no_auto = 1;
free(value);
}
out:
free(line);
fclose(fd);
/*
* ZDEV_NO_AUTO=0|1
*
* Indicator if auto-configuration is requested.
* 0: Perform auto-configuration
* 1: Skip auto-configuration
*/
printf("ZDEV_NO_AUTO=%d\n", no_auto);
}
int main(int argc, char *argv[])
{
char *sysinfo, *cmdline;
sysinfo = argc < 2 ? SYSINFO : argv[1];
cmdline = argc < 3 ? CMDLINE : argv[2];
process_sysinfo(sysinfo);
process_cmdline(cmdline);
return 0;
}

40
zdev/udev/81-dpm.rules Normal file
View File

@@ -0,0 +1,40 @@
# Automatically activate certain s390-specific device types that are attached
# in offline state when running in an LPAR managed by the Dynamic Partition
# Manager (DPM).
#
# Note that processing is restricted to DPM as there may be use cases for
# not enabling these device types in non-DPM mode.
#
# To deactivate this processing, specify the following on the kernel command
# line:
#
# rd.zdev=no-auto
ACTION!="add", GOTO="end_dpm"
# Handle newly added PCI devices in offline state
SUBSYSTEM=="slots", ATTR{power}=="0", GOTO="check_dpm"
# Handle newly added crypto devices in offline state
SUBSYSTEM=="ap", ENV{DEVTYPE}=="ap_card", ATTR{config}=="0", GOTO="check_dpm"
GOTO="end_dpm"
LABEL="check_dpm"
IMPORT{program}="/lib/s390-tools/zdev_id"
# Check for off-switch
ENV{ZDEV_NO_AUTO}=="1", GOTO="end_dpm"
# Check for DPM LPAR
ENV{ZDEV_IS_DPM}!="1", GOTO="end_dpm"
ENV{ZDEV_NEST_LEVEL}!="1", GOTO="end_dpm"
ENV{ZDEV_HYPERVISOR_0}!="LPAR", GOTO="end_dpm"
# Enable PCI device
SUBSYSTEM=="slots", ATTR{power}="1"
# Enable crypto device
SUBSYSTEM=="ap", ATTR{config}="1"
# End of rule
LABEL="end_dpm"

9
zdev/udev/Makefile Normal file
View File

@@ -0,0 +1,9 @@
# Common definitions
include ../../common.mak
UDEVDIR := /usr/lib/udev/rules.d/
RULES := 81-dpm.rules
install:
$(INSTALL) -m 755 -d $(DESTDIR)$(UDEVDIR)
$(INSTALL) -m 644 $(RULES) $(DESTDIR)$(UDEVDIR)/

View File

@@ -30,8 +30,9 @@ check_dep:
$(call check_dep, \
"zdsfs", \
"fuse.h", \
"fuse-devel or libfuse-dev", \
"HAVE_FUSE=0")
"fuse3-devel or libfuse3-dev", \
"HAVE_FUSE=0", \
"-DFUSE_USE_VERSION=30")
$(call check_dep, \
"zdsfs", \
"curl/curl.h", \
@@ -39,13 +40,13 @@ check_dep:
"HAVE_CURL=0")
ifneq ($(shell sh -c 'command -v pkg-config'),)
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse)
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse)
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse3)
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse3)
CURL_CFLAGS = $(shell pkg-config --silence-errors --cflags libcurl)
CURL_LDLIBS = $(shell pkg-config --silence-errors --libs libcurl)
else
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse
FUSE_LDLIBS = -lfuse
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse3
FUSE_LDLIBS = -lfuse3
CURL_CFLAGS = -I/usr/include/s390x-linux-gnu/curl
CURL_LDLIBS = -lcurl
endif

View File

@@ -227,9 +227,6 @@ Allow access by other users
\fB\-o\fR allow_root
Allow access by root
.TP
\fB\-o\fR nonempty
Allow mounts over non\-empty file/dir
.TP
\fB\-o\fR default_permissions
Enable permission checking by kernel
.TP

View File

@@ -8,7 +8,7 @@
*/
/* The fuse version define tells fuse that we want to use the new API */
#define FUSE_USE_VERSION 26
#define FUSE_USE_VERSION 30
#include <errno.h>
#include <fcntl.h>
@@ -312,7 +312,8 @@ void keepalive_start(void)
setup_timer(zdsfsinfo.keepalive);
}
static int zdsfs_getattr(const char *path, struct stat *stbuf)
static int zdsfs_getattr(const char *path, struct stat *stbuf,
struct fuse_file_info *UNUSED(fi))
{
char normds[MAXDSNAMELENGTH];
size_t dssize;
@@ -524,7 +525,8 @@ static int zdsfs_update_vtoc(void)
}
static int zdsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t UNUSED(offset), struct fuse_file_info *UNUSED(fi))
off_t UNUSED(offset), struct fuse_file_info *UNUSED(fi),
enum fuse_readdir_flags UNUSED(flags))
{
char normds[MAXDSNAMELENGTH];
char *mbrname;
@@ -544,9 +546,9 @@ static int zdsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
* type one: the root directory contains all data sets
*/
if (strcmp(path, "/") == 0) {
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, METADATAFILE, NULL, 0);
filler(buf, ".", NULL, 0, 0);
filler(buf, "..", NULL, 0, 0);
filler(buf, METADATAFILE, NULL, 0, 0);
/* note that we do not need to distinguish between
* normal files and directories here, that is done
* in the rdf_getattr function
@@ -558,7 +560,7 @@ static int zdsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
lzds_dataset_get_is_supported(ds, &issupported);
if (issupported) {
lzds_dataset_get_name(ds, &dsname);
filler(buf, dsname, NULL, 0);
filler(buf, dsname, NULL, 0, 0);
}
}
lzds_dsiterator_free(dsit);
@@ -572,14 +574,14 @@ static int zdsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
return -ENOENT;
lzds_dataset_get_is_PDS(ds, &ispds);
if (ispds) {
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, ".", NULL, 0, 0);
filler(buf, "..", NULL, 0, 0);
rc = lzds_dataset_alloc_memberiterator(ds, &it);
if (rc)
return -ENOMEM;
while (!lzds_memberiterator_get_next_member(it, &member)) {
lzds_pdsmember_get_name(member, &mbrname);
filler(buf, mbrname, NULL, 0);
filler(buf, mbrname, NULL, 0, 0);
}
lzds_memberiterator_free(it);
} else

View File

@@ -1,5 +1,7 @@
include ../common.mak
ALL_CFLAGS += -Wno-address-of-packed-member
#
# HAVE_FUSE: Allow to build zgetdump without mount support
#
@@ -13,8 +15,9 @@ check_dep_fuse:
$(call check_dep, \
"zgetdump mount support", \
"fuse.h", \
"fuse-devel or libfuse-dev", \
"HAVE_FUSE=0")
"fuse3-devel or libfuse3-dev", \
"HAVE_FUSE=0", \
"-DFUSE_USE_VERSION=30")
endif
#
@@ -39,28 +42,28 @@ check_dep_zlib:
all: check_dep_fuse check_dep_zlib zgetdump
OBJECTS = zgetdump.o opts.o zg.o \
dfi.o dfi_vmcoreinfo.o \
OBJECTS = zgetdump.o opts.o zg.o zg_error.o zg_print.o \
dfi.o dfi_mem_chunk.o dfi_vmcoreinfo.o \
dfi_lkcd.o dfi_elf.o \
dfi_s390.o dfi_s390_ext.o\
dfi_s390mv.o dfi_s390mv_ext.o \
dfi_s390tape.o dfi_kdump.o \
dfi_devmem.o dfo.o \
dfi_devmem.o dfo.o dfo_mem_chunk.o \
dfo_elf.o dfo_s390.o \
df_s390.o \
df_elf.o df_s390.o \
dt.o dt_s390sv.o dt_s390sv_ext.o \
dt_s390mv.o dt_s390mv_ext.o \
dt_scsi.o stdout.o \
dt_scsi.o output.o
ifeq ("$(HAVE_FUSE)","0")
FUSE_CFLAGS = -DHAVE_FUSE=0 -D_FILE_OFFSET_BITS=64
FUSE_LDLIBS =
else ifneq ($(shell sh -c 'command -v pkg-config'),)
FUSE_CFLAGS = -DHAVE_FUSE=1 $(shell pkg-config --silence-errors --cflags fuse)
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse)
FUSE_CFLAGS = -DHAVE_FUSE=1 $(shell pkg-config --silence-errors --cflags fuse3)
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse3)
else
FUSE_CFLAGS = -DHAVE_FUSE=1 -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse
FUSE_LDLIBS = -lfuse
FUSE_CFLAGS = -DHAVE_FUSE=1 -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse3
FUSE_LDLIBS = -lfuse3
endif
LDLIBS += -lz $(FUSE_LDLIBS)
ALL_CFLAGS += $(FUSE_CFLAGS)

191
zdump/df_elf.c Normal file
View File

@@ -0,0 +1,191 @@
/*
* Copyright IBM Corp. 2001, 2018, 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <string.h>
#include "df_elf.h"
#define NOTE_NAME_CORE "CORE"
#define NOTE_NAME_LINUX "LINUX"
#define NOTE_NAME_VMCOREINFO "VMCOREINFO"
/*
* Initialize ELF header
*/
void *ehdr_init(Elf64_Ehdr *ehdr, Elf64_Half phnum)
{
memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
ehdr->e_ident[EI_CLASS] = ELFCLASS64;
ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
ehdr->e_ident[EI_VERSION] = EV_CURRENT;
ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;
ehdr->e_ident[EI_ABIVERSION] = 0;
memset(ehdr->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
ehdr->e_type = ET_CORE;
ehdr->e_machine = EM_S390;
ehdr->e_version = EV_CURRENT;
ehdr->e_entry = 0;
ehdr->e_phoff = sizeof(Elf64_Ehdr);
ehdr->e_shoff = 0;
ehdr->e_flags = 0;
ehdr->e_ehsize = sizeof(Elf64_Ehdr);
ehdr->e_phentsize = sizeof(Elf64_Phdr);
ehdr->e_phnum = phnum;
ehdr->e_shentsize = 0;
ehdr->e_shnum = 0;
ehdr->e_shstrndx = 0;
return ehdr + 1;
}
/*
* Initialize ELF note
*/
void *nt_init(void *buf, Elf64_Word type, const void *desc, int d_len,
const char *name)
{
Elf64_Nhdr *note;
u64 len;
note = (Elf64_Nhdr *)buf;
note->n_namesz = strlen(name) + 1;
note->n_descsz = d_len;
note->n_type = type;
len = sizeof(Elf64_Nhdr);
memcpy(buf + len, name, note->n_namesz);
len = ROUNDUP(len + note->n_namesz, 4);
memcpy(buf + len, desc, note->n_descsz);
len = ROUNDUP(len + note->n_descsz, 4);
return PTR_ADD(buf, len);
}
/*
* Initialize prstatus note
*/
void *nt_prstatus(void *ptr, const struct dfi_cpu *cpu)
{
struct nt_prstatus_64 nt_prstatus;
static int cpu_nr = 1;
memset(&nt_prstatus, 0, sizeof(nt_prstatus));
memcpy(&nt_prstatus.gprs, cpu->gprs, sizeof(cpu->gprs));
memcpy(&nt_prstatus.psw, cpu->psw, sizeof(cpu->psw));
memcpy(&nt_prstatus.acrs, cpu->acrs, sizeof(cpu->acrs));
nt_prstatus.pr_pid = cpu_nr;
cpu_nr++;
return nt_init(ptr, NT_PRSTATUS, &nt_prstatus, sizeof(nt_prstatus),
NOTE_NAME_CORE);
}
/*
* Initialize fpregset (floating point) note
*/
void *nt_fpregset(void *ptr, const struct dfi_cpu *cpu)
{
struct nt_fpregset_64 nt_fpregset;
memset(&nt_fpregset, 0, sizeof(nt_fpregset));
memcpy(&nt_fpregset.fpc, &cpu->fpc, sizeof(cpu->fpc));
memcpy(&nt_fpregset.fprs, &cpu->fprs, sizeof(cpu->fprs));
return nt_init(ptr, NT_FPREGSET, &nt_fpregset, sizeof(nt_fpregset),
NOTE_NAME_CORE);
}
/*
* Initialize timer note
*/
void *nt_s390_timer(void *ptr, const struct dfi_cpu *cpu)
{
return nt_init(ptr, NT_S390_TIMER, &cpu->timer, sizeof(cpu->timer),
NOTE_NAME_LINUX);
}
/*
* Initialize TOD clock comparator note
*/
void *nt_s390_tod_cmp(void *ptr, const struct dfi_cpu *cpu)
{
return nt_init(ptr, NT_S390_TODCMP, &cpu->todcmp,
sizeof(cpu->todcmp), NOTE_NAME_LINUX);
}
/*
* Initialize TOD programmable register note
*/
void *nt_s390_tod_preg(void *ptr, const struct dfi_cpu *cpu)
{
return nt_init(ptr, NT_S390_TODPREG, &cpu->todpreg,
sizeof(cpu->todpreg), NOTE_NAME_LINUX);
}
/*
* Initialize control register note
*/
void *nt_s390_ctrs(void *ptr, const struct dfi_cpu *cpu)
{
return nt_init(ptr, NT_S390_CTRS, &cpu->ctrs, sizeof(cpu->ctrs),
NOTE_NAME_LINUX);
}
/*
* Initialize prefix register note
*/
void *nt_s390_prefix(void *ptr, const struct dfi_cpu *cpu)
{
return nt_init(ptr, NT_S390_PREFIX, &cpu->prefix,
sizeof(cpu->prefix), NOTE_NAME_LINUX);
}
/*
* Initialize vxrs_low register note
*/
void *nt_s390_vxrs_low(void *ptr, const struct dfi_cpu *cpu)
{
return nt_init(ptr, NT_S390_VXRS_LOW, &cpu->vxrs_low,
sizeof(cpu->vxrs_low), NOTE_NAME_LINUX);
}
/*
* Initialize vxrs_high register note
*/
void *nt_s390_vxrs_high(void *ptr, const struct dfi_cpu *cpu)
{
return nt_init(ptr, NT_S390_VXRS_HIGH, &cpu->vxrs_high,
sizeof(cpu->vxrs_high), NOTE_NAME_LINUX);
}
/*
* Initialize prpsinfo note
*/
void *nt_prpsinfo(void *ptr)
{
struct nt_prpsinfo_64 prpsinfo;
memset(&prpsinfo, 0, sizeof(prpsinfo));
prpsinfo.pr_state = 0;
prpsinfo.pr_sname = 'R';
prpsinfo.pr_zomb = 0;
strcpy(prpsinfo.pr_fname, "vmlinux");
return nt_init(ptr, NT_PRPSINFO, &prpsinfo, sizeof(prpsinfo),
NOTE_NAME_CORE);
}
/*
* Initialize vmcoreinfo note
*/
void *nt_vmcoreinfo(void *ptr, const char *vmcoreinfo)
{
if (!vmcoreinfo)
return ptr;
return nt_init(ptr, 0, vmcoreinfo, strlen(vmcoreinfo),
NOTE_NAME_VMCOREINFO);
}

View File

@@ -17,8 +17,8 @@
#include "lib/zt_common.h"
#include "dfo.h"
#include "zg.h"
#include "dfi.h"
/*
* S390 CPU timer note (u64)
@@ -116,4 +116,20 @@ static inline void df_elf_ensure_s390x(void)
#endif
}
void *ehdr_init(Elf64_Ehdr *ehdr, Elf64_Half phnum);
void *nt_init(void *buf, Elf64_Word type, const void *desc, int d_len,
const char *name);
void *nt_prstatus(void *ptr, const struct dfi_cpu *cpu);
void *nt_fpregset(void *ptr, const struct dfi_cpu *cpu);
void *nt_s390_timer(void *ptr, const struct dfi_cpu *cpu);
void *nt_s390_tod_cmp(void *ptr, const struct dfi_cpu *cpu);
void *nt_s390_tod_preg(void *ptr, const struct dfi_cpu *cpu);
void *nt_s390_ctrs(void *ptr, const struct dfi_cpu *cpu);
void *nt_s390_prefix(void *ptr, const struct dfi_cpu *cpu);
void *nt_s390_vxrs_low(void *ptr, const struct dfi_cpu *cpu);
void *nt_s390_vxrs_high(void *ptr, const struct dfi_cpu *cpu);
void *nt_prpsinfo(void *ptr);
void *nt_vmcoreinfo(void *ptr, const char *vmcoreinfo);
#endif /* DF_ELF_H */

View File

@@ -17,7 +17,7 @@
#include <time.h>
#include <unistd.h>
#include "zgetdump.h"
#include "df_s390.h"
/*
* Check, if we can access the lowcore information in the dump
@@ -37,9 +37,10 @@ static int check_addr_max(struct df_s390_hdr *hdr, u64 addr_max)
/*
* Convert lowcore information into internal CPU representation
*/
void df_s390_cpu_info_add(struct df_s390_hdr *hdr, u64 addr_max)
int df_s390_cpu_info_add(struct df_s390_hdr *hdr, u64 addr_max)
{
unsigned int i;
int rc;
if (hdr->version < 5 && hdr->magic == DF_S390_MAGIC) {
/* No Prefix registers in header */
@@ -53,8 +54,13 @@ void df_s390_cpu_info_add(struct df_s390_hdr *hdr, u64 addr_max)
dfi_cpu_info_init(DFI_CPU_CONTENT_ALL);
}
for (i = 0; i < hdr->cpu_cnt; i++)
dfi_cpu_add_from_lc(hdr->lc_vec[i]);
for (i = 0; i < hdr->cpu_cnt; i++) {
rc = dfi_cpu_add_from_lc(hdr->lc_vec[i]);
if (rc)
return rc;
}
return 0;
}
/*

View File

@@ -127,7 +127,7 @@ struct df_s390_dumper {
*/
extern void df_s390_hdr_add(struct df_s390_hdr *hdr);
extern void df_s390_em_add(struct df_s390_em *em);
extern void df_s390_cpu_info_add(struct df_s390_hdr *hdr, u64 addr_max);
extern int df_s390_cpu_info_add(struct df_s390_hdr *hdr, u64 addr_max);
extern int df_s390_em_verify(struct df_s390_em *em, struct df_s390_hdr *hdr);
extern void df_s390_dumper_read(struct zg_fh *fh, int32_t blk_size,
struct df_s390_dumper *dumper);

View File

@@ -9,12 +9,19 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <time.h>
#include "lib/util_log.h"
#include "zgetdump.h"
#include "dfi_mem_chunk.h"
#include "dfi_vmcoreinfo.h"
#include "dfi.h"
#define TIME_FMT_STR "%a, %d %b %Y %H:%M:%S %z"
#define PROGRESS_HASH_CNT 50
#define KDUMP_OLDMEM_BASE 0x10418
#define KDUMP_OLDMEM_SIZE 0x10420
/*
* DFI vector - ensure that tape is the first in the list and devmem the second!
*/
@@ -47,17 +54,6 @@ struct cpus {
unsigned int cnt;
};
/*
* Memory information
*/
struct mem {
struct dfi_mem_chunk *chunk_cache;
u64 start_addr;
u64 end_addr;
unsigned int chunk_cnt;
struct util_list chunk_list;
};
/*
* Dump header attribute information
*/
@@ -81,8 +77,6 @@ struct attr {
static struct {
enum dfi_arch arch;
struct attr attr;
struct mem mem_phys;
struct mem mem_virt;
struct cpus cpus;
struct dfi *dfi;
unsigned long kdump_base;
@@ -109,125 +103,6 @@ static void date_print(void)
}
}
/*
* Initialize DFI memory chunks
*/
static void mem_init(struct mem *mem)
{
mem->start_addr = U64_MAX;
mem->end_addr = 0;
util_list_init(&mem->chunk_list, struct dfi_mem_chunk, list);
}
/*
* Memory chunk compare function for list sorting
*/
static int mem_chunk_cmp_fn(void *a, void *b, void *UNUSED(data))
{
struct dfi_mem_chunk *mem_chunk1 = a;
struct dfi_mem_chunk *mem_chunk2 = b;
return mem_chunk1->start < mem_chunk2->start ? -1 : 1;
}
/*
* Update DFI memory chunks
*/
static void mem_update(struct mem *mem)
{
struct dfi_mem_chunk *mem_chunk;
util_list_sort(&mem->chunk_list, mem_chunk_cmp_fn, NULL);
mem->start_addr = U64_MAX;
mem->end_addr = 0;
util_list_iterate(&mem->chunk_list, mem_chunk) {
mem->start_addr = MIN(mem->start_addr, mem_chunk->start);
mem->end_addr = MAX(mem->end_addr, mem_chunk->end);
}
}
/*
* Print memory map
*/
static void mem_map_print(void)
{
struct dfi_mem_chunk *mem_chunk;
u64 print_start = 0, print_end = 0;
const char *zero_str;
u32 volnr = 0;
STDERR("\nMemory map:\n");
/*
* Print each memory chunk if verbose specified
*/
if (g.opts.verbose_specified) {
dfi_mem_chunk_iterate(mem_chunk) {
zero_str = "";
if (mem_chunk->read_fn == dfi_mem_chunk_read_zero)
zero_str = " zeroes";
STDERR(" %016llx - %016llx (%llu MB%s)\n",
mem_chunk->start, mem_chunk->end,
TO_MIB(mem_chunk->size), zero_str);
}
return;
}
/*
* Merge adjacent memory chunks from the same volume
*/
dfi_mem_chunk_iterate(mem_chunk) {
if (print_end == 0) {
print_start = mem_chunk->start;
print_end = mem_chunk->end;
volnr = mem_chunk->volnr;
continue;
}
if (mem_chunk->start != print_end + 1 ||
mem_chunk->volnr != volnr) {
STDERR(" %016llx - %016llx (%llu MB)\n", print_start,
print_end, TO_MIB(print_end - print_start + 1));
print_start = mem_chunk->start;
volnr = mem_chunk->volnr;
}
print_end = mem_chunk->end;
}
STDERR(" %016llx - %016llx (%llu MB)\n", print_start,
print_end, TO_MIB(print_end - print_start + 1));
}
/*
* 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;
}
/*
* Is memory already mapped at range?
*/
static int mem_range_mapped(u64 start, u64 size)
{
struct dfi_mem_chunk *mem_chunk;
u64 end = start + size - 1;
dfi_mem_chunk_iterate(mem_chunk) {
if (mem_chunk->start > end)
continue;
if (mem_chunk->end < start)
continue;
return 1;
}
return 0;
}
/*
* Print dump information (--info option)
*/
@@ -236,7 +111,7 @@ void dfi_info_print(void)
STDERR("General dump info:\n");
STDERR(" Dump format........: %s\n", l.dfi->name);
if (l.attr.dfi_version)
STDERR(" Version............: %d\n", *l.attr.dfi_version);
STDERR(" Version............: %u\n", *l.attr.dfi_version);
date_print();
if (l.attr.dump_method)
STDERR(" Dump method........: %s\n", l.attr.dump_method);
@@ -248,259 +123,32 @@ void dfi_info_print(void)
STDERR(" UTS kernel version.: %s\n", l.attr.utsname->version);
}
if (l.attr.vol_nr)
STDERR(" Volume number......: %d\n", *l.attr.vol_nr);
STDERR(" Volume number......: %u\n", *l.attr.vol_nr);
if (l.attr.build_arch)
STDERR(" Build arch.........: %s\n",
dfi_arch_str(*l.attr.build_arch));
dfi_arch_str(*l.attr.build_arch));
STDERR(" System arch........: %s\n", dfi_arch_str(l.arch));
if (l.cpus.cnt)
STDERR(" CPU count (online).: %d\n", l.cpus.cnt);
STDERR(" CPU count (online).: %u\n", l.cpus.cnt);
if (l.attr.real_cpu_cnt)
STDERR(" CPU count (real)...: %d\n", *l.attr.real_cpu_cnt);
STDERR(" CPU count (real)...: %u\n", *l.attr.real_cpu_cnt);
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));
TO_MIB(*l.attr.mem_size_real));
if (l.attr.file_size)
STDERR(" Dump file size.....: %lld MB\n",
TO_MIB(*l.attr.file_size));
TO_MIB(*l.attr.file_size));
if (dfi_mem_range())
mem_map_print();
dfi_mem_map_print(g.opts.verbose);
if (l.dfi->info_dump) {
STDERR("\nDump device info:\n");
l.dfi->info_dump();
}
}
/*
* Add memory chunk to memory
*/
static void mem_chunk_create(struct mem *mem, u64 start, u64 size, void *data,
dfi_mem_chunk_read_fn read_fn,
dfi_mem_chunk_free_fn free_fn)
{
struct dfi_mem_chunk *mem_chunk;
mem_chunk = zg_alloc(sizeof(*mem_chunk));
mem_chunk->start = start;
mem_chunk->end = start + size - 1;
mem_chunk->size = size;
mem_chunk->read_fn = read_fn;
mem_chunk->free_fn = free_fn;
mem_chunk->data = data;
util_list_add_tail(&mem->chunk_list, mem_chunk);
mem->start_addr = MIN(mem->start_addr, mem_chunk->start);
mem->end_addr = MAX(mem->end_addr, mem_chunk->end);
mem->chunk_cache = mem_chunk;
mem->chunk_cnt++;
}
/*
* Check if memory chunk contains address
*/
static int mem_chunk_has_addr(struct dfi_mem_chunk *mem_chunk, u64 addr)
{
return (addr >= mem_chunk->start && addr <= mem_chunk->end);
}
/*
* Find memory chunk that contains address
*/
static struct dfi_mem_chunk *mem_chunk_find(struct mem *mem, u64 addr)
{
struct dfi_mem_chunk *mem_chunk;
if (mem_chunk_has_addr(mem->chunk_cache, addr))
return mem->chunk_cache;
util_list_iterate(&mem->chunk_list, mem_chunk) {
if (mem_chunk_has_addr(mem_chunk, addr)) {
mem->chunk_cache = mem_chunk;
return mem_chunk;
}
}
return NULL;
}
/*
* Read memory at given address
*/
static void mem_read(struct mem *mem, u64 addr, void *buf, size_t cnt)
{
struct dfi_mem_chunk *mem_chunk;
u64 size, off, copied = 0;
while (copied != cnt) {
mem_chunk = mem_chunk_find(mem, addr);
size = MIN(cnt - copied, mem_chunk->end - addr + 1);
off = addr - mem_chunk->start;
mem_chunk->read_fn(mem_chunk, off, buf + copied, size);
copied += size;
addr += size;
}
}
/*
* Read memory for virtual map memory chunk
*/
static void mem_chunk_map_read_fn(struct dfi_mem_chunk *mem_chunk, u64 off,
void *buf, u64 cnt)
{
u64 *start = mem_chunk->data;
dfi_mem_phys_read(*start + off, buf, cnt);
}
/*
* Check if memory chunk is a virtual mapping
*/
static int mem_chunk_is_map(struct dfi_mem_chunk *mem_chunk)
{
return mem_chunk->read_fn == mem_chunk_map_read_fn;
}
/*
* Return physical start address for memory chunk
*/
static u64 mem_chunk_start_phys(struct dfi_mem_chunk *mem_chunk)
{
if (mem_chunk_is_map(mem_chunk))
return *((u64 *) mem_chunk->data);
else
return mem_chunk->start;
}
/*
* Add virtual memory chunk with simple virtual mapping
*/
static void mem_chunk_map_add(u64 start, u64 size, u64 start_p)
{
u64 *data = zg_alloc(sizeof(*data));
*data = start_p;
dfi_mem_chunk_virt_add(start, size, data, mem_chunk_map_read_fn,
zg_free);
}
/*
* Add virtual memory chunk
*/
void dfi_mem_chunk_virt_add(u64 start, u64 size, void *data,
dfi_mem_chunk_read_fn read_fn,
dfi_mem_chunk_free_fn free_fn)
{
if (size == 0)
return;
mem_chunk_create(&l.mem_virt, start, size, data, read_fn, free_fn);
}
/*
* Add memory chunk with volume index
*/
void dfi_mem_chunk_add_vol(u64 start, u64 size, void *data,
dfi_mem_chunk_read_fn read_fn,
dfi_mem_chunk_free_fn free_fn,
u32 volnr)
{
if (size == 0)
return;
mem_chunk_create(&l.mem_phys, start, size, data, read_fn, free_fn);
mem_chunk_create(&l.mem_virt, start, size, data, read_fn, NULL);
l.mem_virt.chunk_cache->volnr = volnr;
}
/*
* Add memory chunk
*/
void dfi_mem_chunk_add(u64 start, u64 size, void *data,
dfi_mem_chunk_read_fn read_fn,
dfi_mem_chunk_free_fn free_fn)
{
dfi_mem_chunk_add_vol(start, size, data, read_fn, free_fn, 0);
}
/*
* Read zero pages
*/
void dfi_mem_chunk_read_zero(struct dfi_mem_chunk *UNUSED(mem_chunk),
u64 UNUSED(off), void *buf, u64 cnt)
{
memset(buf, 0, cnt);
}
/*
* Return mem_chunk list head
*/
struct util_list *dfi_mem_chunk_list(void)
{
return &l.mem_virt.chunk_list;
}
/*
* Return number of memory chunks in input dump
*/
unsigned int dfi_mem_chunk_cnt(void)
{
return l.mem_virt.chunk_cnt;
}
/*
* Return maximum memory range
*/
u64 dfi_mem_range(void)
{
if (l.mem_virt.start_addr == U64_MAX)
return 0;
return l.mem_virt.end_addr - l.mem_virt.start_addr + 1;
}
/*
* Return first memory chunk
*/
struct dfi_mem_chunk *dfi_mem_chunk_first(void)
{
if (util_list_is_empty(&l.mem_virt.chunk_list))
return NULL;
return util_list_start(&l.mem_virt.chunk_list);
}
/*
* Return last memory chunk
*/
struct dfi_mem_chunk *dfi_mem_chunk_last(void)
{
if (util_list_is_empty(&l.mem_virt.chunk_list))
return NULL;
return util_list_end(&l.mem_virt.chunk_list);
}
/*
* Return next memory chunk
*/
struct dfi_mem_chunk *dfi_mem_chunk_next(struct dfi_mem_chunk *mem_chunk)
{
return util_list_next(&l.mem_virt.chunk_list, mem_chunk);
}
/*
* Return previous memory chunk
*/
struct dfi_mem_chunk *dfi_mem_chunk_prev(struct dfi_mem_chunk *mem_chunk)
{
return util_list_prev(&l.mem_virt.chunk_list, mem_chunk);
}
/*
* Find memory chunk for given address
*/
struct dfi_mem_chunk *dfi_mem_chunk_find(u64 addr)
{
return mem_chunk_find(&l.mem_virt, addr);
}
/*
* Initialize CPU info
*/
@@ -600,33 +248,6 @@ struct util_list *dfi_cpu_list(void)
return &l.cpus.list;
}
/*
* Read memory at given address and do kdump swap if necessary
*/
void dfi_mem_read(u64 addr, void *buf, size_t cnt)
{
mem_read(&l.mem_virt, addr, buf, cnt);
}
/*
* Read physical memory at given address
*/
void dfi_mem_phys_read(u64 addr, void *buf, size_t cnt)
{
mem_read(&l.mem_phys, addr, buf, cnt);
}
/*
* Read memory at given address with return code
*/
int dfi_mem_read_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;
}
/*
* Get input dump format name
*/
@@ -665,6 +286,7 @@ const char *dfi_arch_str(enum dfi_arch arch)
return "unknown";
}
ABORT("dfi_arch_str: Invalid dfi arch: %d", arch);
return NULL; /* UNREACHABLE */
}
/*
@@ -886,7 +508,7 @@ static void lc2cpu_64(struct dfi_cpu *cpu, struct dfi_lowcore_64 *lc)
/* Add VX registers if available */
if (!dfi_cpu_lc_has_vx_sa(lc))
return;
if (dfi_mem_read_rc(lc->vector_save_area_addr, &vx_sa, sizeof(vx_sa))) {
if (dfi_mem_virt_read(lc->vector_save_area_addr, &vx_sa, sizeof(vx_sa))) {
STDERR("zgetdump: Vector registers save area is beyond dump memory limit for CPU %d\n", cpu->cpu_id);
return;
}
@@ -917,7 +539,7 @@ static void lc2cpu_32(struct dfi_cpu_32 *cpu, struct dfi_lowcore_32 *lc)
* Note: When this function is called, the memory chunks have to be already
* defined by the DFI dump specific code.
*/
void dfi_cpu_add_from_lc(u32 lc_addr)
int dfi_cpu_add_from_lc(u32 lc_addr)
{
struct dfi_cpu *cpu = dfi_cpu_alloc();
@@ -930,12 +552,14 @@ void dfi_cpu_add_from_lc(u32 lc_addr)
if (l.arch == DFI_ARCH_32) {
struct dfi_cpu_32 cpu_32;
struct dfi_lowcore_32 lc;
dfi_mem_read(lc_addr, &lc, sizeof(lc));
if (dfi_mem_virt_read(lc_addr, &lc, sizeof(lc)))
return -EINVAL;
lc2cpu_32(&cpu_32, &lc);
cpu_32_to_64(cpu, &cpu_32);
} else {
struct dfi_lowcore_64 lc;
dfi_mem_read(lc_addr, &lc, sizeof(lc));
if (dfi_mem_virt_read(lc_addr, &lc, sizeof(lc)))
return -EINVAL;
lc2cpu_64(cpu, &lc);
}
break;
@@ -943,6 +567,7 @@ void dfi_cpu_add_from_lc(u32 lc_addr)
ABORT("dfi_cpu_add_from_lc() called for CONTENT_NONE");
}
dfi_cpu_add(cpu);
return 0;
}
/*
@@ -984,89 +609,6 @@ unsigned long dfi_kdump_base(void)
return l.kdump_base;
}
/*
* Unmap memory region
*/
static void mem_unmap(u64 start, u64 size)
{
u64 start_phys, end_phys, addr_phys, addr_virt, size_virt;
struct dfi_mem_chunk *mem_chunk, *tmp;
u64 end = start + size - 1;
util_list_iterate_safe(&l.mem_virt.chunk_list, mem_chunk, tmp) {
/*
* Chunk not hit?
*/
if (mem_chunk->start >= start + size)
continue;
if (mem_chunk->end < start)
continue;
/*
* Chunk completely unmapped
*
* UNMAP: UUUUUUUUU || UUUUUU
* CHUNK: CCCC || CCCCCC
* TO:
*/
if (mem_chunk->start >= start && mem_chunk->end <= end)
goto free;
/*
* Get real start and end addresses
*/
start_phys = mem_chunk_start_phys(mem_chunk);
end_phys = start_phys + mem_chunk->size - 1;
/*
* Chunk hit at start or in the middle?
*
* UNMAP: UUUUUU || UU || UUU
* CHUNK: CCCCC || CCCCCC || CCCC
* TO: NN || NN || NNN
*/
if (mem_chunk->end > end) {
addr_virt = end + 1;
size_virt = mem_chunk->end - end;
addr_phys = end_phys - size_virt + 1;
mem_chunk_map_add(addr_virt, size_virt, addr_phys);
}
/*
* Chunk hit at end or in the middle?
*
* UNMAP: UUUUUU || UU || UUU
* CHUNK: CCCCC || CCCCCC || CCC
* TO: NN || NN || NN
*/
if (mem_chunk->start < start) {
addr_virt = mem_chunk->start;
size_virt = start - addr_virt;
addr_phys = start_phys;
mem_chunk_map_add(addr_virt, size_virt, addr_phys);
}
free:
util_list_remove(&l.mem_virt.chunk_list, mem_chunk);
l.mem_virt.chunk_cnt--;
if (mem_chunk->data && mem_chunk->free_fn)
mem_chunk->free_fn(mem_chunk->data);
zg_free(mem_chunk);
}
mem_update(&l.mem_virt);
}
/*
* Map memory region
*/
static void mem_map(u64 start, u64 size, u64 start_phys)
{
if (mem_range_mapped(start, size)) {
mem_map_print();
ABORT("Map request for already mapped region (%llx/%llx/%llx)",
start, size, start_phys);
}
mem_chunk_map_add(start, size, start_phys);
mem_update(&l.mem_virt);
}
/*
* Check if dump contains a kdump dump and initialize kdump_base and kdump_size
*/
@@ -1074,8 +616,12 @@ static void kdump_init(void)
{
unsigned long base, size;
dfi_mem_phys_read(0x10418, &base, sizeof(base));
dfi_mem_phys_read(0x10420, &size, sizeof(size));
util_log_print(UTIL_LOG_TRACE, "DFI kdump initialization\n");
if (dfi_mem_phys_read(KDUMP_OLDMEM_BASE, &base, sizeof(base)))
return;
if (dfi_mem_phys_read(KDUMP_OLDMEM_SIZE, &size, sizeof(size)))
return;
if (base == 0 || size == 0)
return;
if (base % MIB || size % MIB)
@@ -1084,6 +630,9 @@ static void kdump_init(void)
return;
l.kdump_base = base;
l.kdump_size = size;
util_log_print(UTIL_LOG_INFO,
"DFI found valid kdump base 0x%016lx size 0x%016lx\n",
l.kdump_base, l.kdump_size);
/*
* For dumped kdump and user has selected "prod" we swap
* the crashkernel memory with old memory. If user selected "kdump",
@@ -1093,11 +642,11 @@ static void kdump_init(void)
if (!g.opts.select_specified)
return;
if (g.opts.select == OPTS_SELECT_PROD) {
mem_unmap(0, size);
mem_unmap(base, size);
mem_map(0, size, base);
dfi_mem_unmap(0, size);
dfi_mem_unmap(base, size);
dfi_mem_map(0, size, base);
} else if (g.opts.select == OPTS_SELECT_KDUMP) {
mem_unmap(l.kdump_size, U64_MAX - l.kdump_size);
dfi_mem_unmap(l.kdump_size, U64_MAX - l.kdump_size);
}
}
@@ -1126,8 +675,8 @@ static void kdump_select_prod_init(void)
}
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)))
if (dfi_mem_virt_read(ptr + i * sizeof(long), &prefix,
sizeof(prefix)))
continue;
if (prefix == 0)
continue;
@@ -1146,9 +695,11 @@ static void utsname_init(void)
unsigned long ptr;
char buf[1024];
util_log_print(UTIL_LOG_TRACE, "DFI utsname initialization\n");
if (dfi_vmcoreinfo_symbol(&ptr, "init_uts_ns"))
return;
if (dfi_mem_read_rc(ptr, buf, sizeof(buf)))
if (dfi_mem_virt_read(ptr, buf, sizeof(buf)))
return;
utsname = memchr(buf, 'L', sizeof(buf) - sizeof(*utsname));
if (!utsname)
@@ -1156,6 +707,8 @@ static void utsname_init(void)
if (strncmp(utsname->sysname, "Linux", sizeof(utsname->version)) != 0)
return;
dfi_attr_utsname_set(utsname);
util_log_print(UTIL_LOG_INFO, "DFI utsname release %s version %s\n",
utsname->release, utsname->version);
}
/*
@@ -1165,7 +718,9 @@ static void livedump_init(void)
{
u64 magic;
if (dfi_mem_read_rc(0, &magic, sizeof(magic)))
util_log_print(UTIL_LOG_TRACE, "DFI livedump initialization\n");
if (dfi_mem_virt_read(0, &magic, sizeof(magic)))
return;
if (magic == dfi_live_dump_magic)
dfi_attr_dump_method_set(DFI_DUMP_METHOD_LIVE);
@@ -1201,12 +756,16 @@ int dfi_init(void)
struct dfi *dfi;
int i = 0, rc;
util_log_print(UTIL_LOG_TRACE, "DFI initialization\n");
l.arch = DFI_ARCH_UNKNOWN;
mem_init(&l.mem_virt);
mem_init(&l.mem_phys);
rc = dfi_mem_chunk_init();
if (rc)
return rc;
attr_init();
dfi_cpu_info_init(DFI_CPU_CONTENT_NONE);
while ((dfi = dfi_vec[i])) {
util_log_print(UTIL_LOG_DEBUG, "DFI trying %s\n", dfi->name);
l.dfi = dfi;
g.fh = dfi_dump_open(g.opts.device);
rc = dfi->init();
@@ -1218,12 +777,15 @@ int dfi_init(void)
utsname_init();
livedump_init();
}
util_log_print(UTIL_LOG_DEBUG, "DFI %s returned with rc %d\n",
dfi->name, rc);
if (rc == 0 || rc == -EINVAL)
return rc;
zg_close(g.fh);
i++;
}
ERR_EXIT("No valid dump found on \"%s\"", g.opts.device);
return -1; /* UNREACHABLE */
}
/*
@@ -1231,6 +793,8 @@ int dfi_init(void)
*/
void dfi_exit(void)
{
util_log_print(UTIL_LOG_TRACE, "DFI exit\n");
if (l.dfi && l.dfi->exit)
l.dfi->exit();
}

View File

@@ -12,13 +12,12 @@
#ifndef DFI_H
#define DFI_H
#include <time.h>
#include <linux/utsname.h>
#include "lib/zt_common.h"
#include "lib/util_list.h"
#include "zg.h"
/*
* CPU info functions and definitions
*/
@@ -116,11 +115,11 @@ struct dfi_cpu_32 {
struct dfi_vxrs vxrs_high[16];
};
extern void dfi_cpu_64_to_32(struct dfi_cpu_32 *cpu_32, struct dfi_cpu *cpu_64);
void dfi_cpu_64_to_32(struct dfi_cpu_32 *cpu_32, struct dfi_cpu *cpu_64);
extern enum dfi_arch dfi_arch(void);
extern void dfi_arch_set(enum dfi_arch arch);
extern const char *dfi_arch_str(enum dfi_arch arch);
enum dfi_arch dfi_arch(void);
void dfi_arch_set(enum dfi_arch arch);
const char *dfi_arch_str(enum dfi_arch arch);
enum dfi_cpu_content {
DFI_CPU_CONTENT_NONE, /* No register information available */
@@ -129,113 +128,62 @@ enum dfi_cpu_content {
};
#define DFI_CPU_CONTENT_FAC_VX 0x00000001
extern int dfi_cpu_content_fac_check(int flags);
extern void dfi_cpu_content_fac_add(int flags);
int dfi_cpu_content_fac_check(int flags);
void dfi_cpu_content_fac_add(int flags);
#define dfi_cpu_iterate(cpu) \
util_list_iterate(dfi_cpu_list(), cpu)
extern struct util_list *dfi_cpu_list(void);
extern void dfi_cpu_info_init(enum dfi_cpu_content content);
extern struct dfi_cpu *dfi_cpu_alloc(void);
extern struct dfi_cpu *dfi_cpu(unsigned int cpu_nr);
extern void dfi_cpu_add(struct dfi_cpu *cpu);
extern unsigned int dfi_cpu_cnt(void);
extern enum dfi_cpu_content dfi_cpu_content(void);
extern void dfi_cpu_add_from_lc(u32 lc_addr);
struct util_list *dfi_cpu_list(void);
void dfi_cpu_info_init(enum dfi_cpu_content content);
struct dfi_cpu *dfi_cpu_alloc(void);
struct dfi_cpu *dfi_cpu(unsigned int cpu_nr);
void dfi_cpu_add(struct dfi_cpu *cpu);
unsigned int dfi_cpu_cnt(void);
enum dfi_cpu_content dfi_cpu_content(void);
int dfi_cpu_add_from_lc(u32 lc_addr);
#define DFI_VX_SA_SIZE (32 * 16)
extern int dfi_cpu_lc_has_vx_sa(void *lc);
extern void dfi_cpu_vx_copy(void *buf, struct dfi_cpu *cpu);
/*
* Mem chunk functions and definitions
*/
struct dfi_mem_chunk;
typedef void (*dfi_mem_chunk_read_fn)(struct dfi_mem_chunk *mem_chunk,
u64 off, void *buf, u64 cnt);
typedef void (*dfi_mem_chunk_free_fn)(void *data);
struct dfi_mem_chunk {
struct util_list_node list; /* List */
u64 start; /* Start address in memory */
u64 end; /* End address in memory */
u64 size; /* Size of chunk in dump file */
dfi_mem_chunk_read_fn read_fn; /* Chunk read callback */
dfi_mem_chunk_free_fn free_fn; /* Free data callback */
void *data; /* Data for callback */
u32 volnr; /* Volume id where chunk resides */
};
extern void dfi_mem_chunk_read_zero(struct dfi_mem_chunk *UNUSED(mem_chunk),
u64 UNUSED(off), void *buf, u64 cnt);
extern void dfi_mem_chunk_add_vol(u64 start, u64 size, void *data,
dfi_mem_chunk_read_fn read_fn,
dfi_mem_chunk_free_fn free_fn,
u32 volnr);
extern void dfi_mem_chunk_add(u64 start, u64 size, void *data,
dfi_mem_chunk_read_fn read_fn,
dfi_mem_chunk_free_fn free_fn);
extern void dfi_mem_chunk_virt_add(u64 start, u64 size, void *data,
dfi_mem_chunk_read_fn read_fn,
dfi_mem_chunk_free_fn free_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_last(void);
extern struct dfi_mem_chunk *dfi_mem_chunk_next(struct dfi_mem_chunk *chunk);
extern struct dfi_mem_chunk *dfi_mem_chunk_prev(struct dfi_mem_chunk *chunk);
extern struct dfi_mem_chunk *dfi_mem_chunk_find(u64 addr);
extern struct util_list *dfi_mem_chunk_list(void);
#define dfi_mem_chunk_iterate(mem_chunk) \
util_list_iterate(dfi_mem_chunk_list(), mem_chunk)
int dfi_cpu_lc_has_vx_sa(void *lc);
void dfi_cpu_vx_copy(void *buf, struct dfi_cpu *cpu);
/*
* Dump header attribute set/get functions
*/
extern void dfi_attr_time_set(struct timeval *time);
extern struct timeval *dfi_attr_time(void);
void dfi_attr_time_set(struct timeval *time);
struct timeval *dfi_attr_time(void);
extern void dfi_attr_time_end_set(struct timeval *time_end);
extern struct timeval *dfi_attr_time_end(void);
void dfi_attr_time_end_set(struct timeval *time_end);
struct timeval *dfi_attr_time_end(void);
extern void dfi_attr_cpu_id_set(u64 cpu_id);
extern u64 *dfi_attr_cpu_id(void);
void dfi_attr_cpu_id_set(u64 cpu_id);
u64 *dfi_attr_cpu_id(void);
extern void dfi_attr_utsname_set(struct new_utsname *utsname);
extern struct new_utsname *dfi_attr_utsname(void);
void dfi_attr_utsname_set(struct new_utsname *utsname);
struct new_utsname *dfi_attr_utsname(void);
extern void dfi_attr_dump_method_set(char *dump_method);
extern char *dfi_attr_dump_method(void);
void dfi_attr_dump_method_set(char *dump_method);
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(void);
void dfi_attr_mem_size_real_set(u64 mem_size_real);
u64 *dfi_attr_mem_size_real(void);
extern void dfi_attr_file_size_set(u64 dump_size);
extern u64 *dfi_attr_file_size(void);
void dfi_attr_file_size_set(u64 dump_size);
u64 *dfi_attr_file_size(void);
extern void dfi_attr_vol_nr_set(unsigned int vol_nr);
extern unsigned int *dfi_attr_vol_nr(void);
void dfi_attr_vol_nr_set(unsigned int vol_nr);
unsigned int *dfi_attr_vol_nr(void);
extern void dfi_attr_version_set(unsigned int dfi_version);
extern unsigned int *dfi_attr_dfi_version(void);
void dfi_attr_version_set(unsigned int dfi_version);
unsigned int *dfi_attr_dfi_version(void);
extern void dfi_attr_build_arch_set(enum dfi_arch build_arch);
extern enum dfi_arch *dfi_attr_build_arch(void);
void dfi_attr_build_arch_set(enum dfi_arch build_arch);
enum dfi_arch *dfi_attr_build_arch(void);
extern void dfi_attr_real_cpu_cnt_set(u32 real_cpu_cnt);
extern u32 *dfi_attr_real_cpu_cnt(void);
void dfi_attr_real_cpu_cnt_set(u32 real_cpu_cnt);
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_mem_phys_read(u64 addr, void *buf, size_t cnt);
extern void dfi_info_print(void);
void dfi_info_print(void);
/*
* DFI feature bits
@@ -243,25 +191,13 @@ extern void dfi_info_print(void);
#define DFI_FEAT_SEEK 0x1 /* Necessary for fuse mount */
#define DFI_FEAT_COPY 0x2 /* Necessary for stdout */
extern int dfi_feat_seek(void);
extern int dfi_feat_copy(void);
int dfi_feat_seek(void);
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);
unsigned long dfi_kdump_base(void);
/*
* DFI operations
@@ -274,14 +210,14 @@ struct dfi {
int feat_bits;
};
extern const char *dfi_name(void);
extern int dfi_init(void);
extern void dfi_exit(void);
const char *dfi_name(void);
int dfi_init(void);
void dfi_exit(void);
/*
* Dump access
*/
extern struct zg_fh *dfi_dump_open(const char *path);
struct zg_fh *dfi_dump_open(const char *path);
/*
* Live dump memory magic
@@ -293,4 +229,18 @@ extern u64 dfi_live_dump_magic;
*/
#define DFI_DUMP_METHOD_LIVE "live"
/*
* Supported DFI dump formats
*/
extern struct dfi dfi_s390tape;
extern struct dfi dfi_s390mv;
extern struct dfi dfi_s390mv_ext;
extern struct dfi dfi_s390;
extern struct dfi dfi_s390_ext;
extern struct dfi dfi_lkcd;
extern struct dfi dfi_elf;
extern struct dfi dfi_kdump;
extern struct dfi dfi_kdump_flat;
extern struct dfi dfi_devmem;
#endif /* DFI_H */

View File

@@ -21,6 +21,9 @@
#include <unistd.h>
#include "zgetdump.h"
#include "df_s390.h"
#include "dfi.h"
#include "dfi_mem_chunk.h"
/*
* Add live dump magic to buffer

View File

@@ -16,7 +16,14 @@
#include <string.h>
#include <unistd.h>
#include "lib/util_libc.h"
#include "lib/util_log.h"
#include "zgetdump.h"
#include "zg.h"
#include "df_elf.h"
#include "dfi.h"
#include "dfi_mem_chunk.h"
/*
* Read memory for given memory chunk
@@ -37,56 +44,68 @@ static int pt_load_add(Elf64_Phdr *phdr)
{
u64 *off_ptr;
util_log_print(UTIL_LOG_DEBUG,
"DFI ELF p_paddr 0x%016lx p_vaddr 0x%016lx p_offset 0x%016lx p_filesz 0x%016lx p_memsz 0x%016lx\n",
phdr->p_paddr, phdr->p_vaddr, phdr->p_offset,
phdr->p_filesz, phdr->p_memsz);
if (phdr->p_paddr != phdr->p_vaddr) {
phdr->p_paddr = phdr->p_vaddr;
STDERR("Dump file \"%s\" is a user space core dump\n",
g.opts.device);
return -EINVAL;
}
if (phdr->p_memsz == 0)
return -EINVAL;
if (phdr->p_offset + phdr->p_filesz > zg_size(g.fh))
return -EINVAL;
if (phdr->p_filesz == 0) {
/* Add zero memory chunk */
dfi_mem_chunk_add(phdr->p_paddr, phdr->p_memsz, NULL,
dfi_mem_chunk_read_zero, NULL);
} else {
if (phdr->p_filesz > phdr->p_memsz)
return -EINVAL;
if (phdr->p_filesz > 0) {
off_ptr = zg_alloc(sizeof(*off_ptr));
*off_ptr = phdr->p_offset;
dfi_mem_chunk_add(phdr->p_paddr, phdr->p_memsz, off_ptr,
dfi_mem_chunk_add(phdr->p_paddr, phdr->p_filesz, off_ptr,
dfi_elf_mem_chunk_read_fn, zg_free);
}
if (phdr->p_memsz - phdr->p_filesz > 0) {
/* Add zero memory chunk */
dfi_mem_chunk_add(phdr->p_paddr + phdr->p_filesz,
phdr->p_memsz - phdr->p_filesz, NULL,
dfi_mem_chunk_read_zero, NULL);
}
return 0;
}
/*
* Skip name of note
*/
static void nt_name_skip(Elf64_Nhdr *note)
{
zg_seek_cur(g.fh, ROUNDUP(note->n_namesz, 4), ZG_CHECK);
}
/*
* Read note
*/
static int nt_read(Elf64_Nhdr *note, void *buf)
static int nt_read(const Elf64_Nhdr *note, void *buf, size_t buf_len)
{
off_t buf_len = ROUNDUP(note->n_descsz, 4);
char tmp_buf[buf_len];
ssize_t nread;
nt_name_skip(note);
if (zg_read(g.fh, tmp_buf, buf_len, ZG_CHECK_ERR) != buf_len)
/* We cannot read more than the current note provides */
if (note->n_descsz < buf_len)
return -EINVAL;
if (buf)
memcpy(buf, tmp_buf, note->n_descsz);
/* Skip note's name and position file at note's descriptor */
zg_seek_cur(g.fh, ROUNDUP(note->n_namesz, 4), ZG_CHECK);
/* Read note's descriptor */
nread = zg_read(g.fh, buf, buf_len, ZG_CHECK_ERR);
if (nread < 0 || (size_t)nread != buf_len)
return -EINVAL;
/* Skip the rest of note's descriptor until the next note */
zg_seek_cur(g.fh, ROUNDUP(note->n_descsz, 4) - buf_len, ZG_CHECK);
return 0;
}
/*
* Skip note
*/
static int nt_skip(Elf64_Nhdr *note)
static void nt_skip(const Elf64_Nhdr *note)
{
return nt_read(note, NULL);
/* Skip note's name + descriptor and position file at the next note */
zg_seek_cur(g.fh,
ROUNDUP(note->n_namesz, 4) + ROUNDUP(note->n_descsz, 4),
ZG_CHECK);
}
/*
@@ -107,7 +126,7 @@ static struct dfi_cpu *nt_prstatus_read(Elf64_Nhdr *note)
struct dfi_cpu *cpu = dfi_cpu_alloc();
struct nt_prstatus_64 nt_prstatus;
if (nt_read(note, &nt_prstatus))
if (nt_read(note, &nt_prstatus, sizeof(nt_prstatus)))
return NULL;
memcpy(cpu->gprs, &nt_prstatus.gprs, sizeof(cpu->gprs));
@@ -126,7 +145,7 @@ static int nt_fpregset_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
struct nt_fpregset_64 nt_fpregset;
check_cpu(cpu, "FPREGSET");
if (nt_read(note, &nt_fpregset))
if (nt_read(note, &nt_fpregset, sizeof(nt_fpregset)))
return -EINVAL;
memcpy(&cpu->fpc, &nt_fpregset.fpc, sizeof(cpu->fpc));
@@ -140,7 +159,7 @@ static int nt_fpregset_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
static int nt_s390_timer_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
{
check_cpu(cpu, "S390_TIMER");
return nt_read(note, &cpu->timer);
return nt_read(note, &cpu->timer, sizeof(cpu->timer));
}
/*
@@ -149,7 +168,7 @@ static int nt_s390_timer_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
static int nt_s390_todcmp_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
{
check_cpu(cpu, "S390_TODCMP");
return nt_read(note, &cpu->todcmp);
return nt_read(note, &cpu->todcmp, sizeof(cpu->todcmp));
}
/*
@@ -158,7 +177,7 @@ static int nt_s390_todcmp_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
static int nt_s390_todpreg_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
{
check_cpu(cpu, "S390_TODPREG");
return nt_read(note, &cpu->todpreg);
return nt_read(note, &cpu->todpreg, sizeof(cpu->todpreg));
}
/*
@@ -167,7 +186,7 @@ static int nt_s390_todpreg_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
static int nt_s390_ctrs_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
{
check_cpu(cpu, "S390_CTRS");
return nt_read(note, &cpu->ctrs);
return nt_read(note, &cpu->ctrs, sizeof(cpu->ctrs));
}
/*
@@ -176,7 +195,7 @@ static int nt_s390_ctrs_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
static int nt_s390_prefix_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
{
check_cpu(cpu, "S390_PREFIX");
return nt_read(note, &cpu->prefix);
return nt_read(note, &cpu->prefix, sizeof(cpu->prefix));
}
/*
@@ -185,7 +204,7 @@ static int nt_s390_prefix_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
static int nt_s390_vxrs_low_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
{
check_cpu(cpu, "S390_VXRS_LOW");
return nt_read(note, &cpu->vxrs_low);
return nt_read(note, &cpu->vxrs_low, sizeof(cpu->vxrs_low));
}
/*
@@ -194,7 +213,7 @@ static int nt_s390_vxrs_low_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
static int nt_s390_vxrs_high_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
{
check_cpu(cpu, "S390_VXRS_HIGH");
return nt_read(note, &cpu->vxrs_high);
return nt_read(note, &cpu->vxrs_high, sizeof(cpu->vxrs_high));
}
/*
@@ -202,7 +221,6 @@ static int nt_s390_vxrs_high_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
*/
static int pt_notes_add(Elf64_Phdr *phdr)
{
u64 start_off = zg_tell(g.fh, ZG_CHECK);
struct dfi_cpu *cpu_current = NULL;
u64 notes_start_off;
Elf64_Nhdr note;
@@ -214,6 +232,8 @@ static int pt_notes_add(Elf64_Phdr *phdr)
rc = zg_read(g.fh, &note, sizeof(note), ZG_CHECK_ERR);
if (rc != sizeof(note))
return -EINVAL;
util_log_print(UTIL_LOG_DEBUG, "DFI ELF n_type 0x%x\n",
note.n_type);
switch (note.n_type) {
case NT_PRSTATUS:
cpu_current = nt_prstatus_read(&note);
@@ -255,12 +275,10 @@ static int pt_notes_add(Elf64_Phdr *phdr)
dfi_cpu_content_fac_add(DFI_CPU_CONTENT_FAC_VX);
break;
default:
if (nt_skip(&note))
return -EINVAL;
nt_skip(&note);
break;
}
}
zg_seek(g.fh, start_off, ZG_CHECK);
return 0;
}
@@ -287,9 +305,11 @@ static int read_elf_hdr(Elf64_Ehdr *ehdr)
static int dfi_elf_init(void)
{
Elf64_Ehdr ehdr;
Elf64_Phdr phdr;
Elf64_Phdr *phdr;
int i;
util_log_print(UTIL_LOG_DEBUG, "DFI ELF initialization\n");
if (read_elf_hdr(&ehdr) != 0)
return -ENODEV;
@@ -297,21 +317,32 @@ static int dfi_elf_init(void)
dfi_arch_set(DFI_ARCH_64);
dfi_cpu_info_init(DFI_CPU_CONTENT_ALL);
phdr = util_malloc(sizeof(*phdr) * ehdr.e_phnum);
zg_seek(g.fh, ehdr.e_phoff, ZG_CHECK);
zg_read(g.fh, phdr, sizeof(*phdr) * ehdr.e_phnum, ZG_CHECK);
util_log_print(UTIL_LOG_DEBUG, "DFI ELF e_phnum %u\n", ehdr.e_phnum);
for (i = 0; i < ehdr.e_phnum; i++) {
zg_read(g.fh, &phdr, sizeof(phdr), ZG_CHECK);
switch (phdr.p_type) {
util_log_print(UTIL_LOG_DEBUG, "DFI ELF p_type[%d] 0x%lx\n",
i, phdr[i].p_type);
switch (phdr[i].p_type) {
case PT_LOAD:
if (pt_load_add(&phdr))
if (pt_load_add(&phdr[i])) {
free(phdr);
return -EINVAL;
}
break;
case PT_NOTE:
if (pt_notes_add(&phdr))
if (pt_notes_add(&phdr[i])) {
free(phdr);
return -EINVAL;
}
break;
default:
break;
}
}
free(phdr);
dfi_attr_version_set(ehdr.e_ident[EI_VERSION]);
return 0;
}

View File

@@ -9,7 +9,12 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <errno.h>
#include "zgetdump.h"
#include "zg.h"
#include "dfi.h"
#include "dfi_mem_chunk.h"
struct df_kdump_hdr {
char signature[8];

View File

@@ -9,8 +9,15 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <string.h>
#include <errno.h>
#include <zlib.h>
#include "zgetdump.h"
#include "zg.h"
#include "df_lkcd.h"
#include "dfi.h"
#include "dfi_mem_chunk.h"
#define MEM_HOLE_SIZE_MIN (1024 * 1024)
#define IDX_KIB 64 /* One index entry per IDX_KIB */
@@ -267,19 +274,25 @@ static int mem_init(void)
/*
* Initialize CPU information
*/
static void cpu_init(void)
static int cpu_init(void)
{
unsigned int i;
int rc;
if (l.hdr_asm.magic != DF_LKCD_MAGIC_ASM) {
/* Old LKCD dump without asm header */
dfi_cpu_info_init(DFI_CPU_CONTENT_NONE);
return;
return 0;
}
dfi_cpu_info_init(DFI_CPU_CONTENT_ALL);
for (i = 0; i < l.hdr_asm.cpu_cnt; i++)
dfi_cpu_add_from_lc(l.hdr_asm.lc_vec[i]);
for (i = 0; i < l.hdr_asm.cpu_cnt; i++) {
rc = dfi_cpu_add_from_lc(l.hdr_asm.lc_vec[i]);
if (rc)
return rc;
}
return 0;
}
/*
@@ -321,7 +334,8 @@ static int dfi_lkcd_init(void)
return -ENODEV;
if (mem_init() != 0)
return -EINVAL;
cpu_init();
if (cpu_init() != 0)
return -EINVAL;
return 0;
}

527
zdump/dfi_mem_chunk.c Normal file
View File

@@ -0,0 +1,527 @@
/*
* Copyright IBM Corp. 2001, 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "lib/util_libc.h"
#include "lib/util_log.h"
#include "zg.h"
#include "dfi_mem_chunk.h"
/*
* Memory information
*/
struct mem {
struct dfi_mem_chunk *chunk_cache;
u64 start_addr;
u64 end_addr;
unsigned int chunk_cnt;
struct util_list chunk_list;
};
/*
* File local static data
*/
static struct {
struct mem mem_phys;
struct mem mem_virt;
} l;
/*
* Initialize DFI memory chunks
*/
static void mem_init(struct mem *mem)
{
mem->start_addr = U64_MAX;
mem->end_addr = 0;
util_list_init(&mem->chunk_list, struct dfi_mem_chunk, list);
}
/*
* Memory chunk compare function for list sorting
*/
static int mem_chunk_cmp_fn(void *a, void *b, void *UNUSED(data))
{
struct dfi_mem_chunk *mem_chunk1 = a;
struct dfi_mem_chunk *mem_chunk2 = b;
return mem_chunk1->start < mem_chunk2->start ? -1 : 1;
}
/*
* Update DFI memory chunks
*/
static void mem_update(struct mem *mem)
{
struct dfi_mem_chunk *mem_chunk;
util_list_sort(&mem->chunk_list, mem_chunk_cmp_fn, NULL);
mem->start_addr = U64_MAX;
mem->end_addr = 0;
util_list_iterate(&mem->chunk_list, mem_chunk) {
mem->start_addr = MIN(mem->start_addr, mem_chunk->start);
mem->end_addr = MAX(mem->end_addr, mem_chunk->end);
}
}
/*
* Print memory map
*/
void dfi_mem_map_print(bool verbose)
{
struct dfi_mem_chunk *mem_chunk;
u64 print_start = 0, print_end = 0;
const char *zero_str;
u32 volnr = 0;
STDERR("\nMemory map:\n");
/*
* Print each memory chunk if verbose specified
*/
if (verbose) {
dfi_mem_chunk_iterate(mem_chunk) {
zero_str = "";
if (mem_chunk->read_fn == dfi_mem_chunk_read_zero)
zero_str = " zeroes";
STDERR(" %016llx - %016llx (%llu MB%s)\n",
mem_chunk->start, mem_chunk->end,
TO_MIB(mem_chunk->size), zero_str);
}
return;
}
/*
* Merge adjacent memory chunks from the same volume
*/
dfi_mem_chunk_iterate(mem_chunk) {
if (print_end == 0) {
print_start = mem_chunk->start;
print_end = mem_chunk->end;
volnr = mem_chunk->volnr;
continue;
}
if (mem_chunk->start != print_end + 1 ||
mem_chunk->volnr != volnr) {
STDERR(" %016llx - %016llx (%llu MB)\n", print_start,
print_end, TO_MIB(print_end - print_start + 1));
print_start = mem_chunk->start;
volnr = mem_chunk->volnr;
}
print_end = mem_chunk->end;
}
STDERR(" %016llx - %016llx (%llu MB)\n", print_start,
print_end, TO_MIB(print_end - print_start + 1));
}
/*
* Check if memory chunk contains address
*/
static int mem_chunk_has_addr(struct dfi_mem_chunk *mem_chunk, u64 addr)
{
return (addr >= mem_chunk->start && addr <= mem_chunk->end);
}
/*
* Find memory chunk that contains address
*/
static struct dfi_mem_chunk *mem_chunk_find(struct mem *mem, u64 addr)
{
struct dfi_mem_chunk *mem_chunk;
if (mem->chunk_cache && mem_chunk_has_addr(mem->chunk_cache, addr))
return mem->chunk_cache;
util_list_iterate(&mem->chunk_list, mem_chunk) {
if (mem_chunk_has_addr(mem_chunk, addr)) {
mem->chunk_cache = mem_chunk;
return mem_chunk;
}
}
return NULL;
}
/*
* Is memory range valid?
*/
static int mem_range_valid(struct mem *mem, u64 addr, u64 len)
{
struct dfi_mem_chunk *mem_chunk;
u64 addr_end = addr + len;
/* check for unsigned wrap */
if (addr_end < addr)
return 0;
do {
mem_chunk = mem_chunk_find(mem, addr);
if (!mem_chunk)
return 0;
addr += MIN(len, mem_chunk->end - addr + 1);
} while (addr < addr_end);
return 1;
}
/*
* Is memory already mapped at range?
*/
static int mem_range_mapped(u64 start, u64 size)
{
struct dfi_mem_chunk *mem_chunk;
u64 end = start + size - 1;
dfi_mem_chunk_iterate(mem_chunk) {
if (mem_chunk->start > end)
continue;
if (mem_chunk->end < start)
continue;
return 1;
}
return 0;
}
/*
* Add memory chunk to memory
*/
static void mem_chunk_create(struct mem *mem, u64 start, u64 size, void *data,
dfi_mem_chunk_read_fn read_fn,
dfi_mem_chunk_free_fn free_fn)
{
struct dfi_mem_chunk *mem_chunk;
mem_chunk = util_malloc(sizeof(*mem_chunk));
mem_chunk->start = start;
mem_chunk->end = start + size - 1;
mem_chunk->size = size;
mem_chunk->read_fn = read_fn;
mem_chunk->free_fn = free_fn;
mem_chunk->data = data;
util_list_add_tail(&mem->chunk_list, mem_chunk);
mem->start_addr = MIN(mem->start_addr, mem_chunk->start);
mem->end_addr = MAX(mem->end_addr, mem_chunk->end);
mem->chunk_cache = mem_chunk;
mem->chunk_cnt++;
}
/*
* Read memory at given address
*/
static void mem_read(struct mem *mem, u64 addr, void *buf, size_t cnt)
{
struct dfi_mem_chunk *mem_chunk;
u64 size, off, copied = 0;
while (copied != cnt) {
mem_chunk = mem_chunk_find(mem, addr);
size = MIN(cnt - copied, mem_chunk->end - addr + 1);
off = addr - mem_chunk->start;
mem_chunk->read_fn(mem_chunk, off, buf + copied, size);
copied += size;
addr += size;
}
}
/*
* Read memory for virtual map memory chunk
*/
static void mem_chunk_map_read_fn(struct dfi_mem_chunk *mem_chunk, u64 off,
void *buf, u64 cnt)
{
u64 *start = mem_chunk->data;
dfi_mem_phys_read(*start + off, buf, cnt);
}
/*
* Check if memory chunk is a virtual mapping
*/
static int mem_chunk_is_map(struct dfi_mem_chunk *mem_chunk)
{
return mem_chunk->read_fn == mem_chunk_map_read_fn;
}
/*
* Return physical start address for memory chunk
*/
static u64 mem_chunk_start_phys(struct dfi_mem_chunk *mem_chunk)
{
if (mem_chunk_is_map(mem_chunk))
return *((u64 *) mem_chunk->data);
else
return mem_chunk->start;
}
/*
* Add virtual memory chunk
*/
static void mem_chunk_virt_add(u64 start, u64 size, void *data,
dfi_mem_chunk_read_fn read_fn,
dfi_mem_chunk_free_fn free_fn)
{
util_log_print(UTIL_LOG_DEBUG,
"DFI add %svirt mem chunk start 0x%016lx size 0x%016lx\n",
read_fn == dfi_mem_chunk_read_zero ? "zero " : "",
start, size);
if (size == 0)
return;
mem_chunk_create(&l.mem_virt, start, size, data, read_fn, free_fn);
}
/*
* Add virtual memory chunk with simple virtual mapping
*/
static void mem_chunk_map_add(u64 start, u64 size, u64 start_p)
{
u64 *data = util_malloc(sizeof(*data));
*data = start_p;
mem_chunk_virt_add(start, size, data, mem_chunk_map_read_fn, free);
}
/*
* Add memory chunk with volume index
*/
void dfi_mem_chunk_add_vol(u64 start, u64 size, void *data,
dfi_mem_chunk_read_fn read_fn,
dfi_mem_chunk_free_fn free_fn,
u32 volnr)
{
util_log_print(UTIL_LOG_DEBUG,
"DFI add %svol mem chunk start 0x%016lx size 0x%016lx volnr %u\n",
read_fn == dfi_mem_chunk_read_zero ? "zero " : "",
start, size, volnr);
if (size == 0)
return;
mem_chunk_create(&l.mem_phys, start, size, data, read_fn, free_fn);
mem_chunk_create(&l.mem_virt, start, size, data, read_fn, NULL);
l.mem_virt.chunk_cache->volnr = volnr;
}
/*
* Add memory chunk
*/
void dfi_mem_chunk_add(u64 start, u64 size, void *data,
dfi_mem_chunk_read_fn read_fn,
dfi_mem_chunk_free_fn free_fn)
{
dfi_mem_chunk_add_vol(start, size, data, read_fn, free_fn, 0);
}
/*
* Read zero pages
*/
void dfi_mem_chunk_read_zero(struct dfi_mem_chunk *UNUSED(mem_chunk),
u64 UNUSED(off), void *buf, u64 cnt)
{
memset(buf, 0, cnt);
}
/*
* Return mem_chunk list head
*/
struct util_list *dfi_mem_chunk_list(void)
{
return &l.mem_virt.chunk_list;
}
/*
* Return number of memory chunks in input dump
*/
unsigned int dfi_mem_chunk_cnt(void)
{
return l.mem_virt.chunk_cnt;
}
/*
* Return maximum memory range
*/
u64 dfi_mem_range(void)
{
if (l.mem_virt.start_addr == U64_MAX)
return 0;
return l.mem_virt.end_addr - l.mem_virt.start_addr + 1;
}
/*
* Is memory range valid?
*/
int dfi_mem_range_valid(u64 addr, u64 len)
{
return mem_range_valid(&l.mem_virt, addr, len);
}
/*
* Return first memory chunk
*/
struct dfi_mem_chunk *dfi_mem_chunk_first(void)
{
if (util_list_is_empty(&l.mem_virt.chunk_list))
return NULL;
return util_list_start(&l.mem_virt.chunk_list);
}
/*
* Return last memory chunk
*/
struct dfi_mem_chunk *dfi_mem_chunk_last(void)
{
if (util_list_is_empty(&l.mem_virt.chunk_list))
return NULL;
return util_list_end(&l.mem_virt.chunk_list);
}
/*
* Return next memory chunk
*/
struct dfi_mem_chunk *dfi_mem_chunk_next(struct dfi_mem_chunk *mem_chunk)
{
return util_list_next(&l.mem_virt.chunk_list, mem_chunk);
}
/*
* Return previous memory chunk
*/
struct dfi_mem_chunk *dfi_mem_chunk_prev(struct dfi_mem_chunk *mem_chunk)
{
return util_list_prev(&l.mem_virt.chunk_list, mem_chunk);
}
/*
* Find memory chunk for given address
*/
struct dfi_mem_chunk *dfi_mem_chunk_find(u64 addr)
{
return mem_chunk_find(&l.mem_virt, addr);
}
/*
* Read physical memory at given address
*/
int dfi_mem_phys_read(u64 addr, void *buf, size_t cnt)
{
util_log_print(UTIL_LOG_TRACE,
"DFI phys mem read addr 0x%016lx size 0x%016lx\n",
addr, cnt);
if (!mem_range_valid(&l.mem_phys, addr, cnt))
return -EINVAL;
mem_read(&l.mem_phys, addr, buf, cnt);
return 0;
}
/*
* Read virtual memory at given address
*/
int dfi_mem_virt_read(u64 addr, void *buf, size_t cnt)
{
util_log_print(UTIL_LOG_TRACE,
"DFI virt mem read addr 0x%016lx size 0x%016lx\n",
addr, cnt);
if (!mem_range_valid(&l.mem_virt, addr, cnt))
return -EINVAL;
mem_read(&l.mem_virt, addr, buf, cnt);
return 0;
}
/*
* Unmap memory region
*/
void dfi_mem_unmap(u64 start, u64 size)
{
u64 start_phys, end_phys, addr_phys, addr_virt, size_virt;
struct dfi_mem_chunk *mem_chunk, *tmp;
u64 end = start + size - 1;
util_list_iterate_safe(&l.mem_virt.chunk_list, mem_chunk, tmp) {
/*
* Chunk not hit?
*/
if (mem_chunk->start >= start + size)
continue;
if (mem_chunk->end < start)
continue;
/*
* Chunk completely unmapped
*
* UNMAP: UUUUUUUUU || UUUUUU
* CHUNK: CCCC || CCCCCC
* TO:
*/
if (mem_chunk->start >= start && mem_chunk->end <= end)
goto free;
/*
* Get real start and end addresses
*/
start_phys = mem_chunk_start_phys(mem_chunk);
end_phys = start_phys + mem_chunk->size - 1;
/*
* Chunk hit at start or in the middle?
*
* UNMAP: UUUUUU || UU || UUU
* CHUNK: CCCCC || CCCCCC || CCCC
* TO: NN || NN || NNN
*/
if (mem_chunk->end > end) {
addr_virt = end + 1;
size_virt = mem_chunk->end - end;
addr_phys = end_phys - size_virt + 1;
mem_chunk_map_add(addr_virt, size_virt, addr_phys);
}
/*
* Chunk hit at end or in the middle?
*
* UNMAP: UUUUUU || UU || UUU
* CHUNK: CCCCC || CCCCCC || CCC
* TO: NN || NN || NN
*/
if (mem_chunk->start < start) {
addr_virt = mem_chunk->start;
size_virt = start - addr_virt;
addr_phys = start_phys;
mem_chunk_map_add(addr_virt, size_virt, addr_phys);
}
free:
util_list_remove(&l.mem_virt.chunk_list, mem_chunk);
l.mem_virt.chunk_cnt--;
if (mem_chunk->data && mem_chunk->free_fn)
mem_chunk->free_fn(mem_chunk->data);
free(mem_chunk);
}
mem_update(&l.mem_virt);
}
/*
* Map memory region
*/
void dfi_mem_map(u64 start, u64 size, u64 start_phys)
{
if (mem_range_mapped(start, size)) {
dfi_mem_map_print(false);
ABORT("Map request for already mapped region (%llx/%llx/%llx)",
start, size, start_phys);
}
mem_chunk_map_add(start, size, start_phys);
mem_update(&l.mem_virt);
}
int dfi_mem_chunk_init(void)
{
mem_init(&l.mem_virt);
mem_init(&l.mem_phys);
return 0;
}
void dfi_mem_chunk_deinit(void)
{
memset(&l, 0, sizeof(l));
}

69
zdump/dfi_mem_chunk.h Normal file
View File

@@ -0,0 +1,69 @@
/*
* Copyright IBM Corp. 2001, 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef DFI_MEM_CHUNK_H
#define DFI_MEM_CHUNK_H
#include <stdbool.h>
#include "lib/zt_common.h"
#include "lib/util_list.h"
/*
* Mem chunk functions and definitions
*/
struct dfi_mem_chunk;
typedef void (*dfi_mem_chunk_read_fn)(struct dfi_mem_chunk *mem_chunk,
u64 off, void *buf, u64 cnt);
typedef void (*dfi_mem_chunk_free_fn)(void *data);
struct dfi_mem_chunk {
struct util_list_node list; /* List */
u64 start; /* Start address in memory */
u64 end; /* End address in memory */
u64 size; /* Size of chunk in dump file */
dfi_mem_chunk_read_fn read_fn; /* Chunk read callback */
dfi_mem_chunk_free_fn free_fn; /* Free data callback */
void *data; /* Data for callback */
u32 volnr; /* Volume id where chunk resides */
};
void dfi_mem_chunk_read_zero(struct dfi_mem_chunk *UNUSED(mem_chunk),
u64 UNUSED(off), void *buf, u64 cnt);
void dfi_mem_chunk_add_vol(u64 start, u64 size, void *data,
dfi_mem_chunk_read_fn read_fn,
dfi_mem_chunk_free_fn free_fn,
u32 volnr);
void dfi_mem_chunk_add(u64 start, u64 size, void *data,
dfi_mem_chunk_read_fn read_fn,
dfi_mem_chunk_free_fn free_fn);
u64 dfi_mem_range(void);
int dfi_mem_range_valid(u64 addr, u64 len);
unsigned int dfi_mem_chunk_cnt(void);
struct dfi_mem_chunk *dfi_mem_chunk_first(void);
struct dfi_mem_chunk *dfi_mem_chunk_last(void);
struct dfi_mem_chunk *dfi_mem_chunk_next(struct dfi_mem_chunk *chunk);
struct dfi_mem_chunk *dfi_mem_chunk_prev(struct dfi_mem_chunk *chunk);
struct dfi_mem_chunk *dfi_mem_chunk_find(u64 addr);
struct util_list *dfi_mem_chunk_list(void);
#define dfi_mem_chunk_iterate(mem_chunk) \
util_list_iterate(dfi_mem_chunk_list(), mem_chunk)
int dfi_mem_virt_read(u64 addr, void *buf, size_t cnt);
int dfi_mem_phys_read(u64 addr, void *buf, size_t cnt);
void dfi_mem_map_print(bool verbose);
void dfi_mem_unmap(u64 start, u64 size);
void dfi_mem_map(u64 start, u64 size, u64 start_phys);
int dfi_mem_chunk_init(void);
void dfi_mem_chunk_deinit(void);
#endif /* DFI_MEM_CHUNK_H */

View File

@@ -17,8 +17,16 @@
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include "lib/util_log.h"
#include "zgetdump.h"
#include "zg.h"
#include "dfi.h"
#include "dfi_mem_chunk.h"
#include "df_elf.h"
#include "df_s390.h"
/*
* File local static data
@@ -68,6 +76,9 @@ static int read_s390_hdr(void)
return -ENODEV;
if (l.hdr.magic != magic_number)
return -ENODEV;
if (l.hdr.cpu_cnt > DF_S390_CPU_MAX)
return -ENODEV;
util_log_print(UTIL_LOG_INFO, "DFI S390 version %u\n", l.hdr.version);
df_s390_hdr_add(&l.hdr);
return 0;
}
@@ -95,6 +106,9 @@ static int mem_chunks_add(void)
{
u64 rc;
util_log_print(UTIL_LOG_DEBUG, "DFI S390 mem_size 0x%016lx\n",
l.hdr.mem_size);
/* Single memory chunk for non-extended dump format */
dfi_mem_chunk_add(0, l.hdr.mem_size, NULL,
dfi_s390_mem_chunk_read,
@@ -112,39 +126,43 @@ static int mem_chunks_add(void)
*/
static int mem_chunks_add_ext(void)
{
struct df_s390_dump_segm_hdr dump_segm;
u64 rc, *off_ptr, old = 0, dump_size = 0;
struct df_s390_dump_segm_hdr dump_segm = { 0 };
u64 rc, off, old = 0, dump_size = 0;
off_ptr = zg_alloc(sizeof(*off_ptr));
*off_ptr = zg_seek(g.fh, DF_S390_HDR_SIZE, ZG_CHECK_NONE);
if (*off_ptr != DF_S390_HDR_SIZE)
off = zg_seek(g.fh, DF_S390_HDR_SIZE, ZG_CHECK_NONE);
if (off != DF_S390_HDR_SIZE)
return -EINVAL;
while (*off_ptr < DF_S390_HDR_SIZE + l.hdr.mem_size - PAGE_SIZE) {
while (off < DF_S390_HDR_SIZE + l.hdr.mem_size - PAGE_SIZE) {
rc = zg_read(g.fh, &dump_segm, PAGE_SIZE, ZG_CHECK_ERR);
if (rc != PAGE_SIZE)
return -EINVAL;
*off_ptr += PAGE_SIZE;
util_log_print(UTIL_LOG_DEBUG,
"DFI S390 dump segment start 0x%016lx size 0x%016lx stop marker %d\n",
dump_segm.start, dump_segm.len, dump_segm.stop_marker);
off += PAGE_SIZE;
/* Add zero memory chunk */
dfi_mem_chunk_add(old, dump_segm.start - old, NULL,
dfi_mem_chunk_read_zero, NULL);
/* Add memory chunk for a dump segment */
u64 *off_ptr = zg_alloc(sizeof(*off_ptr));
*off_ptr = off;
dfi_mem_chunk_add(dump_segm.start, dump_segm.len, off_ptr,
dfi_s390_ext_mem_chunk_read, zg_free);
off_ptr = NULL;
old = dump_segm.start + dump_segm.len;
dump_size += dump_segm.len;
off_ptr = zg_alloc(sizeof(*off_ptr));
*off_ptr = zg_seek_cur(g.fh, dump_segm.len, ZG_CHECK_NONE);
off = zg_seek_cur(g.fh, dump_segm.len, ZG_CHECK_NONE);
if (dump_segm.stop_marker)
break;
}
/* Check if the last dump segment found */
if (!dump_segm.stop_marker)
return -EINVAL;
/* Add zero memory chunk at the end */
dfi_mem_chunk_add(old, l.hdr.mem_size - old, NULL,
dfi_mem_chunk_read_zero, NULL);
/* Set the actual size of the dump file */
dfi_attr_file_size_set(dump_size);
/* Check if the last dump segment found */
if (!dump_segm.stop_marker)
return -EINVAL;
/* Read and verify the end marker */
return read_s390_em();
}
@@ -156,6 +174,9 @@ int dfi_s390_init_gen(bool extended)
{
int rc;
util_log_print(UTIL_LOG_DEBUG, "DFI S390 %sinitialization\n",
extended ? "extended " : "");
l.extended = extended;
if (read_s390_hdr() != 0)
return -ENODEV;
@@ -165,7 +186,9 @@ int dfi_s390_init_gen(bool extended)
rc = mem_chunks_add_ext();
if (rc)
return rc;
df_s390_cpu_info_add(&l.hdr, l.hdr.mem_size);
rc = df_s390_cpu_info_add(&l.hdr, l.hdr.mem_size);
if (rc)
return rc;
zg_seek(g.fh, sizeof(l.hdr), ZG_CHECK);
return 0;
}

View File

@@ -9,7 +9,9 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include "zgetdump.h"
#include "dt.h"
#include "df_s390.h"
#include "dfi.h"
/*
* Initialize s390 input dump format (extended)

View File

@@ -20,12 +20,17 @@
#include <sys/sysmacros.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include "lib/util_file.h"
#include "lib/util_path.h"
#include "zgetdump.h"
#include "dt.h"
#include "df_s390.h"
#include "dfi.h"
#include "dfi_s390mv.h"
#include "dfi_mem_chunk.h"
/*
* Volume information
@@ -574,6 +579,8 @@ static void set_magic_numbers(void)
*/
int dfi_s390mv_init_gen(bool extended)
{
int rc;
l.extended = extended;
set_magic_numbers();
if (open_dump() != 0)
@@ -590,7 +597,9 @@ int dfi_s390mv_init_gen(bool extended)
return -EINVAL;
if (l.dump_incomplete)
return -EINVAL;
df_s390_cpu_info_add(&l.hdr, l.hdr.mem_end);
rc = df_s390_cpu_info_add(&l.hdr, l.hdr.mem_end);
if (rc)
return rc;
df_s390_em_add(&l.em);
return 0;
}

View File

@@ -10,6 +10,9 @@
*/
#include "zgetdump.h"
#include "dt.h"
#include "df_s390.h"
#include "dfi.h"
/*
* Initialize s390 multi-volume input dump format (extedend)

View File

@@ -17,8 +17,12 @@
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include "zgetdump.h"
#include "df_s390.h"
#include "dfi.h"
#include "dfi_mem_chunk.h"
#define TAPE_BLK_SIZE 32768 /* Defined by zipl tape dumper */
@@ -166,7 +170,9 @@ static int vol_init(void)
/* Init memory read & CPU info */
mem_read_init();
df_s390_cpu_info_add(&hdr, hdr.mem_size - 1);
rc = df_s390_cpu_info_add(&hdr, hdr.mem_size - 1);
if (rc)
return rc;
return 0;
}

View File

@@ -9,11 +9,16 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <stdio.h>
#include <string.h>
#include <elf.h>
#include "lib/zt_common.h"
#include "lib/util_log.h"
#include "zgetdump.h"
#include "zg.h"
#include "dfi_mem_chunk.h"
#include "dfi_vmcoreinfo.h"
#ifdef __s390x__
#define LC_VMCORE_INFO 0xe0c
@@ -22,7 +27,7 @@
#endif
#define LC_OS_INFO 0xe18
#define OS_INFO_MAGIC 0x4f53494e464f535aULL /* OSINFOSZ */
#define OS_INFO_MAGIC 0x4f53494e464f535aULL /* OSINFOSZ */
struct os_info {
u64 magic;
@@ -62,10 +67,13 @@ 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));
util_log_print(UTIL_LOG_TRACE, "DFI get osinfo\n");
if (dfi_mem_virt_read(LC_OS_INFO, &addr, sizeof(addr)))
return NULL;
if (addr % 0x1000)
return NULL;
if (dfi_mem_read_rc(addr, &os_info, sizeof(os_info)))
if (dfi_mem_virt_read(addr, &os_info, sizeof(os_info)))
return NULL;
if (os_info.magic != OS_INFO_MAGIC)
return NULL;
@@ -83,32 +91,42 @@ void dfi_vmcoreinfo_init(void)
Elf64_Nhdr note;
char str[128];
util_log_print(UTIL_LOG_TRACE, "DFI vmcoreinfo initialization\n");
l.os_info = os_info_get();
if (l.os_info && l.os_info->vmcoreinfo_size) {
util_log_print(UTIL_LOG_DEBUG, "DFI found valid osinfo\n");
addr = l.os_info->vmcoreinfo_addr;
size = l.os_info->vmcoreinfo_size;
} else {
dfi_mem_read(LC_VMCORE_INFO, &addr, sizeof(addr));
if (dfi_mem_virt_read(LC_VMCORE_INFO, &addr, sizeof(addr)))
return;
if (addr == 0)
return;
if (dfi_mem_read_rc(addr, &note, sizeof(note)))
if (dfi_mem_virt_read(addr, &note, sizeof(note)))
return;
if (note.n_namesz == 0 || note.n_namesz > sizeof(str))
return;
memset(str, 0, sizeof(str));
if (dfi_mem_read_rc(addr + sizeof(note), str, note.n_namesz))
if (dfi_mem_virt_read(addr + sizeof(note), str, note.n_namesz))
return;
if (memcmp(str, "VMCOREINFO", sizeof("VMCOREINFO")) != 0)
return;
size = note.n_descsz;
addr += 24;
}
util_log_print(UTIL_LOG_DEBUG,
"DFI vmcoreinfo addr 0x%016lx size 0x%016lx\n",
addr, size);
l.vmcoreinfo = zg_alloc(size + 1);
if (dfi_mem_read_rc(addr, l.vmcoreinfo, size)) {
if (dfi_mem_virt_read(addr, l.vmcoreinfo, size)) {
zg_free(l.vmcoreinfo);
l.vmcoreinfo = NULL;
return;
}
l.vmcoreinfo[size] = 0;
util_log_print(UTIL_LOG_INFO, "DFI found valid vmcoreinfo\n");
}
/*

20
zdump/dfi_vmcoreinfo.h Normal file
View File

@@ -0,0 +1,20 @@
/*
* Copyright IBM Corp. 2001, 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef DFI_VMCOREINFO_H
#define DFI_VMCOREINFO_H
void dfi_vmcoreinfo_init(void);
char *dfi_vmcoreinfo_get(void);
int dfi_vmcoreinfo_tag(char *str, int len, const char *sym);
int dfi_vmcoreinfo_symbol(unsigned long *val, const char *sym);
int dfi_vmcoreinfo_offset(unsigned long *offs, const char *sym);
int dfi_vmcoreinfo_size(unsigned long *size, const char *sym);
int dfi_vmcoreinfo_length(unsigned long *len, const char *sym);
int dfi_vmcoreinfo_val(unsigned long *val, const char *sym);
#endif /* DFI_VMCOREINFO_H */

View File

@@ -9,11 +9,12 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <time.h>
#include "zgetdump.h"
#include <string.h>
#include <errno.h>
#define dfo_chunk_iterate(dfo_chunk) \
util_list_iterate(&l.dump.chunk_list, dfo_chunk)
#include "zg.h"
#include "dfo_mem_chunk.h"
#include "dfo.h"
/*
* DFO vector
@@ -24,70 +25,14 @@ static struct dfo *dfo_vec[] = {
NULL,
};
/*
* Dump (output) information
*/
struct dump {
u64 off; /* Current file offset in dump */
u64 size; /* Size of dump in bytes */
unsigned int chunk_cnt; /* Number of dump chunks */
struct util_list chunk_list; /* DFO chunk list */
};
/*
* File local static data
*/
static struct {
struct dump dump;
u64 off; /* Current file offset in dump */
struct dfo *dfo;
} l;
/*
* Add dump chunk
*/
void dfo_chunk_add(u64 start, u64 size, void *data, dfo_chunk_read_fn read_fn)
{
struct dfo_chunk *dfo_chunk;
dfo_chunk = zg_alloc(sizeof(*dfo_chunk));
dfo_chunk->start = start;
dfo_chunk->end = start + size - 1;
dfo_chunk->data = data;
dfo_chunk->read_fn = read_fn;
util_list_add_head(&l.dump.chunk_list, dfo_chunk);
l.dump.chunk_cnt++;
l.dump.size = MAX(l.dump.size, dfo_chunk->end + 1);
}
/*
* Dump chunk function: Copy zero pages for chunk
*/
void dfo_chunk_zero_fn(struct dfo_chunk *dfo_chunk, u64 off, void *buf, u64 cnt)
{
(void) dfo_chunk;
(void) off;
memset(buf, 0, cnt);
}
/*
* Dump chunk function: Copy given buffer for chunk
*/
void dfo_chunk_buf_fn(struct dfo_chunk *dfo_chunk, u64 off, void *buf, u64 cnt)
{
memcpy(buf, dfo_chunk->data + off, cnt);
}
/*
* Dump chunk function: Copy given memory range for chunk
*/
void dfo_chunk_mem_fn(struct dfo_chunk *dfo_chunk, u64 off, void *buf, u64 cnt)
{
struct dfi_mem_chunk *mem_chunk = dfo_chunk->data;
mem_chunk->read_fn(mem_chunk, off, buf, cnt);
}
/*
* Get DFO name
*/
@@ -121,55 +66,17 @@ void dfo_init(void)
{
if (!l.dfo)
ABORT("DFO not set");
util_list_init(&l.dump.chunk_list, struct dfo_chunk, list);
if (dfo_chunk_init())
ABORT("DFO memory chunk init failed");
l.dfo->init();
}
/*
* Find dump chunk for offset "off"
*
* This function is a bit hacky. DFO chunks can overlap. If two DFO chunks
* overlap, the last registered chunk wins. The dfo_chunk_find() function
* reflects that by returning the first memory chunk that is found in
* the dfo chunk list.
*
* In addition to that it calculates the "virtual end" of that chunk. An
* overlapping chunk can limit the "virtual end" of an underlying chunk so
* that the "virtual end" of that chunk is lower than the "real end".
*
* Example:
*
* chunk 1.: |------|
* chunk 2.: |---------------------|
* off.....: ^
* virt end: ^
* real end: ^
*
* In this case chunk 2 will be returned and "end" is set to the start of
* chunk 1.
*/
static struct dfo_chunk *dfo_chunk_find(u64 off, u64 *end)
{
struct dfo_chunk *dfo_chunk;
*end = U64_MAX;
dfo_chunk_iterate(dfo_chunk) {
if (dfo_chunk->start <= off && dfo_chunk->end >= off) {
*end = MIN(*end, dfo_chunk->end);
return dfo_chunk;
} else if (dfo_chunk->start > off) {
*end = MIN(*end, dfo_chunk->start - 1);
}
}
return NULL;
}
/*
* Seek to output dump offset "off"
*/
void dfo_seek(u64 off)
{
l.dump.off = off;
l.off = off;
}
/*
@@ -179,7 +86,7 @@ u64 dfo_read(void *buf, u64 cnt)
{
struct dfo_chunk *dfo_chunk;
u64 copied = 0, end, size;
u64 off = l.dump.off;
u64 off = l.off;
while (copied != cnt) {
dfo_chunk = dfo_chunk_find(off, &end);
@@ -192,7 +99,7 @@ u64 dfo_read(void *buf, u64 cnt)
off += size;
}
out:
l.dump.off = off;
l.off = off;
return copied;
}
@@ -201,5 +108,5 @@ out:
*/
u64 dfo_size(void)
{
return l.dump.size;
return dfo_chunk_dump_size();
}

View File

@@ -12,37 +12,12 @@
#ifndef DFO_H
#define DFO_H
#include "lib/util_list.h"
#include "zg.h"
struct dfo_chunk;
typedef void (*dfo_chunk_read_fn)(struct dfo_chunk *chunk, u64 off,
void *buf, u64 cnt);
struct dfo_chunk {
struct util_list_node list;
u64 start;
u64 end;
dfo_chunk_read_fn read_fn;
void *data;
};
extern void dfo_chunk_zero_fn(struct dfo_chunk *chunk, u64 off, void *buf,
u64 cnt);
extern void dfo_chunk_buf_fn(struct dfo_chunk *chunk, u64 off, void *buf,
u64 cnt);
extern void dfo_chunk_mem_fn(struct dfo_chunk *chunk, u64 off, void *buf,
u64 cnt);
extern void dfo_chunk_add(u64 start, u64 size, void *data,
dfo_chunk_read_fn read_fn);
extern u64 dfo_read(void *buf, u64 cnt);
extern void dfo_seek(u64 addr);
extern u64 dfo_size(void);
extern const char *dfo_name(void);
extern void dfo_init(void);
extern int dfo_set(const char *dfo_name);
u64 dfo_read(void *buf, u64 cnt);
void dfo_seek(u64 addr);
u64 dfo_size(void);
const char *dfo_name(void);
void dfo_init(void);
int dfo_set(const char *dfo_name);
/*
* DFO operations
@@ -52,4 +27,10 @@ struct dfo {
void (*init)(void);
};
/*
* Supported DFO dump formats
*/
extern struct dfo dfo_s390;
extern struct dfo dfo_elf;
#endif /* DFO_H */

View File

@@ -16,62 +16,31 @@
#include <string.h>
#include <unistd.h>
#include "zgetdump.h"
#include "df_elf.h"
#include "dfi.h"
#include "dfi_mem_chunk.h"
#include "dfo_mem_chunk.h"
#include "dfi_vmcoreinfo.h"
#include "dfo.h"
#define HDR_PER_CPU_SIZE 0x4a0
#define HDR_PER_MEMC_SIZE 0x100
#define HDR_BASE_SIZE 0x2000
/*
* File local static data
* Initialize ELF loads program headers
*/
static struct {
void *hdr;
u32 hdr_size;
} l;
/*
* Initialize ELF header
*/
static void *ehdr_init(Elf64_Ehdr *ehdr)
{
memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
ehdr->e_ident[EI_CLASS] = ELFCLASS64;
ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
ehdr->e_ident[EI_VERSION] = EV_CURRENT;
ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;
ehdr->e_ident[EI_ABIVERSION] = 0;
memset(ehdr->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
ehdr->e_type = ET_CORE;
ehdr->e_machine = EM_S390;
ehdr->e_version = EV_CURRENT;
ehdr->e_entry = 0;
ehdr->e_phoff = sizeof(Elf64_Ehdr);
ehdr->e_shoff = 0;
ehdr->e_flags = 0;
ehdr->e_ehsize = sizeof(Elf64_Ehdr);
ehdr->e_phentsize = sizeof(Elf64_Phdr);
ehdr->e_phnum = dfi_mem_chunk_cnt() + 1;
ehdr->e_shentsize = 0;
ehdr->e_shnum = 0;
ehdr->e_shstrndx = 0;
return ehdr + 1;
}
/*
* Initialize ELF loads
*/
static u64 loads_init(Elf64_Phdr *phdr, u64 loads_offset)
static u64 load_phdrs_init(Elf64_Phdr *phdr, u64 elf_offset)
{
struct dfi_mem_chunk *mem_chunk;
u64 mem_size = 0;
dfi_mem_chunk_iterate(mem_chunk) {
phdr->p_type = PT_LOAD;
phdr->p_offset = loads_offset;
phdr->p_offset = elf_offset;
phdr->p_vaddr = mem_chunk->start;
phdr->p_paddr = mem_chunk->start;
phdr->p_memsz = mem_chunk->end - mem_chunk->start + 1;
phdr->p_paddr = phdr->p_vaddr;
phdr->p_memsz = mem_chunk->size;
if (mem_chunk->read_fn == dfi_mem_chunk_read_zero)
/* Zero memory chunk */
phdr->p_filesz = 0;
@@ -79,7 +48,7 @@ static u64 loads_init(Elf64_Phdr *phdr, u64 loads_offset)
phdr->p_filesz = phdr->p_memsz;
phdr->p_flags = PF_R | PF_W | PF_X;
phdr->p_align = PAGE_SIZE;
loads_offset += phdr->p_filesz;
elf_offset += phdr->p_filesz;
mem_size += phdr->p_memsz;
phdr++;
}
@@ -87,160 +56,12 @@ static u64 loads_init(Elf64_Phdr *phdr, u64 loads_offset)
}
/*
* Initialize ELF note
* Initialize the program header entries for the notes and the related segment
* data.
*/
static void *nt_init(void *buf, Elf64_Word type, void *desc, int d_len,
const char *name)
static void *notes_init(Elf64_Phdr *phdr, void *segment_start, u64 elf_offset)
{
Elf64_Nhdr *note;
u64 len;
note = (Elf64_Nhdr *)buf;
note->n_namesz = strlen(name) + 1;
note->n_descsz = d_len;
note->n_type = type;
len = sizeof(Elf64_Nhdr);
memcpy(buf + len, name, note->n_namesz);
len = ROUNDUP(len + note->n_namesz, 4);
memcpy(buf + len, desc, note->n_descsz);
len = ROUNDUP(len + note->n_descsz, 4);
return PTR_ADD(buf, len);
}
/*
* Initialize prstatus note
*/
static void *nt_prstatus(void *ptr, struct dfi_cpu *cpu)
{
struct nt_prstatus_64 nt_prstatus;
static int cpu_nr = 1;
memset(&nt_prstatus, 0, sizeof(nt_prstatus));
memcpy(&nt_prstatus.gprs, cpu->gprs, sizeof(cpu->gprs));
memcpy(&nt_prstatus.psw, cpu->psw, sizeof(cpu->psw));
memcpy(&nt_prstatus.acrs, cpu->acrs, sizeof(cpu->acrs));
nt_prstatus.pr_pid = cpu_nr;
cpu_nr++;
return nt_init(ptr, NT_PRSTATUS, &nt_prstatus, sizeof(nt_prstatus),
"CORE");
}
/*
* Initialize fpregset (floating point) note
*/
static void *nt_fpregset(void *ptr, struct dfi_cpu *cpu)
{
struct nt_fpregset_64 nt_fpregset;
memset(&nt_fpregset, 0, sizeof(nt_fpregset));
memcpy(&nt_fpregset.fpc, &cpu->fpc, sizeof(cpu->fpc));
memcpy(&nt_fpregset.fprs, &cpu->fprs, sizeof(cpu->fprs));
return nt_init(ptr, NT_FPREGSET, &nt_fpregset, sizeof(nt_fpregset),
"CORE");
}
/*
* Initialize timer note
*/
static void *nt_s390_timer(void *ptr, struct dfi_cpu *cpu)
{
return nt_init(ptr, NT_S390_TIMER, &cpu->timer, sizeof(cpu->timer),
"LINUX");
}
/*
* Initialize TOD clock comparator note
*/
static void *nt_s390_tod_cmp(void *ptr, struct dfi_cpu *cpu)
{
return nt_init(ptr, NT_S390_TODCMP, &cpu->todcmp,
sizeof(cpu->todcmp), "LINUX");
}
/*
* Initialize TOD programmable register note
*/
static void *nt_s390_tod_preg(void *ptr, struct dfi_cpu *cpu)
{
return nt_init(ptr, NT_S390_TODPREG, &cpu->todpreg,
sizeof(cpu->todpreg), "LINUX");
}
/*
* Initialize control register note
*/
static void *nt_s390_ctrs(void *ptr, struct dfi_cpu *cpu)
{
return nt_init(ptr, NT_S390_CTRS, &cpu->ctrs, sizeof(cpu->ctrs),
"LINUX");
}
/*
* Initialize prefix register note
*/
static void *nt_s390_prefix(void *ptr, struct dfi_cpu *cpu)
{
return nt_init(ptr, NT_S390_PREFIX, &cpu->prefix,
sizeof(cpu->prefix), "LINUX");
}
/*
* Initialize vxrs_low register note
*/
static void *nt_s390_vxrs_low(void *ptr, struct dfi_cpu *cpu)
{
return nt_init(ptr, NT_S390_VXRS_LOW, &cpu->vxrs_low,
sizeof(cpu->vxrs_low), "LINUX");
}
/*
* Initialize vxrs_high register note
*/
static void *nt_s390_vxrs_high(void *ptr, struct dfi_cpu *cpu)
{
return nt_init(ptr, NT_S390_VXRS_HIGH, &cpu->vxrs_high,
sizeof(cpu->vxrs_high), "LINUX");
}
/*
* Initialize prpsinfo note
*/
static void *nt_prpsinfo(void *ptr)
{
struct nt_prpsinfo_64 prpsinfo;
memset(&prpsinfo, 0, sizeof(prpsinfo));
prpsinfo.pr_state = 0;
prpsinfo.pr_sname = 'R';
prpsinfo.pr_zomb = 0;
strcpy(prpsinfo.pr_fname, "vmlinux");
return nt_init(ptr, NT_PRPSINFO, &prpsinfo, sizeof(prpsinfo), "CORE");
}
/*
* 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)
{
void *ptr_start = ptr;
void *ptr = segment_start;
struct dfi_cpu *cpu;
ptr = nt_prpsinfo(ptr);
@@ -262,24 +83,24 @@ static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset)
}
}
out:
ptr = nt_vmcoreinfo(ptr);
ptr = nt_vmcoreinfo(ptr, dfi_vmcoreinfo_get());
memset(phdr, 0, sizeof(*phdr));
phdr->p_type = PT_NOTE;
phdr->p_offset = notes_offset;
phdr->p_filesz = (unsigned long) PTR_SUB(ptr, ptr_start);
phdr->p_offset = elf_offset;
phdr->p_filesz = PTR_DIFF(ptr, segment_start);
return ptr;
}
/*
* Setup dump chunks
*/
static void dump_chunks_init(void)
static void dump_chunks_init(void *hdr, u64 hdr_size)
{
struct dfi_mem_chunk *mem_chunk;
u64 off = 0;
dfo_chunk_add(0, l.hdr_size, l.hdr, dfo_chunk_buf_fn);
off = l.hdr_size;
dfo_chunk_add(off, hdr_size, hdr, dfo_chunk_buf_fn);
off += hdr_size;
dfi_mem_chunk_iterate(mem_chunk) {
if (mem_chunk->read_fn == dfi_mem_chunk_read_zero)
/* Zero memory chunk */
@@ -308,31 +129,29 @@ static void dfo_elf_init(void)
{
Elf64_Phdr *phdr_notes, *phdr_loads;
u32 alloc_size;
void *buf, *ptr;
u64 hdr_off;
void *ptr;
ensure_s390x();
alloc_size = HDR_BASE_SIZE +
dfi_cpu_cnt() * HDR_PER_CPU_SIZE +
dfi_mem_chunk_cnt() * HDR_PER_MEMC_SIZE;
l.hdr = zg_alloc(alloc_size);
buf = zg_alloc(alloc_size);
/* Init elf header */
ptr = ehdr_init(l.hdr);
ptr = ehdr_init(buf, dfi_mem_chunk_cnt() + 1);
/* Init program headers */
phdr_notes = ptr;
ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr));
phdr_loads = ptr;
ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr) * dfi_mem_chunk_cnt());
/* Init notes */
hdr_off = PTR_DIFF(ptr, l.hdr);
hdr_off = PTR_DIFF(ptr, buf);
ptr = notes_init(phdr_notes, ptr, hdr_off);
/* Init loads */
hdr_off = PTR_DIFF(ptr, l.hdr);
loads_init(phdr_loads, hdr_off);
l.hdr_size = hdr_off;
if (l.hdr_size > alloc_size)
ABORT("hdr_size=%u alloc_size=%u", l.hdr_size, alloc_size);
dump_chunks_init();
hdr_off = PTR_DIFF(ptr, buf);
load_phdrs_init(phdr_loads, hdr_off);
if (hdr_off > alloc_size)
ABORT("hdr_size=%llu alloc_size=%u", hdr_off, alloc_size);
dump_chunks_init(buf, hdr_off);
}
/*

128
zdump/dfo_mem_chunk.c Normal file
View File

@@ -0,0 +1,128 @@
/*
* Copyright IBM Corp. 2001, 2017, 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <string.h>
#include "zg.h"
#include "dfi_mem_chunk.h"
#include "dfo_mem_chunk.h"
/*
* File local static data
*/
static struct {
u64 size; /* Size of dump in bytes */
unsigned int chunk_cnt; /* Number of dump chunks */
struct util_list chunk_list; /* DFO chunk list */
} l;
/*
* Add dump chunk
*/
void dfo_chunk_add(u64 start, u64 size, void *data, dfo_chunk_read_fn read_fn)
{
struct dfo_chunk *dfo_chunk;
dfo_chunk = zg_alloc(sizeof(*dfo_chunk));
dfo_chunk->start = start;
dfo_chunk->end = start + size - 1;
dfo_chunk->data = data;
dfo_chunk->read_fn = read_fn;
util_list_add_head(&l.chunk_list, dfo_chunk);
l.chunk_cnt++;
l.size = MAX(l.size, dfo_chunk->end + 1);
}
/*
* Dump chunk function: Copy zero pages for chunk
*/
void dfo_chunk_zero_fn(struct dfo_chunk *dfo_chunk, u64 off, void *buf, u64 cnt)
{
(void) dfo_chunk;
(void) off;
memset(buf, 0, cnt);
}
/*
* Dump chunk function: Copy given buffer for chunk
*/
void dfo_chunk_buf_fn(struct dfo_chunk *dfo_chunk, u64 off, void *buf, u64 cnt)
{
memcpy(buf, dfo_chunk->data + off, cnt);
}
/*
* Dump chunk function: Copy given memory range for chunk
*/
void dfo_chunk_mem_fn(struct dfo_chunk *dfo_chunk, u64 off, void *buf, u64 cnt)
{
struct dfi_mem_chunk *mem_chunk = dfo_chunk->data;
mem_chunk->read_fn(mem_chunk, off, buf, cnt);
}
/*
* Find dump chunk for offset "off"
*
* This function is a bit hacky. DFO chunks can overlap. If two DFO chunks
* overlap, the last registered chunk wins. The dfo_chunk_find() function
* reflects that by returning the first memory chunk that is found in
* the dfo chunk list.
*
* In addition to that it calculates the "virtual end" of that chunk. An
* overlapping chunk can limit the "virtual end" of an underlying chunk so
* that the "virtual end" of that chunk is lower than the "real end".
*
* Example:
*
* chunk 1.: |------|
* chunk 2.: |---------------------|
* off.....: ^
* virt end: ^
* real end: ^
*
* In this case chunk 2 will be returned and "end" is set to the start of
* chunk 1.
*/
struct dfo_chunk *dfo_chunk_find(u64 off, u64 *end)
{
struct dfo_chunk *dfo_chunk;
*end = U64_MAX;
dfo_chunk_iterate(dfo_chunk) {
if (dfo_chunk->start <= off && dfo_chunk->end >= off) {
*end = MIN(*end, dfo_chunk->end);
return dfo_chunk;
} else if (dfo_chunk->start > off) {
*end = MIN(*end, dfo_chunk->start - 1);
}
}
return NULL;
}
struct util_list *dfo_chunk_list(void)
{
return &l.chunk_list;
}
u64 dfo_chunk_dump_size(void)
{
return l.size;
}
int dfo_chunk_init(void)
{
util_list_init(&l.chunk_list, struct dfo_chunk, list);
return 0;
}
void dfo_chunk_deinit(void)
{
memset(&l, 0, sizeof(l));
}

42
zdump/dfo_mem_chunk.h Normal file
View File

@@ -0,0 +1,42 @@
/*
* Copyright IBM Corp. 2001, 2017, 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef DFO_MEM_CHUNK_H
#define DFO_MEM_CHUNK_H
#include "lib/zt_common.h"
#include "lib/util_list.h"
struct dfo_chunk;
typedef void (*dfo_chunk_read_fn)(struct dfo_chunk *chunk, u64 off,
void *buf, u64 cnt);
struct dfo_chunk {
struct util_list_node list;
u64 start;
u64 end;
dfo_chunk_read_fn read_fn;
void *data;
};
void dfo_chunk_zero_fn(struct dfo_chunk *chunk, u64 off, void *buf, u64 cnt);
void dfo_chunk_buf_fn(struct dfo_chunk *chunk, u64 off, void *buf, u64 cnt);
void dfo_chunk_mem_fn(struct dfo_chunk *chunk, u64 off, void *buf, u64 cnt);
void dfo_chunk_add(u64 start, u64 size, void *data, dfo_chunk_read_fn read_fn);
struct dfo_chunk *dfo_chunk_find(u64 off, u64 *end);
struct util_list *dfo_chunk_list(void);
#define dfo_chunk_iterate(dfo_chunk) \
util_list_iterate(dfo_chunk_list(), dfo_chunk)
u64 dfo_chunk_dump_size(void);
int dfo_chunk_init(void);
void dfo_chunk_deinit(void);
#endif /* DFO_MEM_CHUNK_H */

View File

@@ -17,7 +17,10 @@
#include <time.h>
#include <unistd.h>
#include "zgetdump.h"
#include "df_s390.h"
#include "dfi_mem_chunk.h"
#include "dfo_mem_chunk.h"
#include "dfo.h"
/*
* File local static data
@@ -98,7 +101,8 @@ static void dfo_s390_dump_chunk_lc_fn(struct dfo_chunk *dump_chunk,
struct dfi_cpu *cpu = dump_chunk->data;
char lc[0x2000];
dfi_mem_read(cpu->prefix + off, &lc[off], cnt);
if (dfi_mem_virt_read(cpu->prefix + off, &lc[off], cnt))
return;
if (dfi_arch() == DFI_ARCH_64)
cpu2lc_64(lc, cpu);
else
@@ -142,7 +146,8 @@ static void add_cpu_to_dfo(struct dfi_cpu *cpu)
return;
if (!dfi_cpu_content_fac_check(DFI_CPU_CONTENT_FAC_VX))
return;
dfi_mem_read(cpu->prefix, &lc, sizeof(lc));
if (dfi_mem_virt_read(cpu->prefix, &lc, sizeof(lc)))
return;
if (!dfi_cpu_lc_has_vx_sa(&lc))
return;
vx_regs = zg_alloc(DFI_VX_SA_SIZE);
@@ -181,8 +186,8 @@ static void dump_chunks_init(void)
dfi_cpu_iterate(cpu)
add_cpu_to_dfo(cpu);
dfo_chunk_add(dfi_mem_range() + DF_S390_HDR_SIZE,
DF_S390_EM_SIZE,
&l.em, dfo_chunk_buf_fn);
DF_S390_EM_SIZE,
&l.em, dfo_chunk_buf_fn);
}
/*

View File

@@ -10,6 +10,8 @@
*/
#include "zgetdump.h"
#include "zg.h"
#include "dt.h"
/*
* Supported dump tools

View File

@@ -12,9 +12,10 @@
#ifndef DT_H
#define DT_H
#include "dfi.h"
#include <stdbool.h>
#include "dfi.h"
#define DUMP_EXTENDED true
#define DUMP_NON_EXTENDED false
@@ -24,12 +25,21 @@ struct dt {
void (*info)(void);
};
extern void dt_init(void);
extern void dt_info_print(void);
extern void dt_arch_set(enum dfi_arch arch);
extern void dt_version_set(int version);
extern void dt_attr_mem_limit_set(u64 mem_limit);
extern void dt_attr_force_set(int value);
extern void dt_attr_dasd_type_set(const char *dasd_type);
void dt_init(void);
void dt_info_print(void);
void dt_arch_set(enum dfi_arch arch);
void dt_version_set(int version);
void dt_attr_mem_limit_set(u64 mem_limit);
void dt_attr_force_set(int value);
void dt_attr_dasd_type_set(const char *dasd_type);
/*
* Supported s390 dumpers
*/
extern struct dt dt_s390mv;
extern struct dt dt_s390mv_ext;
extern struct dt dt_s390sv;
extern struct dt dt_s390sv_ext;
extern struct dt dt_scsi;
#endif

View File

@@ -9,7 +9,8 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include "zgetdump.h"
#include "dt.h"
#include "df_s390.h"
/*
* Initialize s390 multi-volume dump tool (for -d option)

Some files were not shown because too many files have changed in this diff Show More