Compare commits

...

76 Commits

Author SHA1 Message Date
Jan Höppner
c2db7ce05f New release s390-tools-2.35.0
Signed-off by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 13:23:01 +02:00
Steffen Eiden
0031c762cf rust/pv_core: Fix rusttest owned file descriptor already closed
Newer rust std libary code checks if a fd is already closes and panics.
Test code created a file with fd=17 and relied that test code never
touched the file. This cannot be done anymore. Just use the working dir
as backing file.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Steffen Eiden
7031429d1e rust/pv: Fix new warnings for rustc 1.80
`sizeof` was added into the prelude in rustc 1.80.
This triggers a lint-warning for `unused_qualifications` if rustc 1.80+
is used. Fix this warning by using a use statement to stay compatible
for <1.80.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Steffen Eiden
73d8597db1 rust/pv_core: Clarify error reason for 003* return codes
The RCs 30, 31, 32 may be caused by a malicious host or host bug.
Make this clear and advise to stop the SE-guest.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Marc Hartmayer
77d0d1d1a1 rust/Makefile: Consider HAVE_CARGO in the clean target
This fixes `make clean` errors when cargo is not available:

  $ make clean
  ...
  | make[1]: Entering directory '/home/mhartmay/storage/git/poky/build/workspace/sources/s390-tools/rust'
  | cargo clean  --release
  | /bin/bash: cargo: command not found
  | make[1]: *** [Makefile:72: clean] Error 127

Reviewed-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>
2024-10-01 12:16:19 +02:00
Finn Callies
77a7e11a51 rust/Makefile: Build pvapconfig only on s390x
Configuring the AP bus only makes sense on s390x.

Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Suggested-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Mikhail Zaslonko
279070fa43 zdump/ngdump: Fix seek error on 'zgetdump -d'
When checking CDL formatted DASD for installed dump-tool (zgetdump -d),
we might stumble upon an 'empty' boot record pointer in the volume label
filled with bytes of 0x40 (EBCDIC spaces). This leads to the following
seek error reported:

  # zgetdump -d /dev/dasdb
  zgetdump: Could not seek "/dev/dasdb" (Invalid argument)

Check for empty boot record and return proper error code by
ngdump_get_eckd_part_num() in order to end up with a regular
"No dump tool found" message.

Fixes: f3bcd94524 ("zdump: Add zgetdump -d support for ECKD ldipl-dump")
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Eduard Shishkin
3989e1b741 zipl/src: fix segfault on '--dry-run' for device-based dumps
This fixes a segfault when the option '--dry-run' is specified for
device-based dumps (for which the bootmap file is created on a RAW
device, not formatted with a file system).

The actual status is that the option '--dry-run' for device-based
dumps is not implemented. The implementation is evaluated as not
trivial: In contrast with filesystem-based dumps, it is not possible
to simply make do with rename/unlink of temporary created bootmap.

The fixup returns error on any not file system based dumps being
created with the option '--dry-run'.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Eduard Shishkin
c230b5385a zipl/src: move common checks to disk_is_appropriate()
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Eduard Shishkin
68ecf79b01 zipl/src: cleanups in add_dump_progrem()
Drop a pair of duplicated assignmets
Replace the parameter 'struct job_data' with 'struct job_dump_data'

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Eduard Shishkin
f2960eb0df zipl/src: drop check_dump_device_late()
Move all checks from check_dump_device_late() to disk_is_approproate()
and drop check_dump_device_late() entirely

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Eduard Shishkin
4d004cf8b1 zipl/src: drop never happening case in check_dump_device_late()
In the function check_dump_device_late() drop the case of
(info->device != target_info->device) which never happens. Indeed,
the @info created in check_dump_device_late() coincides with the
@target_info previously created by
prepare_build_program_table_{file, device}.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Mikhail Zaslonko
d8f504f271 zdump/dfi: Fix vm_info_get() check for non-VR kernel
Since the following kernel commit:
"32db401965f1 s390/mm: Pin identity mapping base to zero"
we can have zero identity_base value in os_info. This makes zgetdump
check for non-VR kernel in vm_info_get() incorrect what leads to missing
data (e.g. UTS kernel version) in 'zgetdump -i' output.
Check for zero kaslr_offset value instead (like crash and makedumpfile
do) in order to identify non-VR kernel.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Jan Höppner
7fb3ee4478 gitignore: Add zipl md files
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Mikhail Zaslonko
a95bad6c87 zdump/dfo_s390: Support s390 DFO for vr-kernel dumps
Since memory chunks can overlap for vr-kernel dumps stored in elf
format (ngdump, zfcpdump), we need to consider this when converting to
s390 dump output format. For that sort DFI memory chunks by start
address and adjust dfo_s390 logic for identifying memory gaps.
Otherwise we might end up with bogus DFO memory chunks being created.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Mete Durlu
147ff1bf49 cpuplugd: Halt cpu hotplugging on vertical polarization
On vertical polarization, kernel can be adjusting CPU capacities
dynamically, and cpuplugd can interfere this with hotplug operations
causing performance degradation. To prevent this, check if system has
switched its polarization state, and act accordingly.
If system is on vertical polarization when daemon starts, no CPU hotplug
action is triggered. If system changes to vertical polarization during
daemon runtime, revert cpuhotplug adjustments and stop further CPU
hotplug actions. If system switches back to horizontal polarization
during runtime of the daemon, start evaluating CPU hotplug rules and
trigger adjustments.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Signed-off-by: Mete Durlu <meted@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Mete Durlu
c91d172c99 cpuplugd/cpu: Rework CPU management functions
Simplify the cpu management parts of cpuplugd code by introducing
functions from libutil and rework some logic to drop some assumptions
about how kernel assigns cpuids.
Right now cpuplugd assumes that the cpuids are always sequential and
there are no gaps in between, however kernel does not guarantee that.
Make cpuplugd compliant by traversing cpu sysfs entries instead.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Signed-off-by: Mete Durlu <meted@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Eduard Shishkin
0e4992da3a zipl/src: prevent NULL pointer deref when preparing qcow2 images for IPL
This fixes c0f02d2f6 which results in problems when preparing qcow2
images for IPL:

zipl -V --blsdir /tmp/tmp.kdPooQjoBh/boot//loader/entries/ --config /
Program terminated with signal SIGFPE, Arithmetic exception.

Don't use pointer to not initialized struct disk_info after failed
auto-detection of disk parameters. Make the check that the file
locates on the disk in the form of a separate procedure.

Reported-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Acked-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Tested-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Eduard Shishkin
41da0f0809 zipl/src: make disk type detecton fail
When detecting disk type, the function disk_get_info() is called.
It can fail for various reasons (e.g. when the logial target is not
eligible for boot record installation).

Once disk_get_info() fails, don't proceed with type detection.
Return error instead. When applicable, mark the dump job with
"is_ngdump" flag to avoid extra type detection calls.

Acked-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Eduard Shishkin
f43789e16a zipl/src: fix bugs in SCSI dump installation
This fixes d6b702d57 which introduces a problem: SCSI dump
installation fails:

zipl -V -d /dev/mapper/mpathd1
Error: Invalid dump device: Could not read partition table

The reasons:
1) Wrong (logical) device is passed as a target base;
2) In case of 'source_script' the check to make sure that specified
   target is over a partition isn't applicable any more after zipl
   support of complex logical targets (e.g. mirrors).

The fixup passes the physical device as a target base (instead of
the logical one). Also the fixup removes invalid check from
check_dump_device_late() and instead adds a more generic check to
the helper script that data starts beyong the boot area.

Reported-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Tested-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Marc Hartmayer
136e5eed8c rustfmt: List experimental group_imports option
This option is experimental, but can still be useful.

While at it, sort the options alphabetically.

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>
2024-09-13 19:15:01 +02:00
Eduard Shishkin
e09753f2a3 chreipl_helper.device-mapper: complete device resolution process
This fixes 670bf3e8 which actually isn't an equivalent refactoring.
The generic dm-device resolution procedure was modified to not resolve
the topmost dm-device in the path. So that any calles who don't expect
it, should complete the resolutioin process by themselves. In case of
chreipl_helper such completion was missed. chreipl(8) utility doesn't
expect dm-devices at the output of chreipl_helper.device-mapper

Example:

NAME                     MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINT
sda                        8:0    0   20G  0 disk
|-sda1                     8:1    0   20G  0 part
`-mpathb                 253:0    0   20G  0 mpath
  `-mpathb1              253:2    0   20G  0 part  /
sdb                        8:16   0   20G  0 disk
|-sdb1                     8:17   0   20G  0 part
`-mpathb                 253:0    0   20G  0 mpath
  `-mpathb1              253:2    0   20G  0 part  /

Expected result:
8:16

Actual result:
253:0

As a result, the chreipl(8) "node" option stopped working.
The fixup adds the completion.

Reported-by: Alexander Egorenkov <egorenar@linux.ibm.com>
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>
2024-09-13 19:15:01 +02:00
Sertonix
fe2d240656 netboot/mk-s390image: Fix size when argument is a symlink
`du -b` by default returns the size of a symlink when it is passed a
symlink. Adding the `-L` option allows passing symlinks to mk-s390image
without resulting in unbootable image.

Signed-off-by: Sertonix <sertonix@posteo.net>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Fixes: https://github.com/ibm-s390-linux/s390-tools/pull/176
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Frank Heimes
6fc450f696 (genprotimg|zipl)/boot: discard .note.package ELF section to save memory
The .note.package [1] section is not used by the zipl/genprotimg bootloaders,
therefore discard them via linker script.

This fix solves the error:
 /usr/bin/ld: Heap section doesn't conform to the described memory layout
 collect2: error: ld returned 1 exit status
 make[4]: *** [Makefile:77: stage3a.elf] Error 1
 make[4]: Leaving directory '/<>/genprotimg/boot'
 make[3]: *** [Makefile:20: all-recursive] Error 1
 make[3]: Leaving directory '/<>/genprotimg'
 make[2]: *** [Makefile:56: genprotimg] Error 2

[1] https://systemd.io/ELF_PACKAGE_METADATA/

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/174
Closes: https://github.com/ibm-s390-linux/s390-tools/pull/176
[seiden@linux.ibm.com: Add/edit fixes tags]
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Frank Heimes <frank.heimes@canonical.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:14:16 +02:00
Steffen Eiden
6a55d0c2e5 rust/pv: Lower most lints to warn
Lower the lint level to warn for the styling lints.
This avoids compile issues during packaging for newer tooling with
potential more lint findings.
Still deny compiling if a public symbol has no documentation.

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/173
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Eduard Shishkin
0e69dc1262 zipl_helper.device-mapper: add support for 'raid' device-mapper target
Introduce target operations (struct target_ops);
For each supported device-mapper target implement
. check_target_status()
. get_target_data()

Add support for new 'raid' device-mapper target, which is now default
in LVM.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Eduard Shishkin
3296d85e35 zipl/src: add support of md-mirrors
Add a script to process mirrored zipl targets managed by Linux "md"
driver (AKA "software mirrors")

. In the file zipl_helper.device-mapper.c implement two handlers
  identified by pairs (ZIPL_UTIL_ID, MD_DRIVER_ID) and
  (CHREIPL_UTIL_ID, MD_DRIVER_ID) for the helpers zipl_helper.md
  and chreipl_helper.md respectively

  . zipl_helper.md: prints sets of target parameters (one such set
    per mirror) for a specified logical zipl target managed by linux
    "md" driver.

  . chreipl_helper.md: for a specified logical zipl target managed
    by linux "md" driver prints a random disk from the set of disks
    participating in the mirrored setup.

. Add zipl_helper.md and chreipl_helper.md as symbolic links to
  zipl_helper.device-mapper

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Eduard Shishkin
0eeab96f0d zipl_helper.device-mapper: check status of "mirror" dm targets
For "mirror" device-mapper targets:

. Check status of all the mirrors;
. Return error if some mirror contain failures;
. Align the sample output properly

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Eduard Shishkin
283a61dc2f zipl_helper.device-mapper: support multiple base disks
For "mirror" device-mapper targets:

. Don't assign a logical mirrored device as a zipl target base.
  Instead, add one more branch in complete_physical_device() and
  proceed (in that new branch) to the physical disk participating
  in the mirrored target. This approach allowes to handle
  heterogeneous mirrors properly;
. Provide a set of target parameters for each found physical disk
  by calling dm_dev_to_zipl_params() recursively;
. Don't allow "nested mirrors" by checking/updating the
  fail_on_mirror global;
. Remove the requirements on including block #0 to the mirrored
  device-mapper setup (no more actual);
. Update comments.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Eduard Shishkin
670bf3e870 zipl: refactor zipl_helper.device-mapper
This is used by the next patches in the series to support mirror
setups not including boot sectors (e.g. mirrors over partitions).

. Rework the core procedure of device resolution (by walking along
  the device-mapper tree during logical device resolution) to be an
  explicit sequence of pairs (level-lookup, goto-parent-level);
. Add an "extended" device to keep a track of file system offset
  while ascending the device tree;
. Identify all possible results of a single level lookup;
. Rename target_entry to dmpath_entry;
. Make the main() function to look like a call of a handler
  identified by a pair (driver-id, util-id) and found by the name
  of the executable.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Eduard Shishkin
9cfaac58ea zipl_helper.device-mapper: fix bug in get_physical_device()
Fix mistake in @fs_offset calculation.

Since any logical dm-device can be built of partitions, @fs_offset
must not decrease while ascending the "device tree" during the
procedure of dm-device resolution (which always starts at the
formatted logical device, for which @fs_offset is 0).

This bug was not reproducible earlier because of restricted
functionality in a combination with side-effects. The fixup is
required however by the next patches in the series implementing
support of mirrored targets by zipl tool

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Eduard Shishkin
d6b702d579 zipl/src: add basic support for multiple target base disks
. Modify disk_get_info() to process multiple sets of target parameters
  provided by the helper script and store it in the array of "targets"
  of the structure job_target_data;
. Besides the logical device, maintain an array of physical base disks
  in the disk_info structure;
. Use the logical target device only to create bootmap (it is
  automatically mirrored by the respective linux driver (dm, or md)
  managing the mirrored target). In contrast, install bootstrap blocks
  to each physical base disk individually, bypassing that driver;
. Report in verbose mode on which base disks the bootstrap
  installation was performed;
. Use the following logic of setting @info->device (which is printed
  as "Device...:" in verbose mode):
  . source_auto   - the target base disk is set;
  . source_script - the target (logical) device is set;
  . source_user   - the device specified by user (via --targetbase
                    option), or config file is set.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Peter Oberparleiter
d9a9bd8dcf zdev: Add option to select IPL device
Add new command-line option --ipldev. When specified and IPL was done
from a supported device type, the IPL device is selected for the
requested tool operation.

Example to list IPL device information:

$ lszdev --ipldev

Example to create a persistent configuration for the IPL device:

$ chzdev --enable --persistent --ipldev

Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-22 10:32:36 +02:00
Peter Oberparleiter
cad4e9e15b zdev: Add function for reading text files
Reduce code complexity by adding a utility function for reading text
files based on a variable path.

Note: chzdev/lszdev tools apply special path-handling via command line
option --base to allow redirecting hard-coded paths therefore libutil's
util_file functions cannot easily be used.

Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-22 10:32:36 +02:00
Eduard Shishkin
c0f02d2f68 zipl/src: Fix problems when target parameters are specified by user
Steps to reproduce: Prepare some disk for IPL, specifying its
parameters via zipl "target options", and an image IMAGE_NAME
located on another disk. Don't specify "-a" option.

Actual result: Installation succeeded (resulting in unbootable setup)
Expected result: "Error: Could not add image file 'IMAGE_NAME': File
is not on target device"

The problem is in incorrect evaluation of device number (dev_t)
of the base disk where the image is located by the function
add_component_file_range() in case when target parameters are
specified by user.

Fixup: Retrieve info of the underlying disk without any user hints,
passing zeroed structure job_target_data

This is an improved version of fb0b6263d that was reverted by
63ff07ba3 afterwards. The shortcoming of the original ( fb0b6263d )
fix: it fails to prepare for IPL mounted qcow2 images.
The difference from the original fix: when making sure that boot
files are located on the target disk: in case of failed auto-detection
of disk parameters skip the check with warnings instead of aborting
the whole installation session.

Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-22 10:32:36 +02:00
Finn Callies
5218c243f4 cpacfstats: add MSA 10 and MSA 11 counters
MSA 10 and MSA 11 introduce new function codes containing Full XTS
functions for KM instruction and HMAC functions for KMAC instruction.
Additional Full XTS and HMAC for PCKMO instruction is introduced.

Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-22 10:32:36 +02:00
Finn Callies
c364692e7a cpacfstats: white space fix in cpacfstats/cpacfstatsd.c
Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-22 10:32:36 +02:00
Nihar Panda
41eb7d076f ziomon/ziorep_config: fix warning when multipath device is not there
Perl logs warning message if a variable is not initialized.
get_device_data() set mp_dev with multipath device for a scsi disk device.
mp_dev remain uninitialized if there is no multipath device.
This can happen if a scsi device is not managed by dm multipath driver.

Warning message:
"Use of uninitialized value in subroutine entry at /usr/sbin/ziorep_config line 136"

Fix it by skipping the code dealing with mp_dev and continue with next
scsi device in the loop.

To reproduce, remove a scsi device from dm multipath.
$multipathd -k'del path sdh'
Then run `ziorep_config -D`.

Signed-off-by: Nihar Panda <niharp@linux.ibm.com>
Reviewed-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>
2024-08-22 10:32:36 +02:00
Joern Siglen
1062a7cde6 dbginfo.sh: add network sockstat info
Add procfs files to collect network socket data.

Suggested-by: Eberhard Pasch <epasch@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-22 10:31:33 +02:00
Jan Höppner
54e5e99657 Prepare for next release
Signed-off by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 15:17:58 +02:00
Jan Höppner
4c922b105b New release s390-tools-2.34.0
Signed-off by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 15:17:42 +02:00
Mikhail Zaslonko
4b19b9d950 zdump/dfi_s390: Get rid of device type check for s390_ext dump
Simplify ioctl error processing logic for "BLKSSZGET" operation.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:06 +02:00
Ingo Franzki
cee4bb4995 libkmipclient: Fix typo in debug message
Fix copy & paste error in debug message

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:06 +02:00
Ingo Franzki
c98d8e7629 libkmipclient: Remove superfluous break
A double break in a switch does not make any sense, remove it.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:06 +02:00
Joern Siglen
96084339f5 dbginfo.sh: update/add additional DASD collection
We changed lscss for more detailed output.
Adding use of dasdview for a detailed view on DASD storage.
This data will be collected in a separate file, as many DASDs might flood
the runtime.out
Also updated man pages as a new step is added

Reviewed-by: Stefan Hberland <sth@linux.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:06 +02:00
Harald Freudenberger
f8d5b4b341 rust/pvapconfig: add dead_code pragmas to suppress warnings
The ap.rs code is already prepared for possible support
for CCA mode APQNs for the Secure Execution environment.
However, this patch marks these fields and structs with
pragma allow(dead_code) to prevent warnings during cargo
build of pvapconfig.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:06 +02:00
Matthew Rosato
5806c4e1f4 ap_tools/ap-check: implement get capabilities callout
Add a new action type 'capabilities' for the 'get' event.  This
will return a JSON list of events and actions that the callout
script recognizes and actually does something with.  It omits
events like 'notify' and actions like 'list' that ap-check
currently ignores.

Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:06 +02:00
Matthew Rosato
9d199e06cb ap_tools/ap-check: implement dynamic config during live modify
mdevctl introduces a new event type 'live' with action 'modify',
indicating that the specified configuration changes should be
made dynamically if possible.  Use this as a trigger to perform
dynamic configuration changes to the specified vfio-ap device
if it is active.

Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:05 +02:00
Matthew Rosato
f7425a08d1 ap_tools/ap-check: refactor active config checking
Create a single routine to perform conflict analysis for a
given device against the active configuration.

Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:05 +02:00
Matthew Rosato
f6a97902c3 libap: handle reading ap_config attribute
While unlikely, it is possible for a vfio-ap configuration JSON
to include the 'ap_config' attribute.  In this case, process it
by overwriting the current list of adapters, domains and control
domains for the associated vfio-ap device struct.

Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:05 +02:00
Matthew Rosato
962af1a90e libap: add routines to generate masks for vfio_ap_device
Add routines to generate mask values for the adapters, domains and
control domains for a specified vfio_ap_device struct.

Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:05 +02:00
Matthew Rosato
46dadc8cc4 libap: add routine to check for dynamic config support
For a given vfio-ap mdev, determine whether or not the device will
need dynamic config operations.  This boils down to whether or not
the device is currently active + whether or not the kernel is
detected to support dynamic config operations (via the
'ap_config' sysfs attribute).

Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:05 +02:00
Matthew Rosato
9c8d117cc2 zdev: remove duplicate ap_node structure
There is already an identical vfio_ap_node defined in libap, use
that instead.  Also remove one awkard usage of struct ap_node in
libap.

Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:05 +02:00
Vineeth Vijayan
d7b3196286 zdev: fix warning about failed ATTR writes by udev
The qeth-udev-rule execution logs a warning as below in the journalfs.

Failed to write ATTR{/sys/bus/ccwgroup/drivers/qeth/group}, \
ignoring: Invalid argument

This occurs because the udev rule for qeth devices is triggered by
multiple ccw devices and can be invoked in parallel. This can lead to a
situation where each of the three parallel-running udev rules tries to
group the devices simultaneously. As a result, only the first rule
succeeds, while the others fail with an -EINVAL error because the CCW
devices have already been grouped.

To prevent this, schedule a new change uevent for the base device, which
will verify the sysfs before attempting the grouping. The change event is
triggered by all three devices, ensuring that the actual write to the
attribute occurs only once and only when the sysfs attribute is ready.

Hence the add events on different devices are serialized to change event
on the base device, which then prevent duplicate concurrent grouping
attempts.

Suggested-by: Peter Oberparleiter <oberpar@linux.ibm.com>
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>
2024-07-08 09:25:12 +02:00
Alexander Egorenkov
b6c30404bc zfcpdump: drop use of mmap() for /proc/vmcore
The function copy_table_entry_write() maps/unmaps /proc/vmcore for each
64kB of the file in order to write its content to a dump partition.
This requires a page allocation of order 2 in kernel (crst_table_alloc)
each time a mmap() syscall is performed and which cannot always be
fulfilled due to external memory fragmentation. And this in turn
results in a OOM kernel panic while writing /proc/vmcore content to
a dump partition. To make zfcpdump more robust in the face of such
problems with page allocations of order > 0, we use a simple file
read/write loop to transfer the content of /proc/vmcore to a dump
partition. This solution is less efficient (by not much) than the old
one with mmap() because it requires additional user space copy but
we trade off here efficiency for robustness which is more important
for zfcpdump.

We use a statically allocated buffer to read data into from /proc/vmcore
and write to a dump partition to avoid repeated use of the memory
mapping kernel path which would be required for a buffer allocated
dynamically at each entry of copy_table_entry_write().

Another possible and very convenient solution would be to use sendfile()
which would avoid any user space copies but, unfortunately, sendfile()
doesn't work with large /proc files.

Example of failed mmap() call for /proc/vmcore
==============================================

  [   26.568654] init invoked oom-killer: gfp_mask=0x40cc0(GFP_KERNEL|__GFP_COMP), order=2, oom_score_adj=0
  [   26.568665] CPU: 0 PID: 1 Comm: init Not tainted 6.9.0-20240504.rc6.git0.9986ea583f39.300.fc39.s390x+zfcpdump #1
  [   26.568668] Hardware name: IBM 3931 A01 704 (LPAR)
  [   26.568669] Call Trace:
  [   26.568671]  [<000003ffe03277c6>] dump_stack_lvl+0x76/0x98
  [   26.568676]  [<000003ffe00f15c8>] dump_header+0x58/0x2d0
  [   26.568680]  [<000003ffe00f219a>] out_of_memory+0x252/0x348
  [   26.568683]  [<000003ffe0132f3e>] __alloc_pages_slowpath.constprop.0+0x65e/0x7c0
  [   26.568686]  [<000003ffe01331a4>] __alloc_pages+0x104/0x128
  [   26.568688]  [<000003ffe001ab46>] crst_table_alloc+0x2e/0xa0
  [   26.568693]  [<000003ffe01164c4>] __pmd_alloc+0x24/0x160
  [   26.568696]  [<000003ffe0116650>] pmd_alloc+0x50/0x68
  [   26.568698]  [<000003ffe0117be4>] remap_pfn_range_notrack+0x194/0x310
  [   26.568701]  [<000003ffe0117d7c>] remap_pfn_range+0x1c/0x28
  [   26.568703]  [<000003ffe0015442>] remap_oldmem_pfn_range+0xb2/0x108
  [   26.568705]  [<000003ffe01a0544>] mmap_vmcore+0x414/0x448
  [   26.568707]  [<000003ffe01937c4>] proc_reg_mmap+0x84/0xa0
  [   26.568709]  [<000003ffe011f264>] mmap_region+0x22c/0x6f8
  [   26.568711]  [<000003ffe011fae8>] do_mmap+0x3b8/0x410
  [   26.568713]  [<000003ffe01015cc>] vm_mmap_pgoff+0x9c/0xe8
  [   26.568715]  [<000003ffe011d006>] ksys_mmap_pgoff+0x8e/0xb8
  [   26.568716]  [<000003ffe011d0f4>] __s390x_sys_old_mmap+0x74/0x90
  [   26.568718]  [<000003ffe0341a2a>] __do_syscall+0x1aa/0x220
  [   26.568720]  [<000003ffe03478b0>] system_call+0x70/0x98
  [   26.568724] Mem-Info:
  [   26.568725] active_anon:1 inactive_anon:12 isolated_anon:0
                  active_file:83590 inactive_file:93939 isolated_file:0
                  unevictable:201 dirty:17845 writeback:4
                  slab_reclaimable:4259 slab_unreclaimable:1482
                  mapped:174 shmem:0 pagetables:810
                  sec_pagetables:0 bounce:0
                  kernel_misc_reclaimable:0
                  free:2694 free_pcp:105 free_cma:0
  [   26.568729] Node 0 active_anon:4kB inactive_anon:48kB active_file:334360kB inactive_file:375756kB unevictable:804kB isolated(anon):0kB isolated(file):0kB mapped:696kB dirty:71380kB writeback:16kB shmem:0kB writeback_tmp:0kB kernel_stack:544kB pagetables:3240kB sec_pagetables:0kB all_unreclaimable? no
  [   26.568732] DMA free:10776kB boost:0kB min:3496kB low:4368kB high:5240kB reserved_highatomic:0KB active_anon:4kB inactive_anon:48kB active_file:334360kB inactive_file:375756kB unevictable:804kB writepending:71360kB present:786428kB managed:764664kB mlocked:0kB bounce:0kB free_pcp:420kB local_pcp:420kB free_cma:0kB
  [   26.568735] lowmem_reserve[]: 0 0 0
  [   26.568738] DMA: 1069*4kB (UH) 757*8kB (UH) 11*16kB (H) 6*32kB (H) 1*64kB (H) 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 10764kB
  [   26.568747] 177773 total pagecache pages
  [   26.568748] 196607 pages RAM
  [   26.568748] 0 pages HighMem/MovableOnly
  [   26.568749] 5441 pages reserved
  [   26.568749] Tasks state (memory values in pages):
  [   26.568750] [  pid  ]   uid  tgid total_vm      rss rss_anon rss_file rss_shmem pgtables_bytes swapents oom_score_adj name
  [   26.568751] Out of memory and no killable processes...
  [   26.568752] Kernel panic - not syncing: System is deadlocked on memory
  [   26.568755] CPU: 0 PID: 1 Comm: init Not tainted 6.9.0-20240504.rc6.git0.9986ea583f39.300.fc39.s390x+zfcpdump #1
  [   26.568758] Hardware name: IBM 3931 A01 704 (LPAR)
  [   26.568759] Call Trace:
  [   26.568760]  [<000003ffe03277c6>] dump_stack_lvl+0x76/0x98
  [   26.568763]  [<000003ffe001f14e>] panic+0x10e/0x2e8
  [   26.568765]  [<000003ffe00f21c8>] out_of_memory+0x280/0x348
  [   26.568768]  [<000003ffe0132f3e>] __alloc_pages_slowpath.constprop.0+0x65e/0x7c0
  [   26.568771]  [<000003ffe01331a4>] __alloc_pages+0x104/0x128
  [   26.568773]  [<000003ffe001ab46>] crst_table_alloc+0x2e/0xa0
  [   26.568776]  [<000003ffe01164c4>] __pmd_alloc+0x24/0x160
  [   26.568779]  [<000003ffe0116650>] pmd_alloc+0x50/0x68
  [   26.568781]  [<000003ffe0117be4>] remap_pfn_range_notrack+0x194/0x310
  [   26.568784]  [<000003ffe0117d7c>] remap_pfn_range+0x1c/0x28
  [   26.568787]  [<000003ffe0015442>] remap_oldmem_pfn_range+0xb2/0x108
  [   26.568789]  [<000003ffe01a0544>] mmap_vmcore+0x414/0x448
  [   26.568791]  [<000003ffe01937c4>] proc_reg_mmap+0x84/0xa0
  [   26.568793]  [<000003ffe011f264>] mmap_region+0x22c/0x6f8
  [   26.568795]  [<000003ffe011fae8>] do_mmap+0x3b8/0x410
  [   26.568797]  [<000003ffe01015cc>] vm_mmap_pgoff+0x9c/0xe8
  [   26.568799]  [<000003ffe011d006>] ksys_mmap_pgoff+0x8e/0xb8
  [   26.568801]  [<000003ffe011d0f4>] __s390x_sys_old_mmap+0x74/0x90
  [   26.568803]  [<000003ffe0341a2a>] __do_syscall+0x1aa/0x220
  [   26.568805]  [<000003ffe03478b0>] system_call+0x70/0x98

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Mikhail Zaslonko
6d15850480 zdump: Use os_info data to convert dump vaddr to paddr
For vr-kernel dumps use the offsets stored in os_info entries for
virt to phys address conversion when dump virtual address is to be
read, (e.g. vmcoreinfo symbols) using similar method as implemented
in crash-utility.
It is mainly required for reading "init_uts_ns" symbol and, in case
of crashed kdump, "lowcore_ptr" symbol along with a pointers to the
lowcore of every CPU.

Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Mikhail Zaslonko
858da9af57 zdump: Use os_info.h from include/boot
Get rid of duplicate os_info definitions in dfi_vmcoreinfo.c

Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Mikhail Zaslonko
a7373674bf include/boot/os_info: Add static assert for os_info size
Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Mikhail Zaslonko
613353cd33 zdump/dfi_elf: Support core dumps of vr-kernels
Support vmcore based dumps (ngdump, zfcpdump) with uncoupled physical and
virtual addresses. For that we just remove p_paddr != p_vaddr sanity check
for elf load headers.

Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Peter Oberparleiter
f6e932e0fd libutil: Make formatted meta-data configurable
Output generated using libutil's util_fmt_*() functions contains
meta-data such as hostname and time of invocation. When writing test
cases that compare expected and actual tool output, this run-time
variable information needs to be filtered out, resulting in increased
complexity.

To address this, add a global option to suppress meta-data output via
environment variable FMT_NOMETA. If set to '1', no meta-data will be
generated.

Example:

$ FMT_NOMETA=1 chpstat --format json

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Steffen Eiden
7e31c425c9 rust/pv: Try again if first CRL-URI is invalid
The previous implementation did stop after the first download was
successful, even if it did not contain a CRL. This behavior renders a
second, third, ... link as backup location useless as the code ignores
them if the URI e.g. contains a error message. That results in not
having a CRL and probably a failed certificate verification.

Fix this by trying again if the download was successful but did not
contain a CRL

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Mikhail Zaslonko
6c4171b775 zdump/dfi_s390: Adjust device type check for s390_ext dump
In order to allow loop devices usage for DASD dump emulation in fvt-tests,
do not bail out on ZG_TYPE_DASD device type returned by zg_type() for
s390_ext dump.

Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Jan Höppner
0b0960254e s390-tools: Replace 'which' with built-in 'command -v'
There are still a few scripts using the 'which' command to determine
either the full path or the mere existence of an executable.
Some of these scripts might run in minimal environments where 'which' is
not available due to dependency restriction. 'which' is also considered
unreliable for historical implementation details.

Use the POSIX defined [1] built-in 'command -v' instead to reduce
package dependencies and improve reliability.

[1] https://pubs.opengroup.org/onlinepubs/9699919799/
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Alexander Egorenkov
4d2c9267c2 dumpconf: add new parameter 'SCP_DATA' for SCSI/NVMe/ECKD dump devices
The new parameter 'SCP_DATA' can be used to pass additional kernel cmdline
parameters to a stand-alone SCSI/NVMe/ECKD dumper for debugging purposes.

Configuration example
=====================

ON_PANIC=dump_reipl
DUMP_TYPE=fcp
DEVICE=0.0.4711
WWPN=0x5005076303004711
LUN=0x4711000000000000
BOOTPROG=0
BR_LBA=0
SCP_DATA="dump_debug=6 ignore_loglevel earlyprintk=sclp panic_print=3"

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Alexander Egorenkov
7ea0dfdc17 dumpconf: fix whitespace in sysconfig example for ECKD dump device
Make it conform with every other example.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Alexander Egorenkov
2d3aac1241 dumpconf: fix coding style of CheckDeviceString()
Make it conform with the naming style used for every other function in
this script.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Mikhail Zaslonko
c7fd515790 zdump: Fix 'zgetdump -i' ioctl error on s390 formatted dump file
When dump is copied to the filesystem in s390 format, follow on
'zgetdump -i' can fail with ioctl error:

  # zgetdump /dev/dasdb1 -f s390 dump.s390
  Format Info:
      Source: s390_ext
      Target: s390

  Copying dump:
      00000001 / 00008192 MB
      00003688 / 00008192 MB
      00006646 / 00008192 MB
      00008192 / 00008192 MB
  Success: Dump has been copied

  # zgetdump -iVVVV dump.s390

  zgetdump: Operation "BLKSSZGET" failed on "dump.s390" (Inappropriate ioctl for device)

Call ioctl(BLKSSZGET) only for s390_ext dump format (dump can be
stored on DASD partition only, not on the filesystem). For s390 format
a blocksize is not required for dump processing since s390 dump data is
not compressed.

Fixes: 271b809495 ("zdump/dfi_s390: Support reading compressed s390_ext dumps")
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Steffen Eiden
7a4ec55d77 rust/pvattest: Add short option for --arpk
pvattest-C had a -a option for --arpk which the Rust implementation
missed.
Add this short option.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Marc Hartmayer
63ff07ba38 Revert "zipl/src: Fix problems when target parameters are specified by user"
The commit fb0b6263d1 ("zipl/src: Fix problems when target parameters
are specified by user") breaks the case where the user has to provide
all target attributes via the zipl command line, because the target
device cannot be used to retrieve those attributes.

$ zipl -V --blsdir /tmp/tmp.xHmFUdgBCi/boot//loader/entries/ --config /tmp/tmp.dSv9MJ3svs
Looking for components in '/lib/s390-tools'
Using config file '/tmp/tmp.dSv9MJ3svs' (from command line)
Using BLS config file '/tmp/tmp.xHmFUdgBCi/boot//loader/entries//50_normal.conf'
Using BLS config file '/tmp/tmp.xHmFUdgBCi/boot//loader/entries//45_normal_swiotlb.conf'
Using BLS config file '/tmp/tmp.xHmFUdgBCi/boot//loader/entries//40_pv.conf'
Using BLS config file '/tmp/tmp.xHmFUdgBCi/boot//loader/entries//30_pv_reboot.conf'
Secure boot support: yes
Target device information
  Device..........................: 2b:00
  Device name.....................: nbd0 *)
  Device driver name..............: nbd
  Type............................: disk device
  Disk layout.....................: SCSI disk layout *)
  Geometry - start................: 2048 *)
  File system block size..........: 4096
  Physical block size.............: 512 *)
  Device size in physical blocks..: 2095071
  *) Data provided by user.
Building bootmap in '/tmp/tmp.xHmFUdgBCi/boot/'
Building menu 'zipl-automatic-menu'
Adding #1: IPL section 'Normal Guest' (default)
  initial ramdisk...: /tmp/tmp.xHmFUdgBCi/boot//ramdisk-s390x
  kernel image......: /tmp/tmp.xHmFUdgBCi/boot//vmlinux-s390x
zIPL environment block content:
Error: Could not add image file '/tmp/tmp.xHmFUdgBCi/boot//vmlinux-s390x': Could not get disk geometry

This reverts commit fb0b6263d1.

Acked-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Frank Heimes
26d7eed0aa zfcpdump: Do not save timestamps when compressing
Having timestamps in gzip leads to lintian warning
'package-contains-timestamped-gzip' and will harm reproducible builds.
Gzip option '-n' avoids saving original file name and especially timestamps
by default.

Fixes: https://github.com/ibm-s390-linux/s390-tools/pull/169
Signed-off-by: Frank Heimes <frank.heimes@canonical.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
[seiden@linux.ibm.com: Fix commit message]
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:13 +02:00
Frank Heimes
e0034eddbf s390-tools: Fix typos in code and man page files
Fix typos reported by (Debian) lintian.

Closes: https://github.com/ibm-s390-linux/s390-tools/pull/168
Signed-off-by: Frank Heimes <frank.heimes@canonical.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:09 +02:00
Jan Höppner
0e3034c0f6 Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-05-28 08:26:36 +02:00
Jan Höppner
686262fdcd New release s390-tools-2.33.1
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-05-28 08:26:36 +02:00
Jan Höppner
2379fd8a58 s390-tools: Fix release string
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-05-28 08:26:36 +02:00
Jan Höppner
3552a27ae6 s390-tools: Fix README.md
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-05-28 08:26:36 +02:00
Steffen Eiden
39106ba760 Prepare for next release
Signed-off by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 17:54:42 +02:00
101 changed files with 3244 additions and 1108 deletions

2
.gitignore vendored
View File

@@ -124,9 +124,11 @@ zipl/boot/*.exec
zipl/boot/.loaders
zipl/boot/data.h
zipl/src/chreipl_helper.device-mapper
zipl/src/chreipl_helper.md
zipl/src/zipl
zipl/src/zipl-editenv
zipl/src/zipl_helper.device-mapper
zipl/src/zipl_helper.md
zkey/check-dep-zkey
zkey/check-dep-zkey-cryptsetup
zkey/detect-libcryptsetup.dep

View File

@@ -5,8 +5,9 @@ newline_style = "Unix"
# when they become stable.
#
# They are kept here since they are useful to run from time to time.
#format_code_in_doc_comments = true
#reorder_impl_items = true
#comment_width = 100
#wrap_comments = true
#format_code_in_doc_comments = true
#group_imports = "StdExternalCrate"
#normalize_comments = true
#reorder_impl_items = true
#wrap_comments = true

View File

@@ -1,6 +1,54 @@
Release history for s390-tools (MIT version)
--------------------------------------------
* __v2.35.0 (2024-10-01)__
For Linux kernel version: 6.11
Add new tools / libraries:
Changes of existing tools:
- cpacfstats: Add support for FULL XTS (MSA 10) and HMAC (MSA 11) PAI counter
- cpuplugd: Make cpuplugd compatible with hiperdispatch
- dbginfo.sh: Add network sockstat info
- pvapconfig: s390x exclusive build
- zdev: Add option to select IPL device
- zdump/dfo_s390: Support s390 DFO for vr-kernel dumps
- zipl: Add support of mirror devices
Bug Fixes:
- (genprotimg|zipl)/boot: discard .note.package ELF section to save memory
- netboot/mk-s390image: Fix size when argument is a symlink
- ziorep_config: Fix warning message when multipath device is not there.
- zipl: Fix problems when target parameters are specified by user
- zipl: Fix segfault when creating device-based dumps with '--dry-run'
* __v2.34.0 (2024-08-01)__
For Linux kernel version: 6.10
Changes of existing tools:
- ap_tools/ap-check: Add support for vfio-ap dynamic configuration
- dbginfo.sh: Update/Add additional DASD data collection
- dumpconf: Add new parameter 'SCP_DATA' for SCSI/NVMe/ECKD dump devices
- libutil: Make formatted meta-data configurable
- s390-tools: Replace 'which' with built-in 'command -v'
- zdump/dfi_elf: Support core dumps of vr-kernels
Bug Fixes:
- chzdev: Fix warning about failed ATTR writes by udev
- rust/pv: Try again if first CRL-URI is invalid
- rust/pvattest: Add short option for --arpk
- zdump: Fix 'zgetdump -i' ioctl error on s390 formatted dump file
* __v2.33.1 (2024-05-28)__
For Linux kernel version: 6.9
Bug Fixes:
- s390-tools: Fix formatting and typos in README.md
- s390-tools: Fix release string
* __v2.33.0 (2024-05-27)__
For Linux kernel version: 6.9

View File

@@ -1,4 +1,4 @@
3t90-tools
s390-tools
==========
The s390-tools package contains the source tree of a set of user space
@@ -44,7 +44,7 @@ Package contents
* genprotimg:
Create a protected virtualization image.
* udev rules:
* udev rules:
- 59-dasd.rules: rules for unique DASD device nodes created in /dev/disk/.
- 57-osasnmpd.rules: udev rules for osasnmpd.
- 60-readahead.rules: udev rules to set increased "default max readahead".

View File

@@ -15,6 +15,7 @@
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <json-c/json.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
@@ -27,21 +28,33 @@
#include "ap-check.h"
/* The supported mdevctl callout version */
#define MDEVCTL_CAP_VERSION 2
static const struct mdevctl_action mdevctl_action_table[NUM_MDEVCTL_ACTIONS] = {
{MDEVCTL_ACTION_DEFINE, "define"},
{MDEVCTL_ACTION_LIST, "list"},
{MDEVCTL_ACTION_MODIFY, "modify"},
{MDEVCTL_ACTION_START, "start"},
{MDEVCTL_ACTION_STOP, "stop"},
{MDEVCTL_ACTION_TYPES, "types"},
{MDEVCTL_ACTION_UNDEFINE, "undefine"},
{MDEVCTL_ACTION_ATTRIBUTES, "attributes"}
{MDEVCTL_ACTION_ATTRIBUTES, "attributes"},
{MDEVCTL_ACTION_CAPABILITIES, "capabilities"}
/*
* Note: the following actions are known to exist but currently ignored:
* {MDEVCTL_ACTION_LIST, "list"},
* {MDEVCTL_ACTION_TYPES, "types"}
*/
};
static const struct mdevctl_event mdevctl_event_table[NUM_MDEVCTL_EVENTS] = {
{MDEVCTL_EVENT_PRE, "pre"},
{MDEVCTL_EVENT_POST, "post"},
{MDEVCTL_EVENT_GET, "get"}
{MDEVCTL_EVENT_GET, "get"},
{MDEVCTL_EVENT_LIVE, "live"}
/*
* Note: the following events are known to exist but currently ignored:
* {MDEVCTL_EVENT_NOTIFY, "notify"},
*/
};
/*
@@ -596,6 +609,94 @@ out:
return rc;
}
static int ap_check_active(struct ap_check_anchor *anc)
{
int rc, rc2;
/* Ensure device with control domains also has usage domains */
if (util_list_is_empty(anc->dev->domains) &&
!util_list_is_empty(anc->dev->controls)) {
fprintf(stderr, "At least one usage domain must be specified\n");
return -1;
}
/* Check against all other active vfio-ap devices */
rc = check_other_mdevs_sysfs(anc);
/* Check against the system sysfs values for apmask/aqmask */
rc2 = check_sysfs_mask_conflicts(anc);
/* If either hit an error, reflect this */
rc = rc != 0 ? rc : rc2;
return rc;
}
static int ap_do_dynamic_config(struct ap_check_anchor *anc)
{
char *adapters, *domains, *controls, *path, *attr;
int asize, dsize, csize, size;
int rc = 0;
FILE *f;
adapters = vfio_ap_device_get_adapter_mask(anc->dev, &asize);
domains = vfio_ap_device_get_domain_mask(anc->dev, &dsize);
controls = vfio_ap_device_get_control_mask(anc->dev, &csize);
if (!adapters || !domains || !controls) {
fprintf(stderr, "Failed to read device config\n");
rc = -1;
goto out;
}
/*
* The 'ap_config' command takes a comma-delimited list of the 3 masks
* combined. Each mask size includes a terminating character, two of
* which will be replaced by commas and the final replaced by a
* newline, which ap_config seems to require at the end of the input.
* Add one to ensure room for a null termination.
*/
size = asize + dsize + csize + 1;
attr = util_zalloc(size);
/* Use the 3 masks to generate a 'ap_config' command */
rc = snprintf(attr, size, "%s,%s,%s\n", adapters, domains, controls);
if (rc < size - 1) {
fprintf(stderr, "Error creating ap_config command\n");
rc = -1;
goto out;
}
/* Apply the new configuration to the active device */
path = path_get_vfio_ap_attr(anc->uuid, "ap_config");
f = fopen(path, "w");
if (!f) {
fprintf(stderr, "Error opening ap_config\n");
rc = -1;
goto out;
}
rc = fputs(attr, f);
fclose(f);
if (rc == EOF)
fprintf(stderr, "Error writing to ap_config\n");
else
rc = 0;
out:
if (!adapters)
free(adapters);
if (!domains)
free(domains);
if (!controls)
free(controls);
if (!path)
free(path);
if (!attr)
free(attr);
return rc;
}
/*
* Determine if defining the specified device is a valid operation.
* mdevctl can reach us for a DEFINE under the following circumstances:
@@ -647,6 +748,50 @@ static int ap_check_handle_modify(struct ap_check_anchor *anc)
return ap_check_changes(anc);
}
/*
* Determine if modifying the active device is a valid operation.
* This is similar to STARTing a device, in that the requested modifications
* cannot conflict with the active configuration. LIVE MODIFY can only be
* handled if the ap_config attribute is available in the vfio-ap driver.
*/
static int ap_check_handle_live_modify(struct ap_check_anchor *anc)
{
int rc;
rc = ap_get_lock_callout();
if (rc) {
fprintf(stderr, "Failed to acquire configuration lock %d\n",
rc);
return -1;
}
anc->cleanup_lock = true;
if (vfio_ap_read_device_config(NULL, anc->dev) != 0) {
fprintf(stderr, "Failed to read device config\n");
return -1;
}
if (strcmp(anc->dev->type, anc->type) != 0) {
fprintf(stderr, "Invalid mdev_type: %s\n", anc->dev->type);
return -1;
}
if (!vfio_ap_need_dynamic_config(anc->dev)) {
fprintf(stderr, "vfio-ap module does not support ap_config for live modification");
return -1;
}
/* Check if the new configuration would cause conflicts */
rc = ap_check_active(anc);
if (rc)
return rc;
/* Attempt to perform the dynamic configuration */
rc = ap_do_dynamic_config(anc);
return rc;
}
/*
* Determine if starting the specified device is a valid operation.
* mdevctl can reach us for a START under the following circumstances:
@@ -665,7 +810,7 @@ static int ap_check_handle_modify(struct ap_check_anchor *anc)
*/
static int ap_check_handle_start(struct ap_check_anchor *anc)
{
int rc = 0, rc2;
int rc = 0;
/* Can only start a device if vfio_ap is built-in or loaded */
if (!util_path_is_dir(VFIO_AP_PATH)) {
@@ -694,20 +839,7 @@ static int ap_check_handle_start(struct ap_check_anchor *anc)
goto out;
}
/* Ensure device with control domains also has usage domains */
if (util_list_is_empty(anc->dev->domains) &&
!util_list_is_empty(anc->dev->controls)) {
fprintf(stderr, "At least one usage domain must be specified\n");
rc = -1;
goto out;
}
/* Check against all other active vfio-ap devices */
rc = check_other_mdevs_sysfs(anc);
/* Check against the system sysfs values for apmask/aqmask */
rc2 = check_sysfs_mask_conflicts(anc);
/* If either hit an error, reflect this */
rc = rc != 0 ? rc : rc2;
rc = ap_check_active(anc);
/* If successful, lock must remain held until post callout */
if (rc == 0)
@@ -886,6 +1018,122 @@ static int ap_check_handle_get_attributes(struct ap_check_anchor *anc)
return 0;
}
/*
* If the target 'attr' is in the 's' array, add it to the 't' array.
*/
static void json_add_attr(json_object *t, json_object *s, const char *attr)
{
size_t vlen, alen = strlen(attr);
const char *val;
json_object *o;
int i, num;
num = json_object_array_length(s);
for (i = 0; i < num; i++) {
o = json_object_array_get_idx(s, i);
val = json_object_get_string(o);
vlen = strlen(val);
if (alen == vlen && strncasecmp(attr, val, alen) == 0) {
json_object_array_add(t, json_object_new_string(val));
return;
}
}
}
/*
* Generate a JSON-formatted list of capability information that this script
* supports and return it to the caller via stdout. An example of what the
* output should look like (without the newlines):
* {
* "supports": {
* "version": 2,
* "actions": ["define",
* "modify",
* "start",
* "stop",
* "undefine",
* "attributes",
* "capabilities"],
* "events": ["pre",
* "post",
* "get",
* "live"]
* }
* }
*/
static int ap_check_handle_get_capabilities(void)
{
json_object *root, *csup, *cver, *cact, *cev, *cap, *caps, *o;
int i, rc = 0;
root = json_object_from_fd(STDIN_FILENO);
if (!root) {
fprintf(stderr, "No capabilities provided\n");
return -1;
}
if (!json_object_object_get_ex(root, "provides", &csup)) {
fprintf(stderr, "No supported capabilities provided\n");
rc = -1;
goto out;
}
if (!json_object_object_get_ex(csup, "version", &cver)) {
fprintf(stderr, "No version provided in capabilities\n");
rc = -1;
goto out;
}
if (!json_object_object_get_ex(csup, "actions", &cact)) {
fprintf(stderr, "No actions provided in capabilities\n");
rc = -1;
goto out;
}
if (!json_object_object_get_ex(csup, "events", &cev)) {
fprintf(stderr, "No events provided in capabilities\n");
rc = -1;
goto out;
}
/*
* Advertise the subset of supported capabilities from the list
* provided on stdin.
*/
cap = json_object_new_object();
caps = json_object_new_object();
json_object_object_add(cap, "supports", caps);
/*
* Currently we always advertise a fixed version, but we may need to
* revisit this if we increase MDEVCTL_CAP_VERSION in the future (e.g.
* how to handle ap-check having a greater supported version than
* what mdevctl reports)
*/
o = json_object_new_int(MDEVCTL_CAP_VERSION);
json_object_object_add(caps, "version", o);
o = json_object_new_array();
for (i = 0; i < NUM_MDEVCTL_ACTIONS; i++)
json_add_attr(o, cact, mdevctl_action_table[i].action);
json_object_object_add(caps, "actions", o);
o = json_object_new_array();
for (i = 0; i < NUM_MDEVCTL_EVENTS; i++)
json_add_attr(o, cev, mdevctl_event_table[i].event);
json_object_object_add(caps, "events", o);
/* Return supported capabilities JSON on stdout */
printf("%s\n", json_object_to_json_string(cap));
json_object_put(cap);
out:
json_object_put(root);
return rc;
}
/*
* Determine which mdevctl action is being checked and handle accordingly.
*/
@@ -911,8 +1159,6 @@ static int ap_check_handle_action(struct ap_check_anchor *anc)
case MDEVCTL_ACTION_UNDEFINE:
rc = ap_check_handle_undefine(anc);
break;
case MDEVCTL_ACTION_LIST:
case MDEVCTL_ACTION_TYPES:
default:
/* Ignore some actions including unknown ones */
break;
@@ -937,6 +1183,19 @@ static int ap_check_handle_action(struct ap_check_anchor *anc)
case MDEVCTL_ACTION_ATTRIBUTES:
rc = ap_check_handle_get_attributes(anc);
break;
case MDEVCTL_ACTION_CAPABILITIES:
rc = ap_check_handle_get_capabilities();
break;
default:
/* Ignore some actions including unknown ones */
break;
}
break;
case MDEVCTL_EVENT_LIVE:
switch (anc->action) {
case MDEVCTL_ACTION_MODIFY:
rc = ap_check_handle_live_modify(anc);
break;
default:
/* Ignore some actions including unknown ones */
break;

View File

@@ -24,6 +24,7 @@ enum mdevctl_action_id {
MDEVCTL_ACTION_TYPES,
MDEVCTL_ACTION_UNDEFINE,
MDEVCTL_ACTION_ATTRIBUTES,
MDEVCTL_ACTION_CAPABILITIES,
/* UNKNOWN must always be the last in the list */
MDEVCTL_ACTION_UNKNOWN,
};
@@ -38,6 +39,7 @@ enum mdevctl_event_id {
MDEVCTL_EVENT_PRE = 0,
MDEVCTL_EVENT_POST,
MDEVCTL_EVENT_GET,
MDEVCTL_EVENT_LIVE,
MDEVCTL_EVENT_UNKNOWN,
};
#define NUM_MDEVCTL_EVENTS MDEVCTL_EVENT_UNKNOWN

View File

@@ -951,7 +951,7 @@ static void set_record_extension(struct file *f, int *record, off_t addr,
if (f->record_scan_state != RSS_DATA_BLOCK_STARTED &&
f->record_scan_state != RSS_DATA_BLOCK_EXT)
DIE("%s: interal error\n", __func__);
DIE("%s: internal error\n", __func__);
BUG(*record >= f->fst->nr_records);

View File

@@ -32,7 +32,7 @@ endif
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
VERSION := 2
RELEASE := 32
RELEASE := 35
PATCHLEVEL := 0
DISTRELEASE := build-$(shell date +%Y%m%d)
S390_TOOLS_RELEASE := $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)

View File

@@ -23,7 +23,7 @@
* Number of PAI counters. Contains all counters regardless of kernel or user
* space
*/
#define MAX_NUM_PAI 156
#define MAX_NUM_PAI 172
/*
* This is the sysfs directory from which cpacfstatsd daemon application loads

View File

@@ -192,7 +192,27 @@ const struct pai_counter pai[] = {
[152] = {"PCKMO ECC Ed25519", KERNEL_ONLY_COUNTER},
[153] = {"PCKMO ECC Ed448", KERNEL_ONLY_COUNTER},
[154] = {"Reserved 1", KERNEL_ONLY_COUNTER},
[155] = {"Reserved 2", KERNEL_ONLY_COUNTER}
[155] = {"Reserved 2", KERNEL_ONLY_COUNTER},
[156] = {"KM AES-XTS (full) 128bit", KERNEL_AND_USER_COUNTER},
[157] = {"KM AES-XTS (full) 256bit", KERNEL_AND_USER_COUNTER},
[158] = {"KM AES-XTS (full) 128bit protected key",
KERNEL_AND_USER_COUNTER},
[159] = {"KM AES-XTS (full) 256bit protected key",
KERNEL_AND_USER_COUNTER},
[160] = {"KMAC HMAC SHA 224", KERNEL_AND_USER_COUNTER},
[161] = {"KMAC HMAC SHA 256", KERNEL_AND_USER_COUNTER},
[162] = {"KMAC HMAC SHA 384", KERNEL_AND_USER_COUNTER},
[163] = {"KMAC HMAC SHA 512", KERNEL_AND_USER_COUNTER},
[164] = {"KMAC HMAC SHA 224 protected key", KERNEL_AND_USER_COUNTER},
[165] = {"KMAC HMAC SHA 256 protected key", KERNEL_AND_USER_COUNTER},
[166] = {"KMAC HMAC SHA 384 protected key", KERNEL_AND_USER_COUNTER},
[167] = {"KMAC HMAC SHA 512 protected key", KERNEL_AND_USER_COUNTER},
[168] = {"PCKMO HMAC 512 protected key", KERNEL_ONLY_COUNTER},
[169] = {"PCKMO HMAC 1024 protected key", KERNEL_ONLY_COUNTER},
[170] = {"PCKMO AES-XTS 128bit double key protected key",
KERNEL_ONLY_COUNTER},
[171] = {"PCKMO AES-XTS 256bit double key protected key",
KERNEL_ONLY_COUNTER}
};
/*

View File

@@ -39,7 +39,8 @@ static volatile int stopsig;
*/
static const unsigned int pai_idx[] = {
// KM
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 156, 157, 158,
159,
// KMC
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
// KMA
@@ -55,7 +56,8 @@ static const unsigned int pai_idx[] = {
// KLMD
81, 82, 83, 84, 85, 86, 87, 88, 89,
// KMAC
90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101,
90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 160, 161, 162, 163,
164, 165, 166, 167,
// PCC
102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
@@ -65,7 +67,7 @@ static const unsigned int pai_idx[] = {
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
140, 141, 142,
// PCKMO
143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153,
143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 168, 169, 170, 171,
// Reserved
154, 155
};
@@ -108,7 +110,6 @@ static int recv_query(int s, enum ctr_e *ctr, enum cmd_e *cmd)
return rc;
}
static int send_answer(int s, int ctr, int state, uint64_t value)
{
struct msg m;
@@ -124,7 +125,6 @@ static int send_answer(int s, int ctr, int state, uint64_t value)
return send_msg(s, &m, DEFAULT_SEND_TIMEOUT);
}
/*
* Print according to protocol for PAI:
* - first the state and the number of PAI counters that follow
@@ -160,7 +160,6 @@ static int do_send_pai(int s, int user, unsigned int *counter)
return rc;
}
static int do_enable(int s, enum ctr_e ctr, unsigned int *supported_counters)
{
uint64_t value = 0;
@@ -201,7 +200,6 @@ static int do_enable(int s, enum ctr_e ctr, unsigned int *supported_counters)
return rc;
}
static int do_disable(int s, enum ctr_e ctr, unsigned int *supported_counters)
{
int i, rc = 0;
@@ -228,7 +226,6 @@ static int do_disable(int s, enum ctr_e ctr, unsigned int *supported_counters)
return rc;
}
static int do_reset(int s, enum ctr_e ctr, unsigned int *supported_counters)
{
int i, rc = 0, state;
@@ -260,7 +257,6 @@ static int do_reset(int s, enum ctr_e ctr, unsigned int *supported_counters)
return rc;
}
static int do_print(int s, enum ctr_e ctr, unsigned int *supported_counters)
{
int i, rc = 0, state;
@@ -292,7 +288,6 @@ static int do_print(int s, enum ctr_e ctr, unsigned int *supported_counters)
return rc;
}
static int become_daemon(int *startup_pipe)
{
int child_initialized = 0, fd;
@@ -385,7 +380,6 @@ static int become_daemon(int *startup_pipe)
return 0;
}
static void remove_sock(void)
{
remove(SOCKET_FILE);
@@ -447,14 +441,12 @@ static void remove_pidfile(void)
remove(PID_FILE);
}
void signalhandler(int sig)
{
perf_stop();
stopsig = sig;
}
int eprint(const char *format, ...)
{
char buf[512];
@@ -476,7 +468,6 @@ int eprint(const char *format, ...)
return n;
}
/*
* returns -1 on error
* returns X where X is the found counters in dir

View File

@@ -4,9 +4,11 @@ all: cpuplugd
LDLIBS += -lm
libs = $(rootdir)/libutil/libutil.a
OBJECTS = daemon.o cpu.o info.o terms.o config.o main.o getopt.o mem.o
cpuplugd: $(OBJECTS)
cpuplugd: $(OBJECTS) $(libs)
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
clean:

View File

@@ -204,6 +204,45 @@ void parse_configfile(char *file)
fclose(filp);
}
void apply_cpu_config(void)
{
/*
* Check that the initial number of cpus is not below the
* minimum
*/
if (num_cpu_start < cfg.cpu_min &&
get_numcpus() >= cfg.cpu_min) {
cpuplugd_debug("The number of online cpus is below ");
cpuplugd_debug("the minimum and will be increased.\n");
while (get_num_online_cpus() < cfg.cpu_min) {
if (hotplug_one_cpu())
break;
}
}
if (get_num_online_cpus() > cfg.cpu_max) {
cpuplugd_debug("The number of online cpus is above the maximum");
cpuplugd_debug(" and will be decreased.\n");
while (get_num_online_cpus() > cfg.cpu_max) {
if (hotunplug_one_cpu())
break;
}
}
if (cfg.cpu_min > get_numcpus()) {
/*
* This check only works if nobody used the
* additional_cpus in the boot parameter section
*/
cpuplugd_debug("The minimum amount of cpus is above the ");
cpuplugd_debug("number of available cpus.\n");
cpuplugd_exit("Detected %d available cpus\n", get_numcpus());
}
if (get_num_online_cpus() < cfg.cpu_min) {
cpuplugd_debug("Failed to set the number of online cpus to ");
cpuplugd_debug("the minimum. ");
cpuplugd_exit("Aborting.\n");
}
}
/*
* Check if the required settings are found in the configuration file.
* "Autodetect" if cpu and/or memory hotplug configuration entries
@@ -211,7 +250,6 @@ void parse_configfile(char *file)
*/
void check_config()
{
int cpuid;
int lpar_status;
lpar_status = check_lpar();
@@ -262,60 +300,23 @@ void check_config()
/*
* Save the number of online cpus and the cmm_pagesize at startup,
* so that we can enable exactly the same amount when the daemon ends
*
* Don't adjust cpus if system is on vertical polarization
*/
if (cpu) {
num_cpu_start = get_num_online_cpus();
cpuplugd_debug("Daemon started with %d active cpus.\n",
num_cpu_start);
/*
* Check that the initial number of cpus is not below the
* minimum
*/
if (num_cpu_start < cfg.cpu_min &&
get_numcpus() >= cfg.cpu_min) {
cpuplugd_debug("The number of online cpus is below "
"the minimum and will be increased.\n");
cpuid = 0;
while (get_num_online_cpus() < cfg.cpu_min &&
cpuid < get_numcpus()) {
if (is_online(cpuid) == 1) {
cpuid++;
continue;
}
cpuplugd_debug("cpu with id %d is currently offline "
"and will be enabled\n", cpuid);
hotplug(cpuid);
cpuid++;
}
}
if (get_num_online_cpus() > cfg.cpu_max) {
cpuplugd_debug("The number of online cpus is above the maximum"
" and will be decreased.\n");
cpuid = 0;
while (get_num_online_cpus() > cfg.cpu_max &&
cpuid < get_numcpus()) {
if (is_online(cpuid) != 1) {
cpuid++;
continue;
}
cpuplugd_debug("cpu with id %d is currently online "
"and will be disabled\n", cpuid);
hotunplug(cpuid);
cpuid++;
}
}
if (cfg.cpu_min > get_numcpus())
/*
* This check only works if nobody used the
* additional_cpus in the boot parameter section
*/
cpuplugd_exit("The minimum amount of cpus is above "
"the number of available cpus.\n"
"Detected %d available cpus\n",
get_numcpus());
if (get_num_online_cpus() < cfg.cpu_min)
cpuplugd_exit("Failed to set the number of online "
"cpus to the minimum. Aborting.\n");
saved_polarization = get_polarization();
num_cpu_start = get_num_online_cpus();
cpuplugd_debug("Daemon started with %d active cpus.\n",
num_cpu_start);
if (saved_polarization < 0) {
cpuplugd_debug("Daemon couldn't determine system polarization\n");
cpuplugd_debug("Starting without evaluating cpu rules\n");
} else if (saved_polarization == PLR_VERTICAL) {
cpuplugd_debug("Daemon started with vertical polarization.\n");
cpuplugd_debug("Cpu adjustments won't be made until system ");
cpuplugd_debug("is in horizontal polarization\n");
} else if (saved_polarization == PLR_HORIZONTAL &&
cpu == 1) {
apply_cpu_config();
}
if (memory == 1) {
/*

View File

@@ -12,217 +12,241 @@
#include <limits.h>
#include "cpuplugd.h"
#define NUM_BASE (10)
#define CPU_OFFLINE (0)
#define CPU_ONLINE (1)
#define CPU_DECONFIGURED (0)
#define CPU_CONFIGURED (1)
#define CPU_LIST_LEN (4096)
/*
* Return overall number of available cpus. This does not necessarily
* mean that those are currently online
*/
int get_numcpus()
static int get_sysfs_attribute_cpu_count(char *path)
{
int i;
char path[PATH_MAX];
int number = 0;
char cpu_list[CPU_LIST_LEN];
int number, start, end;
char *sub_list;
for (i = 0; ; i++) {
/* check whether file exists and is readable */
sprintf(path, "/sys/devices/system/cpu/cpu%d", i);
if (access(path, R_OK) == 0)
if (util_file_read_line(cpu_list, sizeof(cpu_list), path))
cpuplugd_exit("Cannot open %s file: %s\n", path, strerror(errno));
number = 0;
sub_list = strtok(cpu_list, ",");
while (sub_list) {
if (strchr(sub_list, '-')) {
if (sscanf(sub_list, "%d-%d", &start, &end) != 2)
cpuplugd_exit("Malformed content of %s: %s\n", path, sub_list);
number += (end - start) + 1;
} else {
number++;
else
break;
}
sub_list = strtok(NULL, ",");
}
return number;
}
/*
* Return number of online cpus
* get_numcpus() - return number of present cpus by sysfs'
* cpu/present attribute.
* This number represents the total number of usable cpus,
* this includes offline or deconfigured cpus as well.
*/
int get_num_online_cpus()
int get_numcpus(void)
{
FILE *filp;
int i;
char path[PATH_MAX];
int status = 0;
int value_of_onlinefile, rc;
int number;
char *path;
for (i = 0; i < get_numcpus(); i++) {
/* check wether file exists and is readable */
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", i);
if (access(path, R_OK) != 0) {
status++;
continue;
}
filp = fopen(path, "r");
if (!filp)
cpuplugd_exit("Cannot open cpu online file: "
"%s\n", strerror(errno));
else {
rc = fscanf(filp, "%d", &value_of_onlinefile);
if (rc != 1)
cpuplugd_exit("Cannot read cpu online file: "
"%s\n", strerror(errno));
if (value_of_onlinefile == 1)
status++;
}
fclose(filp);
path = util_path_sysfs("devices/system/cpu/present");
number = get_sysfs_attribute_cpu_count(path);
free(path);
if (number <= 0)
cpuplugd_exit("number of present cpus (%d) <= 0\n", number);
return number;
}
/*
* get_num_online_cpus() - return number of online cpus
* by parsing sysfs cpu/online attribute
*/
int get_num_online_cpus(void)
{
int number;
char *path;
path = util_path_sysfs("devices/system/cpu/online");
number = get_sysfs_attribute_cpu_count(path);
free(path);
if (number <= 0)
cpuplugd_exit("number of online cpus (%d) <= 0\n", number);
return number;
}
/*
* get_polarization() - return system polarization
*/
int get_polarization(void)
{
int polarization;
char *path;
path = util_path_sysfs("devices/system/cpu/dispatching");
if (util_file_read_i(&polarization, NUM_BASE, path) < 0) {
polarization = -1;
cpuplugd_debug("failed to read system polarization\n");
}
free(path);
return polarization;
}
/*
* is_cpu_hotpluggable() - check if cpuhotplug operations are supported
* for the given cpu.
*/
static int is_cpu_hotpluggable(int cpuid)
{
char *path;
int rc;
path = util_path_sysfs("devices/system/cpu/cpu%d/online", cpuid);
rc = util_path_exists(path);
free(path);
return rc;
}
/*
* hotplug() - perform cpu hotplug on given cpuid
*/
static int hotplug(int cpuid)
{
char *path;
int rc;
path = util_path_sysfs("devices/system/cpu/cpu%d/online", cpuid);
rc = util_file_write_l(CPU_ONLINE, NUM_BASE, path);
if (rc < 0)
cpuplugd_debug("failed to enable cpu with id %d\n", cpuid);
free(path);
return rc;
}
/*
* hotunplug() - perform cpu hotunplug on given cpuid
*/
static int hotunplug(int cpuid)
{
char *path;
int rc;
path = util_path_sysfs("devices/system/cpu/cpu%d/online", cpuid);
rc = util_file_write_l(CPU_OFFLINE, NUM_BASE, path);
if (rc < 0)
cpuplugd_debug("failed to disable cpu with id %d\n", cpuid);
free(path);
return rc;
}
/*
* get_cpu_attribute() - get a certain cpu's selected attribute
*/
static int get_cpu_attribute(int cpuid, char *attribute)
{
int status;
char *path;
path = util_path_sysfs("devices/system/cpu/cpu%d/%s", cpuid, attribute);
if (util_file_read_i(&status, NUM_BASE, path) < 0) {
status = -1;
cpuplugd_debug("failed to read %s status of cpu with id %d\n", attribute, cpuid);
}
free(path);
return status;
}
/*
* Enable a certain cpu
* hotplug_one_cpu() - perform hotplugging on the first available cpu
*/
int hotplug(int cpuid)
int hotplug_one_cpu(void)
{
FILE *filp;
char path[PATH_MAX];
int status, rc;
struct dirent **cpu_dir;
int cpuid, count, i, rc;
char *path;
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpuid);
if (access(path, W_OK) == 0) {
filp = fopen(path, "w");
if (!filp)
cpuplugd_exit("Cannot open cpu online file: %s\n",
strerror(errno));
fprintf(filp, "1");
fclose(filp);
/*
* check if the attempt to enable the cpus really worked
*/
filp = fopen(path, "r");
rc = fscanf(filp, "%d", &status);
if (rc != 1)
cpuplugd_exit("Cannot open cpu online file: %s\n",
strerror(errno));
fclose(filp);
if (status == 1) {
cpuplugd_debug("cpu with id %d enabled\n", cpuid);
return 1;
} else {
cpuplugd_debug("failed to enable cpu with id %d\n",
cpuid);
return -1;
rc = -1;
path = util_path_sysfs("devices/system/cpu/");
count = util_scandir(&cpu_dir, alphasort, path, "cpu[0-9]*");
for (i = 0; (i < count) && (rc != 0); i++) {
if (sscanf(cpu_dir[i]->d_name, "cpu%d", &cpuid) != 1)
cpuplugd_exit("Malformed content of %s: %s\n", path, cpu_dir[i]->d_name);
if (!is_cpu_hotpluggable(cpuid))
continue;
if (get_cpu_attribute(cpuid, "configure") == CPU_CONFIGURED &&
get_cpu_attribute(cpuid, "online") == CPU_OFFLINE) {
cpuplugd_debug("cpu%d will be enabled", cpuid);
rc = hotplug(cpuid);
}
}
cpuplugd_debug("cpu with id %d cannot be hotplugged\n", cpuid);
return -1;
util_scandir_free(cpu_dir, count);
free(path);
return rc;
}
/*
* Disable a certain cpu
* hotunplug_one_cpu() - perform hotunplugging on the first available cpu
*/
int hotunplug(int cpuid)
int hotunplug_one_cpu(void)
{
FILE *filp;
int state, rc;
int retval = -1;
char path[PATH_MAX];
struct dirent **cpu_dir;
int cpuid, count, i, rc;
char *path;
state = -1;
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpuid);
if (access(path, W_OK) == 0) {
filp = fopen(path, "w");
fprintf(filp, "0");
fclose(filp);
/*
* Check if the attempt to enable the cpus really worked
*/
filp = fopen(path, "r");
rc = fscanf(filp, "%d", &state);
if (rc != 1)
cpuplugd_error("Failed to disable cpu with id %d\n",
cpuid);
fclose(filp);
if (state == 0)
return 1;
}
cpuplugd_debug("cpu with id %d cannot be hotunplugged\n", cpuid);
return retval;
}
/*
* Check if a certain cpu is currently online
*/
int is_online(int cpuid)
{
FILE *filp;
int state;
int retval, rc;
char path[PATH_MAX];
retval = -1;
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpuid);
if (access(path, R_OK) == 0) {
filp = fopen(path, "r");
rc = fscanf(filp, "%d", &state);
if (rc == 1) {
if (state == 1)
retval = 1;
if (state == 0)
retval = 0;
rc = -1;
path = util_path_sysfs("devices/system/cpu/");
count = util_scandir(&cpu_dir, alphasort, path, "cpu[0-9]*");
for (i = 0; (i < count) && (rc != 0); i++) {
if (sscanf(cpu_dir[i]->d_name, "cpu%d", &cpuid) != 1)
cpuplugd_exit("Malformed content of %s: %s\n", path, cpu_dir[i]->d_name);
if (!is_cpu_hotpluggable(cpuid))
continue;
if (get_cpu_attribute(cpuid, "online") == CPU_ONLINE) {
cpuplugd_debug("cpu%d will be disabled\n", cpuid);
rc = hotunplug(cpuid);
}
fclose(filp);
} else {
retval = 1;
}
return retval;
util_scandir_free(cpu_dir, count);
free(path);
return rc;
}
/*
* Cleanup method. If the daemon is stopped, we (re)activate all cpus
*/
void reactivate_cpus()
void reactivate_cpus(void)
{
/*
* Only enable the number of cpus which where
* available at daemon startup time
*/
int cpuid, nc;
struct dirent **cpu_dir;
int cpuid, nc, count, i;
char *path;
cpuid = 0;
/* suppress verbose messages on exit */
debug = 0;
/*
* We check for num_cpu_start != 0 because we might want to
* clean up, before we queried for the number on cpus at
* startup
*/
/*
* Only enable the number of cpus which where available at
* daemon startup time by checking num_cpu_start.
* We check for num_cpu_start != 0 because we might want to
* clean up, before we queried for the number on cpus at
* startup
*/
if (num_cpu_start == 0)
return;
while (get_num_online_cpus() != num_cpu_start && cpuid < get_numcpus()) {
nc = 0;
path = util_path_sysfs("devices/system/cpu/");
count = util_scandir(&cpu_dir, alphasort, path, "cpu[0-9]*");
for (i = 0; (i < count) && (nc != num_cpu_start); i++) {
nc = get_num_online_cpus();
if (nc == num_cpu_start)
return;
if (nc > num_cpu_start && is_online(cpuid) == 1)
if (sscanf(cpu_dir[i]->d_name, "cpu%d", &cpuid) != 1)
cpuplugd_exit("Malformed content of %s: %s\n", path, cpu_dir[i]->d_name);
if (nc > num_cpu_start &&
get_cpu_attribute(cpuid, "online") == CPU_ONLINE)
hotunplug(cpuid);
if (nc < num_cpu_start && is_online(cpuid) == 0)
if (nc < num_cpu_start &&
get_cpu_attribute(cpuid, "online") == CPU_OFFLINE)
hotplug(cpuid);
cpuid++;
}
util_scandir_free(cpu_dir, count);
free(path);
}
/*
* In kernels > 2.6.24 cpus can be deconfigured. The following functions is used
* to check if a certain cpus is in a deconfigured state.
*/
int cpu_is_configured(int cpuid)
{
FILE *filp;
int retval, state, rc;
char path[4096];
retval = -1;
sprintf(path, "/sys/devices/system/cpu/cpu%d/configure", cpuid);
if (access(path, R_OK) == 0) {
filp = fopen(path, "r");
rc = fscanf(filp, "%d", &state);
if (rc == 1) {
if (state == 1)
retval = 1;
if (state == 0)
retval = 0;
}
fclose(filp);
}
return retval;
}

View File

@@ -23,6 +23,9 @@
#include <unistd.h>
#include "lib/util_base.h"
#include "lib/util_path.h"
#include "lib/util_file.h"
#include "lib/util_scandir.h"
#include "lib/zt_common.h"
#define NAME "cpuplugd"
@@ -35,6 +38,8 @@
#define MAX_VARNAME 128
#define MAX_LINESIZE 2048
#define CPUSTATS 10
#define PLR_HORIZONTAL 0
#define PLR_VERTICAL 1
/*
* Precedence of C operators
@@ -173,9 +178,11 @@ extern unsigned int history_max;
extern unsigned int history_current;
extern struct symbol_names sym_names[];
extern unsigned int sym_names_count;
extern int saved_polarization;
int get_numcpus();
int get_num_online_cpus();
int get_polarization(void);
void get_loadavg_runnable(double *loadavg, double *runnable);
void clean_up();
void reactivate_cpus();
@@ -190,9 +197,8 @@ void proc_cpu_read(char *procinfo);
unsigned long proc_read_size(char *path);
char *get_var_rvalue(char *var_name);
void cleanup_cmm(void);
int hotplug(int cpuid);
int hotunplug(int cpuid);
int is_online(int cpuid);
int hotplug_one_cpu(void);
int hotunplug_one_cpu(void);
long get_cmmpages_size();
void parse_options(int argc, char **argv);
void check_if_started_twice();
@@ -202,9 +208,9 @@ void reload_daemon(void);
int daemonize(void);
int check_cmmfiles(void);
void check_config();
void apply_cpu_config(void);
void set_cmm_pages(long size);
int check_lpar();
int cpu_is_configured(int cpuid);
void setup_history(void);

View File

@@ -149,6 +149,8 @@ void clean_up()
cpuplugd_info("terminated\n");
remove(pid_file);
remove(LOCKFILE);
/* suppress verbose messages on exit */
debug = 0;
reactivate_cpus();
if (memory)
cleanup_cmm();
@@ -163,6 +165,8 @@ void kill_daemon(int UNUSED(a))
cpuplugd_info("shutting down\n");
remove(pid_file);
remove(LOCKFILE);
/* suppress verbose messages on exit */
debug = 0;
reactivate_cpus();
if (memory)
cleanup_cmm();

View File

@@ -54,12 +54,12 @@ struct config cfg = {
.hotunplug = NULL,
};
int num_cpu_start, memory, cpu, reload_pending;
long cmm_pagesize_start;
unsigned long meminfo_size, vmstat_size, cpustat_size, varinfo_size;
char *meminfo, *vmstat, *cpustat, *varinfo;
double *timestamps;
unsigned int history_max, history_current, history_prev, sym_names_count;
unsigned long meminfo_size, vmstat_size, cpustat_size, varinfo_size;
int num_cpu_start, memory, cpu, reload_pending, saved_polarization;
char *meminfo, *vmstat, *cpustat, *varinfo;
long cmm_pagesize_start;
double *timestamps;
static struct symbols symbols;
static jmp_buf jmpenv;
@@ -77,8 +77,29 @@ static void eval_cpu_rules(void)
{
double diffs[CPUSTATS], diffs_total, percent_factor;
char *procinfo_current, *procinfo_prev;
int cpu, nr_cpus, on_off;
int nr_cpus, on_off, polarization;
polarization = get_polarization();
if (polarization < 0) {
cpuplugd_debug("couldn't determine system polarization\n");
cpuplugd_debug("skipping cpu rule evaluation\n");
return;
}
if (saved_polarization != polarization) {
saved_polarization = polarization;
if (polarization == PLR_VERTICAL) {
/* revert cpu hotplug adjustments after switching from horizontal */
reactivate_cpus();
} else if (polarization == PLR_HORIZONTAL) {
/* reapply cpu config after switching from vertical */
apply_cpu_config();
}
}
if (polarization == PLR_VERTICAL) {
cpuplugd_debug("system is running vertical polarization\n");
cpuplugd_debug("cpuplugd won't make cpu adjustments\n");
return;
}
nr_cpus = get_numcpus();
procinfo_current = cpustat + history_current * cpustat_size;
procinfo_prev = cpustat + history_prev * cpustat_size;
@@ -157,7 +178,6 @@ static void eval_cpu_rules(void)
printf("\n");
printf("---------------------------------------------\n");
}
on_off = 0;
/* Evaluate the hotplug rule */
if (eval_term(cfg.hotplug, &symbols))
@@ -172,40 +192,16 @@ static void eval_cpu_rules(void)
cpuplugd_debug("maximum cpu limit is reached\n");
return;
}
/* try to find a offline cpu */
for (cpu = 0; cpu < nr_cpus; cpu++)
if (is_online(cpu) == 0 && cpu_is_configured(cpu) != 0)
break;
if (cpu < nr_cpus) {
cpuplugd_debug("cpu with id %d is currently offline "
"and will be enabled\n", cpu);
if (hotplug(cpu) == -1)
cpuplugd_debug("unable to find a cpu which "
"can be enabled\n");
} else {
/*
* In case we tried to enable a cpu but this failed.
* This is the case if a cpu is deconfigured
*/
cpuplugd_debug("unable to find a cpu which can "
"be enabled\n");
}
if (hotplug_one_cpu())
cpuplugd_debug("unable to find a cpu which can be enabled\n");
} else if (on_off < 0) {
/* check cpu nr limit */
if (symbols.onumcpus <= cfg.cpu_min) {
cpuplugd_debug("minimum cpu limit is reached\n");
return;
}
/* try to find a online cpu */
for (cpu = get_numcpus() - 1; cpu >= 0; cpu--) {
if (is_online(cpu) != 0)
break;
}
if (cpu > 0) {
cpuplugd_debug("cpu with id %d is currently online "
"and will be disabled\n", cpu);
hotunplug(cpu);
}
if (hotunplug_one_cpu())
cpuplugd_debug("unable to find a cpu which can be disabled\n");
}
}

View File

@@ -22,6 +22,9 @@ of active CPUs are reset to the values they had before the cpuplugd was started.
This program can be used to control the number of CPUs for Linux on z/VM
and for Linux in LPAR mode. The memory hotplug feature (CMM page pool) applies
to Linux on z/VM only.
The cpuplugd daemon stops any CPU hot-plug operations when the system switches
to vertical polarization, thus avoiding possible performance penalties.
.
.SH OPTIONS
.TP

View File

@@ -31,11 +31,11 @@
#
# Dump on ECKD device (DASD)
#
#ON_PANIC=dump
#DUMP_TYPE=eckd
#DEVICE=0.0.1004
#BOOTPROG=0
#BR_CHR=auto
# ON_PANIC=dump
# DUMP_TYPE=eckd
# DEVICE=0.0.1004
# BOOTPROG=0
# BR_CHR=auto
#
# Dump on fcp device (SCSI Disk)

View File

@@ -93,5 +93,6 @@ SECTIONS
*(.eh_frame)
*(.interp)
*(.note.GNU-stack)
*(.note.package)
}
}

View File

@@ -79,5 +79,6 @@ SECTIONS
*(.eh_frame)
*(.interp)
*(.note.GNU-stack)
*(.note.package)
}
}

View File

@@ -15,5 +15,6 @@ SECTIONS
*(.eh_frame)
*(.interp)
*(.note.GNU-stack)
*(.note.package)
}
}

View File

@@ -58,6 +58,8 @@ struct os_info {
uint8_t reserved[3804];
} __packed;
STATIC_ASSERT(sizeof(struct os_info) == 4096)
/*
* Return 0 in case of valid os_info
* Return -EOS_INFO_MISSING if os_info address is not page aligned or page is

View File

@@ -72,6 +72,7 @@ char *path_get_ap_udev(void);
void vfio_ap_parse_matrix(struct vfio_ap_device *dev, char *matrix);
void vfio_ap_sort_matrix_results(struct vfio_ap_device *dev);
void vfio_ap_parse_control(struct vfio_ap_device *dev, char *control);
bool vfio_ap_need_dynamic_config(struct vfio_ap_device *dev);
/* Functions for reading JSON device config */
int vfio_ap_read_device_config(const char *path, struct vfio_ap_device *dev);
@@ -87,6 +88,9 @@ bool ap_read_udev_masks(char *path, char *ap, char *aq, bool *read_ap,
bool *read_aq);
void ap_mask_to_list(char *mask, struct util_list *list);
void ap_list_remove_all(struct util_list *list);
char *vfio_ap_device_get_adapter_mask(struct vfio_ap_device *dev, int *size);
char *vfio_ap_device_get_domain_mask(struct vfio_ap_device *dev, int *size);
char *vfio_ap_device_get_control_mask(struct vfio_ap_device *dev, int *size);
/* Lock Functions */
int ap_get_lock(void);

View File

@@ -723,14 +723,14 @@ static void check_exists(const char *path, const char *attr)
snprintf(fpath, sizeof(fpath), "/sys/firmware/%s", path);
if (access(fpath, F_OK) != 0)
ERR_EXIT("System does not allow to set %s", attr);
ERR_EXIT("System does not allow one to set %s", attr);
}
static void write_str_optional(char *string, char *file, int exit_on_fail,
const char *attr)
{
if (write_str_errno(string, file) && exit_on_fail)
ERR_EXIT("System does not allow to set %s", attr);
ERR_EXIT("System does not allow one to set %s", attr);
}
/*

View File

@@ -15,7 +15,7 @@
prog_name=`basename $0`
guest_name=${USER:-`whoami 2>/dev/null`}
terminal=lnxhvc0
iucvconn=`which iucvconn 2>/dev/null`
iucvconn=`command -v iucvconn 2>/dev/null`
__error() {
printf "$prog_name: $@\n" >&2

View File

@@ -33,6 +33,9 @@
#include "lib/util_path.h"
#include "lib/util_udev.h"
static const char default_mask[AP_MASK_SIZE] =
"0x0000000000000000000000000000000000000000000000000000000000000000";
/*
* Return sysfs path to a bus attribute
* Note: caller is responsible for freeing the returned string
@@ -118,6 +121,37 @@ static void modify_device_attr(struct util_list *list, char *value)
vfio_ap_node_remove_dupes(list);
}
/*
* Pass a comma-delimited string of masks (adapters,domains,controls) and
* for each ON bit in these masks add the associated ID to the device
* lists.
*/
static void modify_device_ap_config(struct vfio_ap_device *dev,
char *value)
{
char *mask, *adapters, *domains, *controls;
mask = util_strdup(value);
adapters = strtok(mask, ",");
domains = strtok(NULL, ",");
controls = strtok(NULL, ",");
util_assert((!strtok(NULL, ",")) && adapters && domains && controls,
"Invalid ap_config attribute encountered %s", value);
/*
* ap_config overwrites the current list of adapters, domains and
* control domains. Clear the current lists before generating new ones
* based upon the input mask values.
*/
ap_list_remove_all(dev->adapters);
ap_list_remove_all(dev->domains);
ap_list_remove_all(dev->controls);
ap_mask_to_list(adapters, dev->adapters);
ap_mask_to_list(domains, dev->domains);
ap_mask_to_list(controls, dev->controls);
}
static void load_attr_to_device(struct vfio_ap_device *dev, char *attr,
const char *value)
{
@@ -129,6 +163,8 @@ static void load_attr_to_device(struct vfio_ap_device *dev, char *attr,
modify_device_attr(dev->domains, v);
else if (strcmp(attr, "assign_control_domain") == 0)
modify_device_attr(dev->controls, v);
else if (strcmp(attr, "ap_config") == 0)
modify_device_ap_config(dev, v);
free(v);
}
@@ -416,6 +452,28 @@ void vfio_ap_parse_control(struct vfio_ap_device *dev, char *control)
}
}
/**
* Determine if the specified device is currently active. If so, see if
* it is enabled for dynamic configuration support.
*
* @param[in] dev Vfio-ap struct
*
* @retval True Device is active and enabled for dynamic config
* @retval False Device is not active OR no dynamic config support
*/
bool vfio_ap_need_dynamic_config(struct vfio_ap_device *dev)
{
char *attr = path_get_vfio_ap_attr(dev->uuid, "ap_config");
if (!attr)
return false;
if (!util_path_is_readable(attr))
return false;
return true;
}
#ifdef HAVE_JSONC
/**
@@ -692,7 +750,7 @@ void ap_mask_to_list(char *mask, struct util_list *list)
*/
void ap_list_remove_all(struct util_list *list)
{
struct ap_node *node;
struct vfio_ap_node *node;
while (!util_list_is_empty(list)) {
node = util_list_start(list);
@@ -715,6 +773,90 @@ static unsigned int random_delay(void)
return AP_LOCK_DELAY_US + (rand() % AP_LOCK_VARIANCE_US);
}
/**
* Return a mask of assigned adapters for the specified vfio_ap device.
* Note: caller is responsible for freeing the returned string
*
* @param[in] dev Vfio-ap struct to get adapter mask from
* @param[in, out] size Size of mask buffer returned
*
* @retval != 0 Adapter mask (hex string)
* @retval 0 Failed to generate a mask
*/
char *vfio_ap_device_get_adapter_mask(struct vfio_ap_device *dev, int *size)
{
struct vfio_ap_node *node;
char *mask;
if (!dev || !size)
return NULL;
mask = util_strdup(default_mask);
*size = AP_MASK_SIZE;
util_list_iterate(dev->adapters, node) {
ap_set_bit(node->id, mask, true);
}
return mask;
}
/**
* Return a mask of assigned domains for the specified vfio_ap device.
* Note: caller is responsible for freeing the returned string
*
* @param[in] dev Vfio-ap struct to get domain mask from
* @param[in, out] size Size of mask buffer returned
*
* @retval != 0 Domain mask (hex string)
* @retval 0 Failed to generate a mask
*/
char *vfio_ap_device_get_domain_mask(struct vfio_ap_device *dev, int *size)
{
struct vfio_ap_node *node;
char *mask;
if (!dev || !size)
return NULL;
mask = util_strdup(default_mask);
*size = AP_MASK_SIZE;
util_list_iterate(dev->domains, node) {
ap_set_bit(node->id, mask, true);
}
return mask;
}
/**
* Return a mask of assigned control domains for the specified vfio_ap device.
* Note: caller is responsible for freeing the returned string
*
* @param[in] dev Vfio-ap struct to get control domain mask from
* @param[in, out] size Size of mask buffer returned
*
* @retval != 0 Control domain mask (hex string)
* @retval 0 Failed to generate a mask
*/
char *vfio_ap_device_get_control_mask(struct vfio_ap_device *dev, int *size)
{
struct vfio_ap_node *node;
char *mask;
if (!dev || !size)
return NULL;
mask = util_strdup(default_mask);
*size = AP_MASK_SIZE;
util_list_iterate(dev->controls, node) {
ap_set_bit(node->id, mask, true);
}
return mask;
}
/**
* Acquire the ap config lock using this Process ID
*

View File

@@ -1084,8 +1084,6 @@ int kmip_connection_new(const struct kmip_conn_config *config,
return -EINVAL;
}
break;
break;
default:
kmip_debug(debug, "Invalid encoding: %d", config->encoding);
return -EINVAL;

View File

@@ -89,7 +89,7 @@ int kmip_decode_xml(const xmlNode *xml, struct kmip_node *parent,
} else {
n->type = kmip_type_by_name_or_hex(type_attr);
if (n->type == 0) {
kmip_debug(debug, "Unknown 'type' in JSON object: '%s'",
kmip_debug(debug, "Unknown 'type' in XML object: '%s'",
type_attr);
rc = -EBADMSG;
goto out;
@@ -361,7 +361,7 @@ int kmip_encode_xml(const struct kmip_node *node, xmlNode **xml, bool debug)
while (element != NULL) {
rc = kmip_encode_xml(element, &elem_xml, debug);
if (rc != 0) {
kmip_debug(debug, "kmip_encode_json failed");
kmip_debug(debug, "kmip_encode_xml failed");
goto out;
}
if (xmlAddChild(ret_xml, elem_xml) == NULL) {

View File

@@ -710,6 +710,14 @@ static void csv_map(struct obj_t *UNUSED(obj), unsigned int mflags,
free(qval);
}
static bool hide_meta_env(void)
{
char *v;
v = secure_getenv("FMT_NOMETA");
return (v && strcmp(v, "1") == 0);
}
void util_fmt_init(FILE *fd, enum util_fmt_t type, unsigned int flags,
int api_level)
{
@@ -719,7 +727,7 @@ void util_fmt_init(FILE *fd, enum util_fmt_t type, unsigned int flags,
f.fileno = fileno(fd);
f.hide_prefix = (flags & FMT_NOPREFIX);
f.hide_inval = !(flags & FMT_KEEPINVAL);
f.hide_meta = (flags & FMT_NOMETA);
f.hide_meta = (flags & FMT_NOMETA) || hide_meta_env();
f.quote_all = (flags & FMT_QUOTEALL);
f.do_filter = (flags & FMT_FILTER);
f.do_warn = (flags & FMT_WARN);

View File

@@ -80,6 +80,10 @@ Cylinder, Head and Record) or "auto".
\fB - BR_LBA:\fR
Boot record logical block address.
.TP
\fB - SCP_DATA:\fR
SCP data for SCSI, NVMe and ECKD dump devices.
.TP
\fB - VMCMD_1, VMCMD_2 ... VMCMD_8:\fR
Up to eight CP commands, which are executed in case of a kernel panic

View File

@@ -127,7 +127,7 @@ echo "$cmd: Copying kexec"
# Install both binary and required shared libraries
OLDPATH=$PATH
PATH=$OLDPATH:/sbin:/usr/sbin
kexec_bin=$(which kexec)
kexec_bin=$(command -v kexec)
kexec_sos=$(sharedobjs $kexec_bin)
PATH=$OLDPATH

View File

@@ -119,9 +119,9 @@ dobuild()
# append ramdisk if specified
if [ "$ramdisk" != "" ]
then
ramdisk_size=$(du -b $ramdisk | cut -f1)
kernel_size=$(du -b $kernel | cut -f1)
ramdisk_offset=$(du -b $image | cut -f1)
ramdisk_size=$(du -b -L $ramdisk | cut -f1)
kernel_size=$(du -b -L $kernel | cut -f1)
ramdisk_offset=$(du -b -L $image | cut -f1)
cat $ramdisk >> $image
binval=$(mktemp)
dec2be64 $ramdisk_offset > $binval
@@ -135,7 +135,7 @@ dobuild()
# set cmdline
if [ "$parmfile" != "" ]
then
parmfile_size=$(du -b $parmfile | cut -f1)
parmfile_size=$(du -b -L $parmfile | cut -f1)
if [ $parmfile_size -le $MAX_PARMFILE_SIZE ]
then
# Clear any previous parameters

View File

@@ -19,7 +19,13 @@ ifneq (${HAVE_CARGO},0)
ifneq (${HAVE_OPENSSL},0)
ifneq (${HAVE_LIBCURL},0)
PV_TARGETS := pvsecret pvapconfig pvattest
PV_TARGETS := pvsecret pvattest
ifeq ($(HOST_ARCH),s390x)
PV_TARGETS += pvapconfig
else
BUILD_TARGETS += skip-pvapconfig
endif #HOSTARCH
PV_BUILD_TARGETS := $(PV_TARGETS)
CARGO_TEST_TARGETS += $(addsuffix .test,pv $(PV_TARGETS))
@@ -56,6 +62,9 @@ skip-build:
skip-pv-build:
echo " SKIP rust-pv-tools due to unresolved dependencies"
skip-pvapconfig:
echo " SKIP pvapconfig due to unsupported architecture (s390x only)"
all: $(BUILD_TARGETS)
install: $(INSTALL_TARGETS)
$(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR)
@@ -65,7 +74,9 @@ print-rust-targets:
echo $(BUILD_TARGETS)
clean:
ifneq (${HAVE_CARGO},0)
$(CARGO_CLEAN) ${ALL_CARGOFLAGS}
endif # CARGO
$(RM) -- .check-dep-pvtools .detect-openssl.dep.c .check-cargo
rust-test: $(CARGO_TEST_TARGETS)

View File

@@ -2,8 +2,8 @@
//
// Copyright IBM Corp. 2023, 2024
#![deny(
missing_docs,
#![deny(missing_docs)]
#![warn(
missing_debug_implementations,
trivial_numeric_casts,
unstable_features,

View File

@@ -302,8 +302,8 @@ pub fn x509_dist_points(cert: &X509Ref) -> Vec<String> {
/// Searches for CRL Distribution points and downloads the CRL. Stops after the first successful
/// download.
///
/// Error if something bad(=unexpected) happens (not bad: CRL not available at link, unexpected
/// format) Other issues are mapped to Ok(None)
/// Error if something bad(=unexpected) happens
/// CRL not available at all URIs and unexpected format at all URIs are mapped to Ok(None)
#[cfg(not(test))]
pub fn download_first_crl_from_x509(cert: &X509Ref) -> Result<Option<Vec<openssl::x509::X509Crl>>> {
use crate::utils::read_crls;
@@ -333,6 +333,7 @@ pub fn download_first_crl_from_x509(cert: &X509Ref) -> Result<Option<Vec<openssl
}
match read_crls(&handle.get_ref().0) {
Err(_) => continue,
Ok(crl) if crl.is_empty() => continue,
Ok(crl) => return Ok(Some(crl)),
}
}

View File

@@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
//
// Copyright IBM Corp. 2023, 2024
#![deny(
missing_docs,
#![deny(missing_docs)]
#![warn(
missing_debug_implementations,
trivial_numeric_casts,
unstable_features,

View File

@@ -72,9 +72,9 @@ fn rc_fmt<C: UvCmd>(rc: u16, rrc: u16, cmd: &mut C) -> &'static str {
(0x0000, _) => Some("invalid rc"),
(0x0002, _) => Some("invalid UV command"),
(0x0005, _) => Some("request has an invalid size"),
(0x0030, _) => Some("home address space control bit has R-bit set to one"),
(0x0031, _) => Some("access exception"),
(0x0032, _) => Some("request contains virtual address translating to an invalid address"),
(0x0030, _) => Some("home address space control bit has R-bit set to one. This may be due to a corrupted host or a guest kernel bug. STOP using this guest"),
(0x0031, _) => Some("adress translation exception. This may be due to a corrupted host or a guest kernel bug. STOP using this guest"),
(0x0032, _) => Some("request contains virtual address translating to an invalid address. This may be due to a corrupted host or a guest kernel bug. STOP using this guest"),
(UvDevice::RC_MORE_DATA, _) => unreachable!("This is no Error!!!!"),
(UvDevice::RC_SUCCESS, _) => unreachable!("This is no Error!!!!"),

View File

@@ -2,6 +2,8 @@
//
// Copyright IBM Corp. 2023
use std::mem::size_of;
use crate::{assert_size, static_assert};
use zerocopy::{AsBytes, FromBytes, FromZeroes};
@@ -103,7 +105,7 @@ assert_size!(uvio_attest, 0x138);
/// corresponds to the UV_IOCTL macro
pub(crate) const fn uv_ioctl(nr: u8) -> u64 {
iowr(UVIO_TYPE_UVC, nr, std::mem::size_of::<uvio_ioctl_cb>())
iowr(UVIO_TYPE_UVC, nr, size_of::<uvio_ioctl_cb>())
}
static_assert!(uv_ioctl(UVIO_IOCTL_ATT_NR) == 0xc0407501);

View File

@@ -6,7 +6,6 @@
use std::{
ffi::{c_int, c_ulong},
os::unix::prelude::FromRawFd,
sync::{Mutex, MutexGuard},
};
@@ -65,13 +64,12 @@ impl IoctlCtx {
pub mod mock_libc {
use super::*;
pub unsafe fn ioctl(fd: c_int, cmd: c_ulong, data: *mut ffi::uvio_ioctl_cb) -> c_int {
pub unsafe fn ioctl(_fd: c_int, cmd: c_ulong, data: *mut ffi::uvio_ioctl_cb) -> c_int {
let mut ctx = get_lock(&IOCTL_MTX);
assert!(!ctx.called, "IOCTL called more than once");
ctx.called = true;
assert_eq!(cmd, ctx.exp_cmd, "IOCTL cmd mismatch");
assert_eq!(fd, 17, "IOCTL fd mismatch");
let data_ref: &mut ffi::uvio_ioctl_cb = &mut *data;
@@ -131,10 +129,10 @@ impl UvCmd for TestCmd {
}
impl UvDevice {
/// use some random fd for `uvdevice` its OK, as the ioctl is mocked and never touches the
/// Use this file as backing file for `uvdevice`. This is OK, as the ioctl is mocked and never touches the
/// passed file
fn test_dev() -> Self {
UvDevice(unsafe { File::from_raw_fd(17) })
Self(File::open(".").unwrap())
}
}

View File

@@ -119,6 +119,7 @@ pub struct ApqnInfoEp11 {
}
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub struct ApqnInfoCca {
pub serialnr: String,
pub mkvp_aes: String, // may be an empty string if no MK set
@@ -129,6 +130,7 @@ pub struct ApqnInfoCca {
pub enum ApqnInfo {
Accel(ApqnInfoAccel),
Ep11(ApqnInfoEp11),
#[allow(dead_code)]
Cca(ApqnInfoCca),
}
@@ -262,6 +264,7 @@ impl ApqnInfo {
#[derive(Debug, Clone)]
pub struct Apqn {
#[allow(dead_code)]
pub name: String,
pub card: u32,
pub domain: u32,

View File

@@ -75,7 +75,7 @@ Write the generated request to FILE.
.RE
.RE
.PP
\-\-arpk <FILE>
\-a, \-\-arpk <FILE>
.RS 4
Save the protection key as unencrypted GCM-AES256 key in FILE Do not publish
this key, otherwise your attestation is compromised.

View File

@@ -45,7 +45,7 @@ must start at a page boundary.
.RE
.RE
.PP
\-\-arpk <FILE>
\-a, \-\-arpk <FILE>
.RS 4
Use FILE as the protection key to decrypt the request Do not publish this key,
otherwise your attestation is compromised. Delete this key after verification.

View File

@@ -97,7 +97,7 @@ pub struct CreateAttOpt {
/// Save the protection key as unencrypted GCM-AES256 key in FILE
///
/// Do not publish this key, otherwise your attestation is compromised.
#[arg(long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
#[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
pub arpk: String,
/// Specify-additional data for the request.
@@ -222,7 +222,7 @@ pub struct VerifyOpt {
///
/// Do not publish this key, otherwise your attestation is compromised.
/// Delete this key after verification.
#[arg(long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
#[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
pub arpk: String,
/// Define the output format.

View File

@@ -259,6 +259,7 @@ readonly LOGFILE="${WORKPATH}dbginfo.log"
readonly OUTPUT_FILE_BRIDGE="${WORKPATH}network.out"
readonly OUTPUT_FILE_CMD="${WORKPATH}runtime.out"
readonly OUTPUT_FILE_COREDUMPCTL="${WORKPATH}coredump.out" # separate file needed
readonly OUTPUT_FILE_DASD="${WORKPATH}dasd.out"
readonly OUTPUT_FILE_DOCKER="${WORKPATH}docker_runtime.out"
readonly OUTPUT_FILE_ETHTOOL="${WORKPATH}network.out"
readonly OUTPUT_FILE_HYPTOP="${WORKPATH}runtime.out"
@@ -296,6 +297,7 @@ ALL_STEPS="\
collect_kvm\
collect_container\
collect_nvme\
collect_dasd\
collect_logfiles\
post_processing\
create_package\
@@ -326,6 +328,8 @@ PROCFILES="\
/proc/mounts\
/proc/net/vlan\
/proc/net/bonding\
/proc/net/sockstat\
/proc/net/sockstat6\
/proc/net/softnet_stat\
/proc/partitions\
/proc/qeth\
@@ -491,7 +495,7 @@ CMDS="uname -a\
# Z device subsystem commands (first commands in non alphabetical order)
CMDS="${CMDS}\
:lschp\
:lscss\
:lscss --vpm\
:lszdev\
:find /dev -print0 | sort -z | xargs -0 -n 10 ls -ld\
:lspci -t\
@@ -1233,6 +1237,26 @@ collect_nvme() {
fi
}
########################################
collect_dasd() {
local device
if type dasdview >/dev/null; then
pr_collect_output "DASD storage"
call_run_command "lsdasd" "${OUTPUT_FILE_DASD}" # duplicate as file header
for device in /dev/dasd*; do
if [ -b $device ]; then
call_run_command "dasdview -i $device" "${OUTPUT_FILE_DASD}"
call_run_command "dasdview -t info $device" "${OUTPUT_FILE_DASD}"
else
echo "$device is no block device" >> ${OUTPUT_FILE_DASD}
fi
done
else
pr_skip "dasdview: not available"
fi
}
########################################
collect_kvm() {
local cmd

View File

@@ -1,4 +1,4 @@
.TH DBGINFO.SH 8 "01 2024" "s390-tools"
.TH DBGINFO.SH 8 "07 2024" "s390-tools"
.SH NAME
dbginfo.sh \- collect runtime, configuration and trace information
@@ -65,57 +65,59 @@ Hardware platform = s390x
.br
Runtime environment = z/VM - DPM: NO
.br
Kernel version = 5.14.0 (5.14.0-162.6.1.el9_1.s390x)
Kernel version = 5.14.0 (5.14.0-427.13.1.el9_4.s390x)
.br
OS version / distro = Red Hat Enterprise Linux 9.1 (Plow)
OS version / distro = Red Hat Enterprise Linux 9.4 (Plow)
.br
Date and time of info = 2023-12-22-11-43-08
Date and time of info = 2024-07-11-11-11-11
.PP
1 of 19: Collecting sysfs
1 of 20: Collecting sysfs
.PP
2 of 19: Collecting procfs
2 of 20: Collecting procfs
.PP
3 of 19: Collecting config files
3 of 20: Collecting config files
.PP
4 of 19: Collecting initrd config files
4 of 20: Collecting initrd config files
.PP
5 of 19: Collecting command output
5 of 20: Collecting command output
.PP
6 of 19: Collecting hyptop for z/VM - 5s output
6 of 20: Collecting hyptop for z/VM - 5s output
.PP
7 of 19: Collecting z/VM output
7 of 20: Collecting z/VM output
.PP
8 of 19: Collecting network output
8 of 20: Collecting network output
.PP
9 of 19: Collecting osa oat output
9 of 20: Collecting osa oat output
.PP
10 of 19: Collecting ethtool output
10 of 20: Collecting ethtool output
.PP
11 of 19: Collecting Trafic Control output
11 of 20: Collecting Trafic Control output
.PP
12 of 19: Collecting bridge output
12 of 20: Collecting bridge output
.PP
13 of 19: Skip OpenVSwitch: ovs-vsctl not available
13 of 20: Skip OpenVSwitch: ovs-vsctl not available
.PP
14 of 19: Skip KVM: no virsh command
14 of 20: Skip KVM: no virsh command
.PP
15 of 19: Collecting container host output
15 of 20: Collecting container host output
.PP
Kubernetes ...
.br
16 of 19: Collecting NVME storage output
16 of 20: Collecting NVME storage output
.PP
17 of 19: Collecting log files
17 of 20: Collecting DASD storage output
.PP
18 of 20: Collecting log files
.PP
0 logfiles over 50 MB
.PP
18 of 19: Postprocessing
19 of 20: Postprocessing
.PP
19 of 19: Finalizing: Creating archive with collected data
20 of 20: Finalizing: Creating archive with collected data
.PP
Collected data was saved to:
.br
>> /data\-collection/DBGINFO\-2023\-12\-22\-11\-43\-08\-host\-012345.tgz <<
>> /data\-collection/DBGINFO\-2024\-07\-11\-11\-11\-11\-host\-012345.tgz <<
.br
Please review all collected data before sending to your service organization.
.SH HINTS

View File

@@ -50,7 +50,7 @@ check_environment()
if [ "$(cat /proc/filesystems|grep sysfs)" = "" ]; then
pr_error "no sysfs found"
exit 1
exit 1
fi
SYSFSDIR=$(cat /proc/mounts|awk '$3=="sysfs"{print $2; exit}')
@@ -184,7 +184,8 @@ verify_ccw_dump_device()
#------------------------------------------------------------------------------
# Helper function to check a device string.
#------------------------------------------------------------------------------
function CheckDeviceString() {
check_device_string()
{
local X
X=$(
@@ -222,7 +223,7 @@ function CheckDeviceString() {
setup_ccw_device()
{
DEV="$(CheckDeviceString $DEVICE)"
DEV="$(check_device_string $DEVICE)"
if [ "$DEV" != "" ]; then
echo $DEV > $1/ccw/device
else
@@ -234,7 +235,7 @@ setup_ccw_device()
setup_eckd_device()
{
DEV="$(CheckDeviceString $DEVICE)"
DEV="$(check_device_string $DEVICE)"
if [ "$DEV" != "" ]; then
echo $DEV > $1/eckd/device
else
@@ -252,11 +253,18 @@ setup_eckd_device()
pr_error "ERROR: Invalid BR_CHR '$BR_CHR'." $ERRMSG
return
fi
if [ -e $1/eckd/scp_data ]; then
echo -n "$SCP_DATA" > $1/eckd/scp_data 2>/dev/null || RETVAL=1
if [ $RETVAL -eq 1 ]; then
pr_error "ERROR: Invalid SCP_DATA '$SCP_DATA'." $ERRMSG
return
fi
fi
}
setup_fcp_device()
{
DEV="$(CheckDeviceString $DEVICE)"
DEV="$(check_device_string $DEVICE)"
if [ "$DEV" != "" ]; then
echo $DEV > $1/fcp/device
else
@@ -284,6 +292,13 @@ setup_fcp_device()
pr_error "ERROR: Invalid BR_LBA '$BR_LBA'." $ERRMSG
return
fi
if [ -e $1/fcp/scp_data ]; then
echo -n "$SCP_DATA" > $1/fcp/scp_data 2>/dev/null || RETVAL=1
if [ $RETVAL -eq 1 ]; then
pr_error "ERROR: Invalid SCP_DATA '$SCP_DATA'." $ERRMSG
return
fi
fi
}
setup_nss_device()
@@ -313,6 +328,13 @@ setup_nvme_device()
pr_error "ERROR: Invalid BR_LBA '$BR_LBA'." $ERRMSG
return
fi
if [ -e $1/nvme/scp_data ]; then
echo -n "$SCP_DATA" > $1/nvme/scp_data 2>/dev/null || RETVAL=1
if [ $RETVAL -eq 1 ]; then
pr_error "ERROR: Invalid SCP_DATA '$SCP_DATA'." $ERRMSG
return
fi
fi
}
setup_reipl()
@@ -428,6 +450,10 @@ print_fcp_device()
pr_info "bootprog: $BOOTPROG"
BR_LBA=$(cat $1/fcp/br_lba) || RETVAL=1
pr_info "br_lba..: $BR_LBA"
if [ -e $1/fcp/scp_data ]; then
SCP_DATA=$(cat $1/fcp/scp_data) || RETVAL=1
pr_info "scp_data: $SCP_DATA"
fi
}
print_ccw_device()
@@ -444,6 +470,10 @@ print_eckd_device()
pr_info "br_chr..: $BR_CHR"
BOOTPROG=$(cat $1/eckd/bootprog) || RETVAL=1
pr_info "bootprog: $BOOTPROG"
if [ -e $1/eckd/scp_data ]; then
SCP_DATA=$(cat $1/eckd/scp_data) || RETVAL=1
pr_info "scp_data: $SCP_DATA"
fi
}
print_nvme_device()
@@ -456,6 +486,10 @@ print_nvme_device()
pr_info "bootprog: $BOOTPROG"
BR_LBA=$(cat $1/nvme/br_lba) || RETVAL=1
pr_info "br_lba..: $BR_LBA"
if [ -e $1/nvme/scp_data ]; then
SCP_DATA=$(cat $1/nvme/scp_data) || RETVAL=1
pr_info "scp_data: $SCP_DATA"
fi
}
print_nss_name()

View File

@@ -283,7 +283,7 @@ static void tape390_crypt_parse_opts(struct tape390_crypt *info, int argc,
"%s: No device specified.\n",prog_name);
if (optind + 1 < argc)
ERRMSG_EXIT(EXIT_MISUSE,
"%s: More than one device speficied.\n",prog_name);
"%s: More than one device specified.\n",prog_name);
strcpy(info->devname, argv[optind]);
}

View File

@@ -24,11 +24,6 @@ extern struct devtype ap_devtype;
extern struct subtype ap_subtype;
extern struct namespace ap_namespace;
struct ap_node {
struct util_list_node node;
unsigned int id;
};
struct mdev_cb_data {
struct util_list *adapters;
struct util_list *domains;

View File

@@ -23,6 +23,7 @@
#define PATH_MODPROBE "/sbin/modprobe"
#define PATH_CCW_BUS "/sys/bus/ccw"
#define PATH_CCWGROUP_BUS "/sys/bus/ccwgroup"
#define PATH_IPL "/sys/firmware/ipl"
#define PATH_UDEV_RULES "/etc/udev/rules.d"
#define PATH_UDEV_RULES_VOLATILE "/run/udev/rules.d"
#define PATH_PROC "/proc"
@@ -65,6 +66,7 @@ char *path_get_zfcp_lun_dev(struct zfcp_lun_devid *);
char *path_get_zfcp_port_dev(struct zfcp_lun_devid *);
char *path_get_scsi_hctl_dev(const char *);
char *path_get_bus_attr(const char *, const char *);
char *path_read_text_file(int chomp, err_t err, char *fmt, ...);
exit_code_t path_for_each(const char *,
exit_code_t (*callback)(const char *, const char *,

View File

@@ -29,6 +29,7 @@ struct select_opts {
unsigned int online:1;
unsigned int offline:1;
unsigned int failed:1;
unsigned int ipldev:1;
struct util_list devids; /* List of struct strlist_node */
struct util_list by_path; /* List of struct strlist_node */
struct util_list by_node; /* List of struct strlist_node */

View File

@@ -127,6 +127,7 @@ typedef exit_code_t (*subtype_cb_t)(struct subtype *st, const char *id,
* @device_undefine: Optional: Undefine a device
* @add_definable_ids: Optional: Add IDs of all devices that can be defined to
* specified strlist
* @get_ipldev_id: Optional: If subtype provides IPL device, return its ID
*/
struct subtype {
/* Static data. */
@@ -222,6 +223,7 @@ struct subtype {
exit_code_t (*device_undefine)(struct subtype *, struct device *);
void (*add_definable_ids)(struct subtype *,
struct util_list *);
char *(*get_ipldev_id)(struct subtype *);
};
/* Subtype method accessor functions. */
@@ -287,6 +289,7 @@ exit_code_t subtype_detect_definable(struct subtype *, struct device *);
exit_code_t subtype_device_define(struct subtype *, struct device *);
exit_code_t subtype_device_undefine(struct subtype *, struct device *);
void subtype_add_definable_ids(struct subtype *, struct util_list *);
char *subtype_get_ipldev_id(struct subtype *);
/* Subtype helper functions. */
bool subtype_device_exists(struct subtype *st, const char *id,
@@ -308,6 +311,7 @@ struct subtype *subtype_find(const char *name);
struct attrib *subtype_find_dev_attrib(struct subtype *st, const char *str);
exit_code_t subtype_read_all_devices(struct subtype *st, config_t config,
read_scope_t);
bool subtypes_find_ipldev(struct subtype **st_ptr, char **id_ptr);
bool subtypes_find_by_devnode(struct devnode *devnode,
struct subtype **st_ptr, char **id_ptr);
void subtype_devices_print_all(void);

View File

@@ -345,6 +345,12 @@ errors.
.CL lszdev \-\-failed \-\-info
.PP
.
.OD ipldev "" ""
Select IPL device
Select the device used for the most recent IPL operation.
.PP
.
.
.SH SETTINGS
A

View File

@@ -86,7 +86,7 @@ By default lszdev displays information from both the active and the persistent
configuration, and, if available, from the auto-configuration.
.PP
.SS Output Format
In list format, lszdev uses values with the following meaning for the persistent colums (PERS):
In list format, lszdev uses values with the following meaning for the persistent columns (PERS):
.B yes
.CL A persistent, non-site specific configuration exists; No site specific configurations available.
@@ -313,7 +313,12 @@ errors.
.B Example:
.CL lszdev \-\-failed \-\-info
.PP
.
.OD ipldev "" ""
Select IPL device
Select the device used for the most recent IPL operation.
.PP
.
.
.SH ACTIONS

View File

@@ -53,18 +53,18 @@ static void ap_mask_list_changes(const char *source, const char *target,
struct util_list *adds, struct util_list *subs)
{
int i;
struct ap_node *node;
struct vfio_ap_node *node;
for (i = 0; i <= AP_MAX_MASK_VALUE; i++) {
if (ap_test_bit(i, source)) {
if (!ap_test_bit(i, target)) {
node = misc_malloc(sizeof(struct ap_node));
node = misc_malloc(sizeof(struct vfio_ap_node));
node->id = i;
util_list_add_tail(subs, node);
}
} else {
if (ap_test_bit(i, target)) {
node = misc_malloc(sizeof(struct ap_node));
node = misc_malloc(sizeof(struct vfio_ap_node));
node->id = i;
util_list_add_tail(adds, node);
}
@@ -210,7 +210,7 @@ static bool ap_validate_mask_input(char *mask, const char *input,
* Translate the mask value into a list of additions/removals for later
* conflict analysis.
*/
util_list_init(adds, struct ap_node, node);
util_list_init(adds, struct vfio_ap_node, node);
ap_mask_list_changes(mask, newmask, adds, subs);
strcpy(mask, newmask);
goto out;
@@ -948,8 +948,8 @@ static exit_code_t ap_check_mask_changes(config_t config,
struct util_list all_ap;
struct util_list all_aq;
util_list_init(&all_ap, struct ap_node, node);
util_list_init(&all_aq, struct ap_node, node);
util_list_init(&all_ap, struct vfio_ap_node, node);
util_list_init(&all_aq, struct vfio_ap_node, node);
/* Validate the mask changes against existing vfio-ap devices */
if (SCOPE_ACTIVE(config) && (!util_list_is_empty(add_ap) ||
@@ -996,14 +996,14 @@ static exit_code_t ap_devtype_write_settings(struct devtype *dt,
exit_code_t rc = EXIT_OK;
/* No kernel or module parameters exist for AP device driver. */
util_list_init(&add_ap, struct ap_node, node);
util_list_init(&add_aq, struct ap_node, node);
util_list_init(&sub_ap, struct ap_node, node);
util_list_init(&sub_aq, struct ap_node, node);
util_list_init(&add_p_ap, struct ap_node, node);
util_list_init(&add_p_aq, struct ap_node, node);
util_list_init(&sub_p_ap, struct ap_node, node);
util_list_init(&sub_p_aq, struct ap_node, node);
util_list_init(&add_ap, struct vfio_ap_node, node);
util_list_init(&add_aq, struct vfio_ap_node, node);
util_list_init(&sub_ap, struct vfio_ap_node, node);
util_list_init(&sub_aq, struct vfio_ap_node, node);
util_list_init(&add_p_ap, struct vfio_ap_node, node);
util_list_init(&add_p_aq, struct vfio_ap_node, node);
util_list_init(&sub_p_ap, struct vfio_ap_node, node);
util_list_init(&sub_p_aq, struct vfio_ap_node, node);
write_ap = write_aq = write_udev = false;
rc = ap_get_lock();

View File

@@ -1827,6 +1827,27 @@ static char *ccw_st_get_active_attrib_path(struct subtype *st,
return path;
}
/* Return a newly allocated character string containing the IPL device ID in
* case of CCW IPL. */
static char *ccw_st_get_ipldev_id(struct subtype *st)
{
char *type, *id = NULL;
type = path_read_text_file(1, err_ignore, PATH_IPL "/ipl_type");
if (strcmp(type, "ccw") != 0)
goto out;
id = path_read_text_file(1, err_ignore, PATH_IPL "/device");
if (!ccw_st_exists_active(st, id)) {
free(id);
id = NULL;
}
out:
free(type);
return id;
}
/* The methods of this subtype assume that @data points to a
* struct ccw_subtype_data. */
struct subtype ccw_subtype = {
@@ -1864,4 +1885,6 @@ struct subtype ccw_subtype = {
.add_devnodes = &ccw_st_add_devnodes,
.resolve_devnode = &ccw_st_resolve_devnode,
.get_active_attrib_path = &ccw_st_get_active_attrib_path,
.get_ipldev_id = &ccw_st_get_ipldev_id,
};

View File

@@ -124,6 +124,7 @@ enum {
OPT_ONLINE = (OPT_ANONYMOUS_BASE+__COUNTER__),
OPT_OFFLINE = (OPT_ANONYMOUS_BASE+__COUNTER__),
OPT_FAILED = (OPT_ANONYMOUS_BASE+__COUNTER__),
OPT_IPLDEV = (OPT_ANONYMOUS_BASE+__COUNTER__),
OPT_BY_PATH = (OPT_ANONYMOUS_BASE+__COUNTER__),
OPT_BY_NODE = (OPT_ANONYMOUS_BASE+__COUNTER__),
OPT_BY_INTERFACE = (OPT_ANONYMOUS_BASE+__COUNTER__),
@@ -173,14 +174,14 @@ static struct opts_conflict conflict_list[] = {
OPT_REMOVE_ALL, OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE,
OPT_OFFLINE, OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE,
OPT_BY_ATTRIB, OPT_ACTIVE, OPT_PERSISTENT, OPT_FAILED,
OPT_DECONFIGURE_ALL, 0),
OPT_IPLDEV, OPT_DECONFIGURE_ALL, 0),
OPTS_CONFLICT(OPT_LIST_TYPES,
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
OPT_EXPORT, OPT_IMPORT, OPT_APPLY, OPT_REMOVE,
OPT_REMOVE_ALL, OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE,
OPT_OFFLINE, OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE,
OPT_BY_ATTRIB, OPT_ACTIVE, OPT_PERSISTENT, OPT_FAILED,
OPT_DECONFIGURE_ALL, 0),
OPT_IPLDEV, OPT_DECONFIGURE_ALL, 0),
OPTS_CONFLICT(OPT_EXPORT,
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
OPT_LIST_TYPES, OPT_IMPORT, OPT_APPLY, OPT_REMOVE,
@@ -197,7 +198,7 @@ static struct opts_conflict conflict_list[] = {
OPT_REMOVE_ALL, OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE,
OPT_OFFLINE, OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE,
OPT_BY_ATTRIB, OPT_ACTIVE, OPT_PERSISTENT, OPT_FAILED,
OPT_DECONFIGURE_ALL, 0),
OPT_IPLDEV, OPT_DECONFIGURE_ALL, 0),
OPTS_CONFLICT(OPT_APPLY,
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
OPT_LIST_TYPES, OPT_EXPORT, OPT_IMPORT, OPT_REMOVE,
@@ -223,6 +224,7 @@ static const struct option opt_list[] = {
{ "online", no_argument, NULL, OPT_ONLINE },
{ "offline", no_argument, NULL, OPT_OFFLINE },
{ "failed", no_argument, NULL, OPT_FAILED },
{ "ipldev", no_argument, NULL, OPT_IPLDEV },
{ "by-path", required_argument, NULL, OPT_BY_PATH },
{ "by-node", required_argument, NULL, OPT_BY_NODE },
{ "by-interface", required_argument, NULL, OPT_BY_INTERFACE },
@@ -837,6 +839,11 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
opts->select->failed = 1;
break;
case OPT_IPLDEV:
/* --ipldev */
opts->select->ipldev = 1;
break;
case OPT_BY_PATH:
/* --by-path MOUNTPOINT */
strlist_add(&opts->select->by_path, "%s", optarg);

View File

@@ -21,6 +21,7 @@ SELECTION
--existing Select devices found in the active configuration
--online/--offline Select devices that are online/offline
--failed Select devices that are not functioning correctly
--ipldev Select device used for IPL/boot
--by-path PATH Select device providing file system path, e.g. /usr
--by-node NODE Select device providing device node, e.g. /dev/sda
--by-interface NAME Select device providing network interface, e.g. eth0

View File

@@ -477,6 +477,26 @@ static void dasd_st_add_modules(struct subtype *st, struct device *dev,
strlist_add_unique(modules, DASD_DIAG_MOD_NAME);
}
static char *dasd_eckd_st_get_ipldev_id(struct subtype *st)
{
char *id, *type;
/* Handle CCW-type IPL first. */
id = st->super->get_ipldev_id(st);
if (id)
return id;
/* Extra-handling for eckd LD-IPL. */
type = path_read_text_file(1, err_ignore, PATH_IPL "/ipl_type");
if (strcmp(type, "eckd") != 0)
goto out;
id = path_read_text_file(1, err_ignore, PATH_IPL "/ipl/device");
out:
free(type);
return id;
}
/*
* DASD methods.
*/
@@ -798,6 +818,7 @@ struct subtype dasd_subtype_eckd = {
.configure_persistent = &dasd_st_configure_persistent,
.check_pre_configure = &dasd_st_check_pre_configure,
.add_modules = &dasd_st_add_modules,
.get_ipldev_id = &dasd_eckd_st_get_ipldev_id,
};
static struct ccw_subtype_data dasd_fba_data = {

View File

@@ -89,6 +89,7 @@ enum {
OPT_ONLINE = (OPT_ANONYMOUS_BASE+__COUNTER__),
OPT_OFFLINE = (OPT_ANONYMOUS_BASE+__COUNTER__),
OPT_FAILED = (OPT_ANONYMOUS_BASE+__COUNTER__),
OPT_IPLDEV = (OPT_ANONYMOUS_BASE+__COUNTER__),
OPT_BY_PATH = (OPT_ANONYMOUS_BASE+__COUNTER__),
OPT_BY_NODE = (OPT_ANONYMOUS_BASE+__COUNTER__),
OPT_BY_INTERFACE = (OPT_ANONYMOUS_BASE+__COUNTER__),
@@ -129,6 +130,7 @@ static struct opts_conflict conflict_list[] = {
OPTS_CONFLICT(OPT_TYPE,
OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE, OPT_OFFLINE,
OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE, OPT_FAILED,
OPT_IPLDEV,
0),
OPTS_CONFLICT(OPT_SITE,
OPT_TYPE),
@@ -148,6 +150,7 @@ static const struct option opt_list[] = {
{ "online", no_argument, NULL, OPT_ONLINE },
{ "offline", no_argument, NULL, OPT_OFFLINE },
{ "failed", no_argument, NULL, OPT_FAILED },
{ "ipldev", no_argument, NULL, OPT_IPLDEV },
{ "by-path", required_argument, NULL, OPT_BY_PATH },
{ "by-node", required_argument, NULL, OPT_BY_NODE },
{ "by-interface", required_argument, NULL, OPT_BY_INTERFACE },
@@ -609,6 +612,11 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
opts->select->failed = 1;
break;
case OPT_IPLDEV:
/* --ipldev */
opts->select->ipldev = 1;
break;
case OPT_BY_PATH:
/* --by-path MOUNTPOINT */
strlist_add(&opts->select->by_path, "%s", optarg);

View File

@@ -21,6 +21,7 @@ SELECTION
--existing Select devices found in the active configuration
--online/--offline Select devices that are online/offline
--failed Select devices that are not functioning correctly
--ipldev Select device used for IPL/boot
--by-path PATH Select device providing file system path, e.g. /usr
--by-node NODE Select device providing device node, e.g. /dev/sda
--by-interface NAME Select device providing network interface, e.g. eth0

View File

@@ -18,6 +18,7 @@
#include <unistd.h>
#include "devtype.h"
#include "lib/util_libc.h"
#include "misc.h"
#include "path.h"
#include "zfcp.h"
@@ -404,3 +405,20 @@ char *path_get_bus_attr(const char *bus, const char *attr)
{
return path_get("/sys/bus/%s/%s", bus, attr);
}
/* Read text file from adjusted path. */
char *path_read_text_file(int chomp, err_t err, char *fmt, ...)
{
char *path, *path2, *text;
va_list args;
va_start(args, fmt);
util_vasprintf(&path, fmt, args);
va_end(args);
path2 = path_get(path);
text = misc_read_text_file(path2, chomp, err);
free(path2);
free(path);
return text;
}

View File

@@ -69,7 +69,8 @@ bool select_opts_dev_specified(struct select_opts *select)
!util_list_is_empty(&select->by_if) ||
!util_list_is_empty(&select->by_attr) ||
select->all || select->configured || select->existing ||
select->online || select->offline || select->failed)
select->online || select->offline || select->failed ||
select->ipldev)
return true;
return false;
@@ -1207,6 +1208,19 @@ out:
return rc;
}
/* Select device that was used for IPL. */
static void select_ipldev(struct util_list *selected)
{
struct subtype *st;
char *id;
if (!subtypes_find_ipldev(&st, &id))
return;
selected_dev_list_add(selected, st->devtype, st, id, NULL, 0);
free(id);
}
/* Determine list of IDs of selected devices based on selection options.
* Results are stored as list of struct selected_dev_node in SELECTED.
* If @existing is set, only return nodes for existing devices.
@@ -1235,7 +1249,7 @@ exit_code_t select_devices(struct select_opts *select,
!(util_list_is_empty(&select->by_path) &&
util_list_is_empty(&select->by_node) &&
util_list_is_empty(&select->by_if) &&
util_list_is_empty(&select->by_attr)))
util_list_is_empty(&select->by_attr) && !select->ipldev))
goto by_function;
/* Convert device ID specifications to enable tracking of specifications
@@ -1291,6 +1305,9 @@ by_function:
goto out;
}
if (select->ipldev)
select_ipldev(selected);
out:
/* Release device ID specifications tracking list. */
ptrlist_free(specs, 1);

View File

@@ -96,6 +96,30 @@ static exit_code_t devnode_cb(struct subtype *st, const char *id,
return rc;
}
/* Find device which was used for IPL. Note that id_ptr will point to a newly
* allocated string on success. */
bool subtypes_find_ipldev(struct subtype **st_ptr, char **id_ptr)
{
int i, j;
struct devtype *dt;
struct subtype *st;
char *id;
for (i = 0; (dt = devtypes[i]); i++) {
for (j = 0; (st = dt->subtypes[j]); j++) {
id = subtype_get_ipldev_id(st);
if (id) {
*st_ptr = st;
*id_ptr = id;
return true;
}
}
}
return false;
}
/* Find a device which provides the specified devnode. Note that id_ptr will
* point to a newly allocated string on success. */
bool subtypes_find_by_devnode(struct devnode *devnode, struct subtype **st_ptr,
@@ -520,6 +544,16 @@ void subtype_add_definable_ids(struct subtype *st, struct util_list *ids)
super->add_definable_ids(st, ids);
}
char *subtype_get_ipldev_id(struct subtype *st)
{
struct subtype *super = super_get(st, get_ipldev_id, 0);
if (super)
return super->get_ipldev_id(st);
return NULL;
}
/*
* Subtype helpers. These functions combine some of the subtype methods
* to implement more complex functions.

View File

@@ -251,11 +251,12 @@ exit_code_t udev_ccwgroup_write_device(struct device *dev, bool autoconf)
fprintf(fd, "# Generated by chzdev\n");
/* Triggers. */
fprintf(fd, "ACTION==\"add\", SUBSYSTEM==\"drivers\", "
fprintf(fd, "ACTION!=\"add|change\", GOTO=\"%s\"\n", end_label);
fprintf(fd, "SUBSYSTEM==\"drivers\", "
"KERNEL==\"%s\", GOTO=\"%s\"\n", drv, group_label);
for (i = 0; i < devid.num; i++) {
chan_id = ccw_devid_to_str(&devid.devid[i]);
fprintf(fd, "ACTION==\"add\", SUBSYSTEM==\"ccw\", "
fprintf(fd, "SUBSYSTEM==\"ccw\", "
"KERNEL==\"%s\", DRIVER==\"%s\", "
"GOTO=\"%s\"\n", chan_id, drv, group_label);
free(chan_id);
@@ -275,7 +276,19 @@ exit_code_t udev_ccwgroup_write_device(struct device *dev, bool autoconf)
end_label);
free(chan_id);
}
fprintf(fd, "ATTR{[drivers/ccwgroup:%s]group}=\"", drv);
/* Parallel execution of the ccwgroup devices udev rule can lead to
* udevadm warnings. To prevent this, serialize the execution.
*/
fprintf(fd, "\n# Note: Serialize add events on different devices to"
" change event on single\n# base device to prevent duplicate"
" concurrent grouping attempts\n");
/* The new change uevent should be generated to the base-device only */
chan_id = ccw_devid_to_str(&devid.devid[0]);
fprintf(fd, "ACTION==\"add\", ATTR{[ccw/%s]uevent}=\"change\"\n", chan_id);
fprintf(fd, "ACTION==\"change\", ATTR{[drivers/ccwgroup:%s]group}=\"", drv);
free(chan_id);
for (i = 0; i < devid.num; i++) {
chan_id = ccw_devid_to_str(&devid.devid[i]);
fprintf(fd, "%s%s", i > 0 ? "," : "", chan_id);

View File

@@ -1105,6 +1105,28 @@ static exit_code_t zfcp_lun_st_detect_definable(struct subtype *st,
return EXIT_OK;
}
static char *zfcp_lun_st_get_ipldev_id(struct subtype *st)
{
char *type, *fcp_dev, *wwpn, *lun, *id = NULL;
type = path_read_text_file(1, err_ignore, PATH_IPL "/ipl_type");
if (strcmp(type, "fcp") != 0)
goto out;
fcp_dev = path_read_text_file(1, err_ignore, PATH_IPL "/device");
wwpn = path_read_text_file(1, err_ignore, PATH_IPL "/wwpn");
lun = path_read_text_file(1, err_ignore, PATH_IPL "/lun");
if (fcp_dev && wwpn && lun)
id = misc_asprintf("%s:%s:%s", fcp_dev, wwpn, lun);
free(lun);
free(wwpn);
free(fcp_dev);
out:
free(type);
return id;
}
/*
* zfcp lun subtype.
*/
@@ -1168,4 +1190,6 @@ struct subtype zfcp_lun_subtype = {
.detect_definable = &zfcp_lun_st_detect_definable,
.device_define = &zfcp_lun_st_device_define,
.device_undefine = &zfcp_lun_st_device_undefine,
.get_ipldev_id = &zfcp_lun_st_get_ipldev_id,
};

View File

@@ -695,6 +695,8 @@ static void kdump_select_prod_init(void)
unsigned long prefix, ptr, count, tv_sec, i;
struct timeval timeval;
util_log_print(UTIL_LOG_TRACE, "DFI kdump production system dump initialization\n");
if (g.opts.select_specified && !l.kdump_base)
ERR_EXIT("The \"--select\" option is not possible with this "
"dump");
@@ -712,9 +714,10 @@ static void kdump_select_prod_init(void)
}
dfi_cpu_info_init(DFI_CPU_CONTENT_ALL);
for (i = 0; i < count; i++) {
if (dfi_mem_virt_read(ptr + i * sizeof(long), &prefix,
if (dfi_mem_virt_read(dfi_vm_vtop(ptr) + i * sizeof(long), &prefix,
sizeof(prefix)))
continue;
prefix = dfi_vm_vtop(prefix);
if (prefix == 0)
continue;
if (prefix % 0x1000)
@@ -736,7 +739,7 @@ static void utsname_init(void)
if (dfi_vmcoreinfo_symbol(&ptr, "init_uts_ns"))
return;
if (dfi_mem_virt_read(ptr, buf, sizeof(buf)))
if (dfi_mem_virt_read(dfi_vm_vtop(ptr), buf, sizeof(buf)))
return;
utsname = memchr(buf, 'L', sizeof(buf) - sizeof(*utsname));
if (!utsname)
@@ -806,6 +809,8 @@ int dfi_init(void)
l.dfi = dfi;
g.fh = dfi_dump_open(g.opts.device);
rc = dfi->init();
if (rc == 0)
dfi_mem_chunk_sort();
if (rc == 0 && dfi_feat_seek()) {
kdump_init();
dfi_vmcoreinfo_init();

View File

@@ -30,10 +30,6 @@ int pt_load_add(const struct zg_fh *fh, const Elf64_Phdr *phdr, void **data,
__func__, phdr->p_paddr, phdr->p_vaddr, phdr->p_offset, phdr->p_filesz,
phdr->p_memsz);
if (phdr->p_paddr != phdr->p_vaddr) {
STDERR("Dump file \"%s\" is a user space core dump\n", fh->path);
return -EINVAL;
}
if (phdr->p_memsz == 0)
return -EINVAL;
if (phdr->p_offset + phdr->p_filesz > zg_size(fh))

View File

@@ -324,6 +324,14 @@ void dfi_mem_chunk_read_zero(struct dfi_mem_chunk *UNUSED(mem_chunk),
memset(buf, 0, cnt);
}
/*
* Sort memory chunks by start value
*/
void dfi_mem_chunk_sort(void)
{
util_list_sort(&l.mem_virt.chunk_list, mem_chunk_cmp_fn, NULL);
}
/*
* Return mem_chunk list head
*/
@@ -350,6 +358,14 @@ u64 dfi_mem_range(void)
return l.mem_virt.end_addr - l.mem_virt.start_addr + 1;
}
/*
* Return maximum memory address
*/
u64 dfi_mem_end(void)
{
return l.mem_virt.end_addr;
}
/*
* Is memory range valid?
*/
@@ -439,6 +455,10 @@ void dfi_mem_unmap(u64 start, u64 size)
struct dfi_mem_chunk *mem_chunk, *tmp;
u64 end = start + size - 1;
util_log_print(UTIL_LOG_TRACE,
"DFI mem unmap start 0x%016lx, size 0x%016lx\n",
start, size);
util_list_iterate_safe(&l.mem_virt.chunk_list, mem_chunk, tmp) {
/*
* Chunk not hit?
@@ -504,6 +524,10 @@ void dfi_mem_unmap(u64 start, u64 size)
*/
void dfi_mem_map(u64 start, u64 size, u64 start_phys)
{
util_log_print(UTIL_LOG_TRACE,
"DFI mem map start 0x%016lx, size 0x%016lx, base 0x%016lx\n",
start, size, start_phys);
if (mem_range_mapped(start, size)) {
dfi_mem_map_print(false);
ABORT("Map request for already mapped region (%llx/%llx/%llx)",

View File

@@ -43,6 +43,7 @@ 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);
u64 dfi_mem_end(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);
@@ -54,6 +55,7 @@ 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)
void dfi_mem_chunk_sort(void);
int dfi_mem_virt_read(u64 addr, void *buf, size_t cnt);
int dfi_mem_phys_read(u64 addr, void *buf, size_t cnt);

View File

@@ -346,11 +346,19 @@ int dfi_s390_init_gen(bool extended)
l.extended = extended;
if (read_s390_hdr() != 0)
return -ENODEV;
zg_ioctl(g.fh, BLKSSZGET, &l.blk_size, "BLKSSZGET", ZG_CHECK);
if (!extended)
if (!extended) {
rc = mem_chunks_add();
else
} else {
/*
* A device block size is required for a decompression of
* s390_ext dump with compressed dump segments.
* Since dumps in s390_ext format can reside on DASD partition
* only, bail out upon ioctl error on BLKSSZGET.
*/
if (zg_ioctl(g.fh, BLKSSZGET, &l.blk_size, "BLKSSZGET", ZG_CHECK_NONE))
return -ENODEV;
rc = mem_chunks_add_ext();
}
if (rc)
return rc;
rc = df_s390_cpu_info_add(&l.hdr, l.hdr.mem_size);

View File

@@ -20,6 +20,8 @@
#include "dfi_mem_chunk.h"
#include "dfi_vmcoreinfo.h"
#include "boot/os_info.h"
#ifdef __s390x__
#define LC_VMCORE_INFO 0xe0c
#else
@@ -27,26 +29,14 @@
#endif
#define LC_OS_INFO 0xe18
#define OS_INFO_MAGIC 0x4f53494e464f535aULL /* OSINFOSZ */
struct os_info {
u64 magic;
u32 csum;
u16 version_major;
u16 version_minor;
u64 crashkernel_addr;
u64 crashkernel_size;
u64 vmcoreinfo_addr;
u64 vmcoreinfo_size;
u32 vmcoreinfo_csum;
u64 reipl_block_addr;
u64 reipl_block_size;
u32 reipl_block_csum;
u64 init_fn_addr;
u64 init_fn_size;
u32 init_fn_csum;
u8 reserved[4004];
} __packed;
struct vm_info {
u64 identity_base;
u64 kaslr_offset;
u64 kaslr_offset_phys;
u64 amode31_start;
u64 amode31_end;
};
/*
* File local static data
@@ -54,6 +44,7 @@ struct os_info {
static struct {
char *vmcoreinfo;
struct os_info *os_info;
struct vm_info *vm_info;
} l;
static u32 os_info_csum(struct os_info *os_info)
@@ -71,6 +62,7 @@ static struct os_info *os_info_get(void)
if (dfi_mem_virt_read(LC_OS_INFO, &addr, sizeof(addr)))
return NULL;
util_log_print(UTIL_LOG_DEBUG, "DFI osinfo addr: 0x%016lx\n", addr);
if (addr % 0x1000)
return NULL;
if (dfi_mem_virt_read(addr, &os_info, sizeof(os_info)))
@@ -79,9 +71,46 @@ static struct os_info *os_info_get(void)
return NULL;
if (os_info.csum != os_info_csum(&os_info))
return NULL;
util_log_print(UTIL_LOG_DEBUG, "DFI found valid osinfo!\n");
return &os_info;
}
static struct vm_info *vm_info_get(void)
{
static struct vm_info vm_info = { 0 };
util_log_print(UTIL_LOG_TRACE, "DFI read vm_info\n");
vm_info.kaslr_offset = l.os_info->entry[OS_INFO_KASLR_OFFSET].val;
if (vm_info.kaslr_offset == 0)
return NULL;
vm_info.kaslr_offset_phys = l.os_info->entry[OS_INFO_KASLR_OFF_PHYS].val;
vm_info.identity_base = l.os_info->entry[OS_INFO_IDENTITY_BASE].val;
vm_info.amode31_start = l.os_info->entry[OS_INFO_AMODE31_START].val;
vm_info.amode31_end = l.os_info->entry[OS_INFO_AMODE31_END].val;
return &vm_info;
}
/*
* Convert virual address in the dump to the physical address using
* vm_info data derived from os_info
*/
u64 dfi_vm_vtop(u64 vaddr)
{
if (!l.vm_info)
return vaddr;
if (vaddr < LOWCORE_SIZE)
return vaddr;
if ((vaddr < l.vm_info->amode31_end) &&
(vaddr >= l.vm_info->amode31_start))
return vaddr;
if (vaddr < l.vm_info->kaslr_offset)
return vaddr - l.vm_info->identity_base;
return vaddr - l.vm_info->kaslr_offset + l.vm_info->kaslr_offset_phys;
}
/*
* Initialize vmcoreinfo
*/
@@ -94,11 +123,13 @@ void dfi_vmcoreinfo_init(void)
util_log_print(UTIL_LOG_TRACE, "DFI vmcoreinfo initialization\n");
l.os_info = os_info_get();
if (l.os_info)
l.vm_info = vm_info_get();
if (l.os_info && l.os_info->vmcoreinfo_size) {
if (l.os_info && l.os_info->entry[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;
addr = l.os_info->entry[OS_INFO_VMCOREINFO].addr;
size = l.os_info->entry[OS_INFO_VMCOREINFO].size;
} else {
if (dfi_mem_virt_read(LC_VMCORE_INFO, &addr, sizeof(addr)))
return;
@@ -175,6 +206,7 @@ static int vmcoreinfo_item_ulong(unsigned long *val, const char *fmt,
int rc;
rc = vmcoreinfo_item(str, sizeof(str), fmt, sym);
util_log_print(UTIL_LOG_DEBUG, "DFI vmcoreinfo symbol %s : %s\n", sym, str);
if (rc)
return rc;
*val = strtoul(str, NULL, base);

View File

@@ -16,5 +16,6 @@ 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);
u64 dfi_vm_vtop(u64 vaddr);
#endif /* DFI_VMCOREINFO_H */

View File

@@ -6,6 +6,7 @@
*/
#include <string.h>
#include "lib/util_log.h"
#include "zg.h"
#include "dfi_mem_chunk.h"
@@ -27,6 +28,10 @@ void dfo_chunk_add(u64 start, u64 size, void *data, dfo_chunk_read_fn read_fn)
{
struct dfo_chunk *dfo_chunk;
util_log_print(UTIL_LOG_DEBUG, "DFO add chunk start=0x%lx, size=0x%lx\n", start, size);
if (size == 0)
return;
dfo_chunk = zg_alloc(sizeof(*dfo_chunk));
dfo_chunk->start = start;
dfo_chunk->end = start + size - 1;

View File

@@ -30,6 +30,7 @@
static struct {
struct df_s390_hdr hdr;
struct df_s390_em em;
u64 dfi_max_end; // Max end address among processed DFI memory chunks
} l;
/*
@@ -159,19 +160,48 @@ static void add_cpu_to_dfo(struct dfi_cpu *cpu)
}
/*
* Add memory chunk to dump layout
* Add memory chunk to DFO dump layout.
* The function is supposed to be called in a loop for each DFI mem chunk in the list.
* DFI memory chunk list is considered to be sorted by start address, thus the
* input memory chunk coming last has a priority for DFO.
*/
static void add_mem_chunk_to_dfo(struct dfi_mem_chunk *mem_chunk)
{
struct dfi_mem_chunk *mem_chunk_prev = dfi_mem_chunk_prev(mem_chunk);
const u64 dfo_current_memsz = dfo_chunk_dump_size() - DF_S390_HDR_SIZE;
if (mem_chunk_prev && (mem_chunk_prev->end + 1 != mem_chunk->start))
dfo_chunk_add(mem_chunk_prev->end + 1 + DF_S390_HDR_SIZE,
mem_chunk->start - mem_chunk_prev->end - 1,
/*
* Consider memory holes and filtered memory pages filling the missing
* areas with zeroes for s390 output format. Keep in mind that dfi_mem_chunks
* can overlap for VR-kernel dumps.
* If no dfi_mem_chunk with zero start address registered, add
* zero DFO memory chunk first.
*
* See the diagram of resulting dfo_s390 for several cases of input memory
* chunks layout below:
*
* DFI DFO(s390)
* ---------------------------------
* aaaa.... HDR|aa|bb|cc|cc
* ..bbbb..
* ....cccc
* ---------------------------------
* ..aa.... HDR|00|aa|00|bb
* ......bb
* ---------------------------------
* aaaaaaaa HDR|aa|bb|aa|cc
* ..bb....
* ......cc
*/
if (l.dfi_max_end < mem_chunk->start &&
mem_chunk->start - l.dfi_max_end > 1)
dfo_chunk_add(dfo_chunk_dump_size(),
mem_chunk->start - dfo_current_memsz,
NULL, dfo_chunk_zero_fn);
dfo_chunk_add(mem_chunk->start + DF_S390_HDR_SIZE, mem_chunk->size,
mem_chunk, dfo_chunk_mem_fn);
l.dfi_max_end = MAX(mem_chunk->end, l.dfi_max_end);
}
/*
@@ -187,7 +217,7 @@ static void dump_chunks_init(void)
add_mem_chunk_to_dfo(mem_chunk);
dfi_cpu_iterate(cpu)
add_cpu_to_dfo(cpu);
dfo_chunk_add(dfi_mem_range() + DF_S390_HDR_SIZE,
dfo_chunk_add(l.hdr.mem_size + DF_S390_HDR_SIZE,
DF_S390_EM_SIZE,
&l.em, dfo_chunk_buf_fn);
}
@@ -209,7 +239,8 @@ static void df_s390_dump_init(void)
else
dh->version = 5;
dh->mem_start = 0;
dh->mem_size = dh->mem_end = dfi_mem_range();
dh->mem_end = dfi_mem_end();
dh->mem_size = dh->mem_end + 1;
dh->num_pages = dh->mem_size / PAGE_SIZE;
dh->arch = df_s390_from_dfi_arch(dfi_arch());
if (dfi_attr_build_arch())

View File

@@ -435,6 +435,13 @@ static int ngdump_get_eckd_part_num(struct zg_fh *zg_fh)
if (!is_vol1(vl.vollbl))
return -1;
/* Read Master Boot Record and check its magic */
if (vl.br.cc == 0x4040 && vl.br.hh == 0x4040 &&
vl.br.b == 0x40) {
util_log_print(UTIL_LOG_TRACE,
"%s: No boot record pointer found in volume label\n",
__func__);
return -1;
}
blk = cchhb2blk(&vl.br, &geo);
if (blk == 0)
return -1;

View File

@@ -35,7 +35,7 @@ zfcpdump_part: zfcpdump.o zfcpdump_part.o
$(ZFCPDUMP_INITRD): cpioinit zfcpdump_part
$(CPIOINIT) zfcpdump_part > $@.tmp
$(GZIP) -f $@.tmp
$(GZIP) -f -n $@.tmp
$(MV) $@.tmp.gz $(ZFCPDUMP_INITRD)
scripts: $(INSTALL_SCRIPTS)

View File

@@ -24,7 +24,6 @@
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/reboot.h>
#include <sys/stat.h>
@@ -294,32 +293,38 @@ static int copy_table_init(int fd, struct copy_table *table)
*/
static int copy_table_entry_write(int fdin, int fdout,
const struct copy_table_entry *entry,
unsigned long offset)
unsigned long disk_offset)
{
unsigned long buf_size, bytes_left, off;
void *map;
static unsigned char buf[COPY_BUF_SIZE];
unsigned long bytes_left, count;
ssize_t bytes_read, bytes_written;
if (entry->size == 0)
return 0;
off = entry->off;
bytes_left = entry->size;
if (lseek(fdout, entry->off + offset, SEEK_SET) < 0)
if (bytes_left == 0)
return 0;
if (lseek(fdin, entry->off, SEEK_SET) < 0)
return -1;
if (lseek(fdout, disk_offset + entry->off, SEEK_SET) < 0)
return -1;
PRINT_TRACE("Write dump: vmcore offset=0x%016lx disk offset=0x%016lx bytes=0x%016lx\n",
entry->off, disk_offset + entry->off, bytes_left);
while (bytes_left > 0) {
buf_size = MIN(COPY_BUF_SIZE, bytes_left);
map = mmap(0, buf_size, PROT_READ, MAP_SHARED, fdin, off);
if (map == (void *)-1) {
PRINT_PERR("Mapping failed\n");
count = MIN(COPY_BUF_SIZE, bytes_left);
bytes_read = read(fdin, buf, count);
if (bytes_read < 0) {
PRINT_PERR("Read from /proc/vmcore failed: offset=0x%016lx bytes=0x%016lx\n",
entry->off + entry->size - bytes_left, count);
return -1;
}
if (write(fdout, map, buf_size) < 0) {
PRINT_PERR("Write to partition failed\n");
bytes_written = write(fdout, buf, bytes_read);
if (bytes_written < 0) {
PRINT_PERR("Write to partition failed: offset=0x%016lx bytes=0x%016lx\n",
disk_offset + entry->off + entry->size - bytes_left,
bytes_read);
return -1;
}
munmap(map, buf_size);
bytes_left -= buf_size;
off += buf_size;
show_progress(buf_size);
bytes_left -= bytes_written;
show_progress(bytes_written);
}
return 0;
}

View File

@@ -667,8 +667,7 @@ function check_free_space_mileage() {
function check_blktrace() {
which blktrace >/dev/null 2>&1;
if [ $? -ne 0 ]; then
if ! command -v blktrace >/dev/null 2>&1; then
echo "$WRP_TOOLNAME: Could not find blktrace. Please make sure that the blktrace package is installed and matches the level in the documentation.";
exit 1;
fi

View File

@@ -196,7 +196,7 @@ int add_to_agg(struct aggr_data *agg_data, struct message *msg,
else if (msg->type == f_hdr->msgid_zfcpdd)
aggregate_zfcpdd(agg_data, msg);
else {
fprintf(stderr, "%s: Unknow msg id: %d,"
fprintf(stderr, "%s: Unknown msg id: %d,"
" discarding\n", toolname, msg->type);
return -1;
}

View File

@@ -5,7 +5,7 @@
#
# Script to list the FCP, SCSI and multipath configuration
#
# Copyright IBM Corp. 2008, 2017
# Copyright IBM Corp. 2008, 2024
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
@@ -130,8 +130,8 @@ sub get_device_data
unless(!$devices{$hctl}{dev});
$devices{$hctl}{mm} = get_line("dev");
$devices{$hctl}{mp_dev} = glob_last("holders", "dm*");
$devices{$hctl}{mp_dev} =~ s/.*\/(.+)\Z/$1/
unless (!$devices{$hctl}{mp_dev});
next if !defined $devices{$hctl}{mp_dev};
$devices{$hctl}{mp_dev} =~ s/.*\/(.+)\Z/$1/;
$c_src = catdir($base_dir, "sys", "block",
$devices{$hctl}{mp_dev});
$devices{$hctl}{mp_dev_mm} = get_line("dev");
@@ -297,7 +297,7 @@ sub mapper_report
"=====================================================\n";
}
foreach my $hctl (sort keys %devices) {
next if (! $devices{$hctl}{mp_dev});
next if (!defined $devices{$hctl}{mp_dev});
next if (@$adapters && "@$adapters" !~ /\b$devices{$hctl}{hba_id}\b/);
next if (@$ports && "@$ports" !~ /\b$devices{$hctl}{wwpn}\b/);
next if (@$s_devs && "@$s_devs" !~ /\b$devices{$hctl}{dev}\b/);
@@ -391,7 +391,7 @@ MSG
sub version {
print "$PROGRAM_NAME: version %S390_TOOLS_VERSION%\n";
print "Copyright IBM Corp. 2008, 2017\n";
print "Copyright IBM Corp. 2008, 2024\n";
}
sub unpack_config

View File

@@ -72,5 +72,6 @@ SECTIONS
*(.eh_frame)
*(.interp)
*(.note.GNU-stack)
*(.note.package)
}
}

View File

@@ -14,5 +14,6 @@ SECTIONS
*(.eh_frame)
*(.interp)
*(.note.GNU-stack)
*(.note.package)
}
}

View File

@@ -14,5 +14,6 @@ SECTIONS
*(.eh_frame)
*(.interp)
*(.note.GNU-stack)
*(.note.package)
}
}

View File

@@ -14,5 +14,6 @@ SECTIONS
*(.eh_frame)
*(.interp)
*(.note.GNU-stack)
*(.note.package)
}
}

View File

@@ -93,5 +93,6 @@ SECTIONS
*(.eh_frame)
*(.interp)
*(.note.GNU-stack)
*(.note.package)
}
}

View File

@@ -74,5 +74,6 @@ SECTIONS
*(.eh_frame)
*(.interp)
*(.note.GNU-stack)
*(.note.package)
}
}

View File

@@ -53,16 +53,22 @@ typedef enum {
disk_type_eckd_cdl,
} disk_type_t;
struct disk_ext_type {
disk_type_t type;
bool is_nvme;
};
/* targetbase definition */
typedef enum {
defined_as_device,
defined_as_name
defined_as_name,
undefined
} definition_t;
/* Disk information type */
struct disk_info {
disk_type_t type;
dev_t device;
dev_t device; /* logical device for bootmap creation */
dev_t partition;
int devno;
int partnum;
@@ -72,8 +78,11 @@ struct disk_info {
struct hd_geometry geo;
char* name;
char* drv_name;
definition_t targetbase;
definition_t targetbase_def;
int is_nvme;
dev_t basedisks[MAX_TARGETS]; /* array of physical disks for
* bootstrap blocks recording
*/
};
struct file_range {
@@ -83,12 +92,15 @@ struct file_range {
struct job_target_data;
int disk_get_info(const char* device, struct job_target_data* target,
struct disk_info** info);
int disk_is_tape(const char* device);
int disk_is_scsi(const char* device, struct job_target_data* target);
int disk_is_eckd_ldl(const char* device, struct job_target_data* target);
int disk_is_nvme(const char* device, struct job_target_data* target);
int disk_get_info(const char *device, struct job_target_data *target,
struct disk_info **info);
int disk_get_ext_type(const char *device, struct disk_ext_type *ext_type);
int disk_is_tape(const char *device);
int disk_type_is_scsi(struct disk_ext_type *ext_type);
int disk_type_is_eckd_ldl(struct disk_ext_type *ext_type);
int disk_type_is_nvme(struct disk_ext_type *ext_type);
int disk_type_is_eckd(disk_type_t type);
int disk_get_info_from_file(const char* filename,
struct job_target_data* target,
struct disk_info** info);
@@ -113,6 +125,9 @@ blocknum_t disk_write_block_buffer_align(int fd, int fd_is_basedisk,
struct disk_info *info, int align,
off_t *offset);
void disk_print_devt(dev_t d);
void disk_print_devname(dev_t d);
void prepare_footnote_ptr(int source, char *ptr);
void print_footnote_ref(int source, const char *prefix);
void disk_print_info(struct disk_info *info, int source);
int disk_is_zero_block(disk_blockptr_t* block, struct disk_info* info);
blocknum_t disk_compact_blocklist(disk_blockptr_t* list, blocknum_t count,
@@ -122,7 +137,6 @@ blocknum_t disk_get_blocklist_from_file(const char* filename,
disk_blockptr_t** blocklist,
struct disk_info* pinfo);
int disk_check_subchannel_set(int devno, dev_t device, char* dev_name);
void disk_print_geo(struct disk_info *data);
int fs_map(int fd, uint64_t offset, blocknum_t *mapped, int fs_block_size);
#endif /* not DISK_H */

View File

@@ -71,7 +71,7 @@ struct install_set {
struct program_component *components[NR_PROGRAM_COMPONENTS];
int nr_menu_entries;
int fd;
char *device;
char *basetmp[MAX_TARGETS];
char *filename;
unsigned int tmp_filename_created:1;
unsigned int skip_prepare:1;

View File

@@ -18,7 +18,6 @@
#include "disk.h"
#include "zipl.h"
enum job_id {
job_print_usage = 1,
job_print_version = 2,
@@ -30,6 +29,21 @@ enum job_id {
job_mvdump = 8,
};
/*
* Set of parameters per physical disk, which are provided
* either by user, or by helper script
*/
struct target {
char *targetbase;
disk_type_t targettype;
int targetcylinders;
int targetheads;
int targetsectors;
int targetblocksize;
blocknum_t targetoffset;
int check_params;
};
/* target information source */
typedef enum {
source_unknown = 0,
@@ -39,17 +53,21 @@ typedef enum {
} source_t;
struct job_target_data {
char* bootmap_dir;
char* targetbase;
disk_type_t targettype;
int targetcylinders;
int targetheads;
int targetsectors;
int targetblocksize;
blocknum_t targetoffset;
char *bootmap_dir;
int nr_targets;
struct target targets[MAX_TARGETS];
source_t source;
};
enum target_params {
TARGET_BASE,
TARGET_TYPE,
TARGET_GEOMETRY,
TARGET_BLOCKSIZE,
TARGET_OFFSET,
LAST_TARGET_PARAM
};
struct job_common_ipl_data {
char* image;
char* parmline;
@@ -81,6 +99,7 @@ struct job_dump_data {
struct job_common_ipl_data common;
char* device;
uint64_t mem;
bool is_ngdump;
bool no_compress;
};
@@ -142,12 +161,94 @@ struct job_data {
int is_ldipl_dump;
};
static inline struct target *target_at(struct job_target_data *data,
int index)
{
return index >= MAX_TARGETS ? NULL : &data->targets[index];
}
static inline char *get_targetbase(struct job_target_data *data, int index)
{
return target_at(data, index)->targetbase;
}
static inline void set_targetbase(struct job_target_data *data, int index,
char *value)
{
target_at(data, index)->targetbase = value;
}
static inline disk_type_t get_targettype(struct job_target_data *data,
int index)
{
return target_at(data, index)->targettype;
}
int set_targettype(struct job_target_data *data, int index, char *value);
static inline char *job_get_targetbase(struct job_data *job)
{
return get_targetbase(&job->target, 0);
}
static inline void job_set_targetbase(struct job_data *job, char *value)
{
set_targetbase(&job->target, 0, value);
}
static inline int job_get_nr_targets(struct job_data *job)
{
return job->target.nr_targets;
}
static inline void job_set_nr_targets(struct job_data *job, int value)
{
job->target.nr_targets = value;
}
static inline disk_type_t job_get_targettype(struct job_data *job)
{
return get_targettype(&job->target, 0);
}
int job_set_targettype(struct job_data *job, char *value);
#define define_target_param_ops(_TYPE_, _PARAM_) \
static inline _TYPE_ get_target##_PARAM_(struct job_target_data *data, \
int index) \
{ \
return target_at(data, index)->target##_PARAM_; \
} \
\
static inline void set_target##_PARAM_(struct job_target_data *data, \
int index, _TYPE_ value) \
{ \
target_at(data, index)->target##_PARAM_ = value; \
} \
\
static inline _TYPE_ job_get_target##_PARAM_(struct job_data *job) \
{ \
return get_target##_PARAM_(&job->target, 0); \
} \
\
static inline void job_set_target##_PARAM_(struct job_data *job, \
_TYPE_ value) \
{ \
set_target##_PARAM_(&job->target, 0, value); \
}
define_target_param_ops(int, cylinders)
define_target_param_ops(int, heads)
define_target_param_ops(int, sectors)
define_target_param_ops(int, blocksize)
define_target_param_ops(blocknum_t, offset)
/**
* Return true, if target parameters for the base disk are set
* Return true, if target parameters are set at least for one target base disk
*/
static inline int target_parameters_are_set(struct job_target_data *td)
{
return td->targetbase != NULL;
return get_targetbase(td, 0) != NULL;
}
int job_get(int argc, char* argv[], struct job_data** data);
@@ -156,6 +257,8 @@ void free_target_data(struct job_target_data *td);
int type_from_target(char *target, disk_type_t *type);
int check_job_dump_images(struct job_dump_data* dump, char* name);
int check_job_images_ngdump(struct job_dump_data* dump, char* name);
bool is_ngdump_enabled(struct job_data *job);
void job_dump_check_set_ngdump(struct job_data *job,
struct disk_ext_type *ext_type);
bool job_dump_is_ngdump(struct job_data *job);
#endif /* not JOB_H */

View File

@@ -41,6 +41,7 @@
#define MENU_DEFAULT_TIMEOUT 0
#define MAX_DUMP_VOLUMES 32
#define MAX_TARGETS 32
#define SECURE_BOOT_UNDEFINED -1
#define SECURE_BOOT_DISABLED 0

View File

@@ -13,21 +13,25 @@ objects = misc.o error.o scan.o job.o boot.o bootmap.o fs-map.o disk.o \
bootmap_header.o envblk.o install.o zipl.o
zipl_helpers = $(basename $(wildcard zipl_helper.*.c))
zipl_helpers += zipl_helper.md
chreipl_helpers = $(subst zipl_,chreipl_, $(zipl_helpers))
all: zipl zipl-editenv $(chreipl_helpers)
all: zipl zipl-editenv zipl_helper.md $(chreipl_helpers)
boot.o: ../boot/.loaders
zipl: $(objects) $(libs)
zipl_helper.device-mapper: $(rootdir)/libdasd/libdasd.a \
$(rootdir)/libvtoc/libvtoc.a \
$(libs) zipl_helper.device-mapper.o
$(libs) misc.o error.o zipl_helper.device-mapper.o
zipl-editenv: $(libs) misc.o error.o fs-map.o bootmap_header.o \
envblk.o zipl-editenv.o
chreipl_helper.%: zipl_helper.%
zipl_helper.md: zipl_helper.device-mapper
ln -f -s $< $@
chreipl_helper.%: zipl_helper.device-mapper
ln -f -s $< $@
install: all

View File

@@ -298,6 +298,47 @@ create_component_header(void* buffer, component_header_type type)
header->type = (uint8_t) type;
}
/*
* Not precise check that the file FILENAME locates on specified physical DISK.
*
* Try to auto-detect parameters of the disk which the file locates on
* and compare found device-ID with DISK.
* Return 0, if auto-detection succeeded, and it is proven that the
* file does NOT locate on DISK. Otherwise, return 1.
*/
static int file_is_on_disk(const char *filename, dev_t disk)
{
/*
* Retrieve info of the underlying disk without any user hints
*/
struct job_target_data tmp = {.source = source_unknown};
struct disk_info *info;
int rc;
rc = disk_get_info_from_file(filename, &tmp, &info);
free_target_data(&tmp);
if (rc) {
/*
* In some cases it is impossible to auto-detect
* disk parameters (e.g. when the file is on a
* mounted qcow2 image).
* Skip the check with warnings.
*/
fprintf(stderr,
"Warning: Could not auto-detect disk parameters for %s\n",
filename);
fprintf(stderr,
"Warning: Preparing a logical device for boot might fail\n");
return 1;
}
if (info->device != disk) {
disk_free_info(info);
return 0;
}
disk_free_info(info);
return 1;
}
static int add_component_file_range(struct install_set *bis,
const char *filename,
struct file_range *reg,
@@ -311,7 +352,6 @@ static int add_component_file_range(struct install_set *bis,
struct component_loc *location = &pc->loc;
disk_blockptr_t **list = &pc->list;
blocknum_t *count = &pc->count;
struct disk_info* file_info;
disk_blockptr_t segment;
char* buffer;
size_t size;
@@ -338,26 +378,13 @@ static int add_component_file_range(struct install_set *bis,
return -1;
}
} else {
/*
* Make sure that file is on target device.
* For this, retrieve info of the underlying disk without
* any user hints
*/
struct job_target_data tmp = {.source = source_unknown};
rc = disk_get_info_from_file(filename, &tmp, &file_info);
free_target_data(&tmp);
if (rc)
return -1;
if (file_info->device != bis->info->device) {
disk_free_info(file_info);
if (!file_is_on_disk(filename, bis->info->device)) {
error_reason("File is not on target device");
return -1;
}
/* Get block list from existing file */
*count = disk_get_blocklist_from_file(filename, reg,
list, file_info);
disk_free_info(file_info);
list, bis->info);
if (*count == 0)
return -1;
*count -= DIV_ROUND_UP(trailer, bis->info->phy_block_size);
@@ -942,62 +969,20 @@ static int add_segment_program(struct install_set *bis,
return rc;
}
#define DUMP_PARAM_MAX_LEN 896
static int
check_dump_device_late(char *partition, struct disk_info *target_info,
struct job_target_data *target,
struct job_data *job)
{
struct disk_info* info;
int rc;
/* Get information about partition */
rc = disk_get_info(partition, target, &info);
if (rc) {
error_text("Could not get information for dump partition '%s'",
partition);
return rc;
}
if ((job->is_ldipl_dump && info->type != disk_type_eckd_cdl) ||
(!job->is_ldipl_dump && info->type != disk_type_scsi) ||
info->partnum == 0) {
error_reason("Device '%s' is not a SCSI or DASD partition",
partition);
disk_free_info(info);
return -1;
}
if (info->device != target_info->device) {
error_reason("Target directory is not on same device as "
"'%s'", partition);
disk_free_info(info);
return -1;
}
disk_free_info(info);
return 0;
}
static int add_dump_program(struct install_set *bis, struct job_data *job,
static int add_dump_program(struct install_set *bis,
const struct job_dump_data *dump,
disk_blockptr_t *program, int verbose,
component_header_type type,
int program_table_id)
{
struct job_dump_data *dump = &job->data.dump;
struct job_target_data *target = &job->target;
struct job_ipl_data ipl;
int rc;
/* Convert fs dump job to IPL job */
memset(&ipl, 0, sizeof(ipl));
ipl.common = dump->common;
/* Get file system dump parmline */
rc = check_dump_device_late(dump->device, bis->info, target, job);
if (rc)
return rc;
ipl.common.parmline = dump->common.parmline;
ipl.common.parm_addr = dump->common.parm_addr;
return add_ipl_program(bis, NULL, false, NULL, &ipl, program,
verbose, 1, type, SECURE_BOOT_DISABLED,
0 /* menu_idx */, program_table_id);
@@ -1068,7 +1053,7 @@ static int build_program_table(struct job_data *job,
printf("Adding dump section '%s' (default)\n",
job->name);
}
rc = add_dump_program(bis, job, &table[0],
rc = add_dump_program(bis, &job->data.dump, &table[0],
verbose || job->command_line,
COMPONENT_HEADER_DUMP,
program_table_id);
@@ -1381,7 +1366,7 @@ estimate_scsi_dump_size(struct job_data *job, struct disk_info *info, ulong *dum
}
/**
* Check that disk is appropriate for the JOB
* Check that disk with retrieved INFO is appropriate for the JOB
*/
static int disk_is_appropriate(const struct job_data *job,
const struct disk_info *info)
@@ -1392,11 +1377,31 @@ static int disk_is_appropriate(const struct job_data *job,
error_reason("Secure boot forced for improper disk type");
return 0;
}
if (job->id == job_dump_partition &&
job->is_ldipl_dump &&
info->type != disk_type_eckd_cdl) {
error_reason("List-directed dump not support on DASD with LDL format");
return 0;
/* common checks */
if (job->target.source == source_auto &&
info->type == disk_type_diag) {
error_reason("Unsupported disk type (%s)",
disk_get_type_name(info->type));
return -1;
}
/* job-specific checks */
if (job->id == job_dump_partition) {
if (job->is_ldipl_dump && info->type != disk_type_eckd_cdl) {
error_reason("Inappropriate dump device (not DASD-CDL)");
return 0;
}
if (!job->is_ldipl_dump && info->type != disk_type_scsi) {
error_reason("Inappropriate dump device (not SCSI)");
return 0;
}
/* Check that data starts beyond the boot area on the base disk.
* In case of source_script the check is performed by the script
*/
if (job->target.source == source_auto && info->partnum == 0) {
error_reason("Dump device %s is not a partition",
job->data.dump.device);
return 0;
}
}
return 1;
}
@@ -1407,19 +1412,10 @@ check_dump_device(struct job_data *job, const struct disk_info *info,
{
int rc, part_ext;
/* Check for supported disk and driver types */
if (job->target.source == source_auto &&
info->type == disk_type_diag) {
error_reason("Unsupported disk type (%s)",
disk_get_type_name(info->type));
return -1;
}
if (!disk_is_appropriate(job, info))
return -1;
if (is_ngdump_enabled(job))
if (job_dump_is_ngdump(job))
return 0;
rc = util_part_search(device, info->geo.start,
info->phy_blocks, info->phy_block_size, &part_ext);
if (rc <= 0 || part_ext) {
@@ -1446,30 +1442,18 @@ static int prepare_build_program_table_device(struct job_data *job,
if (bis->skip_prepare)
/* skip the preparation work */
return 0;
if (dry_run) {
error_text("Option '--dry-run' is not implemented for this type of dump");
return -1;
}
/* Get full path of bootmap file */
if (!dry_run) {
bis->filename = misc_strdup(job->data.dump.device);
if (!bis->filename)
return -1;
bis->fd = misc_open_exclusive(bis->filename);
if (bis->fd == -1) {
error_text("Could not open file '%s'", bis->filename);
return -1;
}
} else {
bis->filename = misc_make_path(job->target.bootmap_dir,
BOOTMAP_TEMPLATE_FILENAME);
if (!bis->filename)
return -1;
/* Create temporary bootmap file */
bis->fd = mkstemp(bis->filename);
if (bis->fd == -1) {
error_reason(strerror(errno));
error_text("Could not create file '%s':",
bis->filename);
return -1;
}
bis->tmp_filename_created = 1;
bis->filename = misc_strdup(job->data.dump.device);
if (!bis->filename)
return -1;
bis->fd = misc_open_exclusive(bis->filename);
if (bis->fd == -1) {
error_text("Could not open file '%s'", bis->filename);
return -1;
}
/* Retrieve target device information */
if (disk_get_info(bis->filename, &job->target, &bis->info))
@@ -1479,9 +1463,9 @@ static int prepare_build_program_table_device(struct job_data *job,
printf("Target device information\n");
disk_print_info(bis->info, job->target.source);
}
if (misc_temp_dev(bis->info->device, 1, &bis->device))
if (misc_temp_dev(bis->info->basedisks[0], 1, &bis->basetmp[0]))
return -1;
if (check_dump_device(job, bis->info, bis->device))
if (check_dump_device(job, bis->info, bis->basetmp[0]))
return -1;
printf("Building bootmap directly on partition '%s'%s\n",
bis->filename,
@@ -1545,6 +1529,8 @@ static int prepare_bootloader_device(struct job_data *job,
static int prepare_build_program_table_file(struct job_data *job,
struct install_set *bis)
{
int i;
if (bis->skip_prepare)
/* skip the preparation work */
return 0;
@@ -1565,21 +1551,18 @@ static int prepare_build_program_table_file(struct job_data *job,
* block size. */
if (disk_get_info_from_file(bis->filename, &job->target, &bis->info))
return -1;
/* Check for supported disk and driver types */
if (job->target.source == source_auto &&
bis->info->type == disk_type_diag) {
error_reason("Unsupported disk type (%s)",
disk_get_type_name(bis->info->type));
return -1;
}
if (!disk_is_appropriate(job, bis->info))
return -1;
if (verbose) {
printf("Target device information\n");
disk_print_info(bis->info, job->target.source);
}
if (misc_temp_dev(bis->info->device, 1, &bis->device))
return -1;
for (i = 0; i < job_get_nr_targets(job); i++) {
if (misc_temp_dev(bis->info->basedisks[i],
1,
&bis->basetmp[i]))
return -1;
}
/* Check configuration number limits */
if (job->id == job_menu) {
if (check_menu_positions(&job->data.menu, job->name,
@@ -1694,9 +1677,9 @@ static int prepare_bootloader_ngdump(struct job_data *job,
/* Retrieve target device information */
if (disk_get_info(job->data.dump.device, &job->target, &info))
return -1;
if (misc_temp_dev(info->device, 1, &bis->device))
if (misc_temp_dev(info->basedisks[0], 1, &bis->basetmp[0]))
return -1;
if (check_dump_device(job, info, bis->device))
if (check_dump_device(job, info, bis->basetmp[0]))
return -1;
assert(!job->target.bootmap_dir);
@@ -1802,7 +1785,7 @@ int prepare_bootloader(struct job_data *job, struct install_set *bis)
if (init_bis(job, bis))
return -1;
if (job->id == job_dump_partition) {
if (is_ngdump_enabled(job))
if (job_dump_is_ngdump(job))
return prepare_bootloader_ngdump(job, bis);
else
return prepare_bootloader_device(job, bis);
@@ -1818,7 +1801,7 @@ int prepare_bootloader(struct job_data *job, struct install_set *bis)
int post_install_bootloader(struct job_data *job, struct install_set *bis)
{
if (job->id == job_dump_partition) {
if (is_ngdump_enabled(job))
if (job_dump_is_ngdump(job))
return dry_run ? 0 : finalize_create_file(job, bis);
else
return 0;
@@ -1846,6 +1829,9 @@ void free_bootloader(struct install_set *bis)
if (bis->tmp_filename_created)
misc_free_temp_file(bis->filename);
free(bis->filename);
misc_free_temp_dev(bis->device);
for (i = 0; i < MAX_TARGETS; i++) {
if (bis->basetmp[i])
misc_free_temp_dev(bis->basetmp[i]);
}
disk_free_info(bis->info);
}

View File

@@ -92,14 +92,6 @@ disk_determine_dasd_type(struct disk_info *data,
return 0;
}
/* Return non-zero for ECKD type. */
static int
disk_is_eckd(disk_type_t type)
{
return (type == disk_type_eckd_ldl ||
type == disk_type_eckd_cdl);
}
static int
read_block_by_offset(int fd, int blksize, uint64_t offset, char *buffer)
{
@@ -187,43 +179,134 @@ out_err:
return rc;
}
/**
* Process a script output represented by FH and consisting
* of pairs 'key=value' (each such pair is on a separate line).
* Check its consistency and set the extracted target parameters
* to the array of "targets" at TD.
*
* NOTE: this function defines specifications on valid output of
* zipl helper scripts. See zipl-support-for-mirrored-devices.txt
* for details. Before modifying this function, make sure that it
* won't lead to format change.
*/
static int set_target_parameters(FILE *fh, struct job_target_data *td)
{
int checkparm = 0;
int idx[LAST_TARGET_PARAM] = {0};
struct target *t;
char buffer[80];
char value[40];
char *error;
int i;
/**
* Process a stream of 'key=value' pairs and distribute
* them into groups.
* The i-th occurrence of some "key" in the stream means
* that the respective pair belongs to the group #i
*/
error = "Exceeded the maximum number of base disks";
while (fgets(buffer, 80, fh)) {
if (sscanf(buffer, "targetbase=%s", value) == 1) {
td->targetbase = misc_strdup(value);
checkparm++;
t = target_at(td, idx[TARGET_BASE]++);
if (!t)
goto error;
t->targetbase = misc_strdup(value);
goto found;
}
if (sscanf(buffer, "targettype=%s", value) == 1) {
type_from_target(value, &td->targettype);
checkparm++;
t = target_at(td, idx[TARGET_TYPE]++);
if (!t)
goto error;
type_from_target(value, &t->targettype);
goto found;
}
if (sscanf(buffer, "targetgeometry=%s", value) == 1) {
td->targetcylinders =
atoi(strtok(value, ","));
td->targetheads = atoi(strtok(NULL, ","));
td->targetsectors = atoi(strtok(NULL, ","));
checkparm++;
t = target_at(td, idx[TARGET_GEOMETRY]++);
if (!t)
goto error;
t->targetcylinders = atoi(strtok(value, ","));
t->targetheads = atoi(strtok(NULL, ","));
t->targetsectors = atoi(strtok(NULL, ","));
goto found;
}
if (sscanf(buffer, "targetblocksize=%s", value) == 1) {
td->targetblocksize = atoi(value);
checkparm++;
t = target_at(td, idx[TARGET_BLOCKSIZE]++);
if (!t)
goto error;
t->targetblocksize = atoi(value);
goto found;
}
if (sscanf(buffer, "targetoffset=%s", value) == 1) {
td->targetoffset = atol(value);
checkparm++;
t = target_at(td, idx[TARGET_OFFSET]++);
if (!t)
goto error;
t->targetoffset = atol(value);
goto found;
}
continue;
found:
t->check_params++;
}
if ((!disk_is_eckd(td->targettype) && checkparm < 4) ||
(disk_is_eckd(td->targettype) && checkparm != 5)) {
error_reason("Target parameters missing from script");
return -1;
/* Check for consistency */
error = "Inconsistent script output";
/*
* First, calculate total number of groups
*/
td->nr_targets = 0;
for (i = 0; i < MAX_TARGETS; i++) {
t = target_at(td, i);
if (t->check_params == 0)
break;
td->nr_targets++;
}
if (!td->nr_targets)
/* No keywords found in the stream */
goto error;
/*
* Each group has to include targetbase, targettype,
* targetblocksize and targetoffset.
*/
if (td->nr_targets != idx[TARGET_BASE] ||
td->nr_targets != idx[TARGET_TYPE] ||
td->nr_targets != idx[TARGET_BLOCKSIZE] ||
td->nr_targets != idx[TARGET_OFFSET])
goto error;
/*
* In addition, any group of "ECKD" type has to include
* targetgeometry
*/
for (i = 0; i < td->nr_targets; i++) {
t = target_at(td, i);
assert(t->check_params >= 4);
if (disk_type_is_eckd(t->targettype) && t->check_params != 5)
goto error;
}
return 0;
error:
error_reason("%s", error);
return -1;
}
static void print_base_disk_params(struct job_target_data *td, int index)
{
disk_type_t type = get_targettype(td, index);
if (!verbose)
return;
{
fprintf(stderr, "Base disk '%s':\n", get_targetbase(td, index));
fprintf(stderr, " layout........: %s\n", disk_get_type_name(type));
}
if (disk_type_is_eckd(type)) {
fprintf(stderr, " heads.........: %u\n", get_targetheads(td, index));
fprintf(stderr, " sectors.......: %u\n", get_targetsectors(td, index));
fprintf(stderr, " cylinders.....: %u\n", get_targetcylinders(td, index));
}
{
fprintf(stderr, " start.........: %lu\n", get_targetoffset(td, index));
fprintf(stderr, " blksize.......: %u\n", get_targetblocksize(td, index));
}
}
/**
@@ -235,31 +318,57 @@ static int disk_set_info_by_hint(struct job_target_data *td,
{
int majnum, minnum;
struct stat stats;
int i;
/*
* Currently multiple base disks with different parameters
* are not supported
*/
data->devno = -1;
data->phy_block_size = td->targetblocksize;
data->type = td->targettype;
data->partnum = 0;
data->phy_block_size = get_targetblocksize(td, 0);
data->type = get_targettype(td, 0);
if (sscanf(td->targetbase, "%d:%d", &majnum, &minnum) == 2) {
data->device = makedev(majnum, minnum);
data->targetbase = defined_as_device;
data->partnum = minor(stats.st_rdev) - minnum;
} else {
if (stat(td->targetbase, &stats)) {
error_reason(strerror(errno));
error_text("Could not get information for "
"file '%s'", td->targetbase);
assert(td->nr_targets != 0);
for (i = 1; i < td->nr_targets; i++) {
if (data->type != get_targettype(td, i) ||
data->phy_block_size != get_targetblocksize(td, i)) {
print_base_disk_params(td, 0);
print_base_disk_params(td, i);
error_reason("Inconsistent base disk geometry in target device");
return -1;
}
if (!S_ISBLK(stats.st_mode)) {
error_reason("Target base device '%s' is not "
"a block device",
td->targetbase);
}
data->partnum = 0;
data->targetbase_def = undefined;
for (i = 0; i < td->nr_targets; i++) {
definition_t defined_as;
if (sscanf(get_targetbase(td, i),
"%d:%d", &majnum, &minnum) == 2) {
data->basedisks[i] = makedev(majnum, minnum);
defined_as = defined_as_device;
} else {
if (stat(get_targetbase(td, i), &stats)) {
error_reason(strerror(errno));
error_text("Could not get information for "
"file '%s'", get_targetbase(td, i));
return -1;
}
if (!S_ISBLK(stats.st_mode)) {
error_reason("Target base device '%s' is not "
"a block device",
get_targetbase(td, i));
return -1;
}
data->basedisks[i] = stats.st_rdev;
defined_as = defined_as_name;
}
if (data->targetbase_def != undefined &&
data->targetbase_def != defined_as) {
error_reason("Target base disks are defined by different ways");
return -1;
}
data->device = stats.st_rdev;
data->targetbase = defined_as_name;
data->targetbase_def = defined_as;
}
if (data->type == disk_type_scsi && ioctl(fd, NVME_IOCTL_ID) >= 0)
data->is_nvme = 1;
@@ -446,11 +555,28 @@ static int run_targetbase_script(struct job_target_data *td,
static int disk_set_geometry_by_hint(struct job_target_data *td,
struct disk_info *data)
{
data->geo.heads = td->targetheads;
data->geo.sectors = td->targetsectors;
data->geo.cylinders = td->targetcylinders;
data->geo.start = td->targetoffset;
int i;
/*
* Currently multiple base disks with different parameters
* are not supported
*/
data->geo.heads = get_targetheads(td, 0);
data->geo.sectors = get_targetsectors(td, 0);
data->geo.cylinders = get_targetcylinders(td, 0);
data->geo.start = get_targetoffset(td, 0);
assert(td->nr_targets != 0);
for (i = 1; i < td->nr_targets; i++) {
if (data->geo.heads != get_targetheads(td, i) ||
data->geo.sectors != get_targetsectors(td, i) ||
data->geo.cylinders != get_targetcylinders(td, i) ||
data->geo.start != get_targetoffset(td, i)) {
print_base_disk_params(td, 0);
print_base_disk_params(td, i);
error_reason("Inconsistent base disk geometry in target device");
return -1;
}
}
return 0;
}
@@ -483,7 +609,7 @@ static int disk_set_info_complete(struct job_target_data *td,
return -1;
}
/* Check for valid CHS geometry data. */
if (disk_is_eckd(data->type) && (data->geo.cylinders == 0 ||
if (disk_type_is_eckd(data->type) && (data->geo.cylinders == 0 ||
data->geo.heads == 0 || data->geo.sectors == 0)) {
error_reason("Invalid disk geometry (CHS=%d/%d/%d)",
data->geo.cylinders, data->geo.heads,
@@ -515,14 +641,16 @@ static int disk_set_info_complete(struct job_target_data *td,
}
/**
* Prepare INFO required to perform IPL installation on the physical
* disk where the logical DEVICE is located.
* Prepare INFO required to perform IPL installation on physical disks
* participating in the logical DEVICE.
* Preparation is performed in 2 steps:
*
* 1. Find out a physical "base" disk where the logical DEVICE is
* located. Calculate "target" parameters (type, geometry, physical
* block size, data offset, etc);
* 2. Complete INFO by the found base disk and target parameters.
* 1. Find out a set of physical "base" disks participating in the
* logical DEVICE. For each found disk calculate "target" parameters
* (type, geometry, physical block size, data offset, etc) and store
* it in the array of "targets" of TD;
* 2. Complete INFO using the found base disks and calculated target
* parameters.
*
* TD: optionally contains target parameters specified by user via
* config file, or special "target options" of zipl tool.
@@ -569,6 +697,7 @@ int disk_get_info(const char *device, struct job_target_data *td,
goto error;
if (disk_set_info_by_hint(td, data, fd))
goto error;
data->device = stats.st_rdev;
break;
case source_user:
/*
@@ -581,6 +710,12 @@ int disk_get_info(const char *device, struct job_target_data *td,
goto error;
if (disk_set_info_by_hint(td, data, fd))
goto error;
/*
* multiple base disks are not supported
* with this source type
*/
assert(td->nr_targets == 1);
data->device = data->basedisks[0];
break;
case source_auto:
/* no ready target parameters are available */
@@ -588,6 +723,12 @@ int disk_get_info(const char *device, struct job_target_data *td,
goto error;
if (disk_set_info_auto(data, &stats, fd))
goto error;
/*
* multiple base disks are not supported
* with this source type
*/
data->basedisks[0] = data->device;
td->nr_targets = 1;
break;
default:
assert(0);
@@ -620,45 +761,48 @@ disk_is_tape(const char* device)
return rc;
}
int
disk_is_scsi(const char* device, struct job_target_data* target)
{
struct disk_info* info;
int rc = 0;
if (disk_get_info(device, target, &info) == -1)
return 0;
if (info->type == disk_type_scsi)
rc = 1;
disk_free_info(info);
return rc;
}
int disk_is_eckd_ldl(const char *device, struct job_target_data *target)
/**
* Get "extended type" of base disk by logical DEVICE
*
* This function may fail for various reasons. E.g. in case when
* DEVICE is not eligible for boot record installation (not a
* partition, etc). In case of success the resulted disk type is
* stored in EXT_TYPE.
*/
int disk_get_ext_type(const char *device, struct disk_ext_type *ext_type)
{
struct job_target_data tmp = {.source = source_unknown};
struct disk_info *info;
int rc = 0;
if (disk_get_info(device, target, &info) == -1)
return 0;
if (info->type == disk_type_eckd_ldl)
rc = 1;
if (disk_get_info(device, &tmp, &info))
return -1;
ext_type->type = info->type;
ext_type->is_nvme = info->is_nvme;
disk_free_info(info);
return rc;
free_target_data(&tmp);
return 0;
}
int
disk_is_nvme(const char* device, struct job_target_data* target)
int disk_type_is_scsi(struct disk_ext_type *ext_type)
{
struct disk_info* info;
int rc = 0;
return ext_type->type == disk_type_scsi;
}
if (disk_get_info(device, target, &info) == -1)
return 0;
if (info->type == disk_type_scsi && info->is_nvme)
rc = 1;
disk_free_info(info);
return rc;
int disk_type_is_eckd_ldl(struct disk_ext_type *ext_type)
{
return ext_type->type == disk_type_eckd_ldl;
}
int disk_type_is_nvme(struct disk_ext_type *ext_type)
{
return ext_type->is_nvme;
}
int disk_type_is_eckd(disk_type_t type)
{
return (type == disk_type_eckd_ldl ||
type == disk_type_eckd_cdl);
}
int
@@ -943,6 +1087,33 @@ disk_print_devt(dev_t d)
printf("%02x:%02x", major(d), minor(d));
}
void disk_print_devname(dev_t dev)
{
struct util_proc_part_entry part_entry;
if (!util_proc_part_get_entry(dev, &part_entry)) {
printf("%s", part_entry.name);
util_proc_part_free_entry(&part_entry);
} else {
disk_print_devt(dev);
}
}
void prepare_footnote_ptr(int source, char *ptr)
{
if (source == source_user || source == source_script)
strcpy(ptr, " *)");
else
strcpy(ptr, "");
}
void print_footnote_ref(int source, const char *prefix)
{
if (source == source_user)
printf("%s*) Data provided by user.\n", prefix);
else if (source == source_script)
printf("%s*) Data provided by script.\n", prefix);
}
/* Return a name for a given disk TYPE. */
char *
@@ -994,12 +1165,11 @@ disk_is_large_volume(struct disk_info* info)
void disk_print_info(struct disk_info *info, int source)
{
char footnote[4] = "";
if (source == source_user || source == source_script)
strcpy(footnote, " *)");
prepare_footnote_ptr(source, footnote);
printf(" Device..........................: ");
disk_print_devt(info->device);
if (info->targetbase == defined_as_device)
if (info->targetbase_def == defined_as_device)
printf("%s", footnote);
printf("\n");
if (info->partnum != 0) {
@@ -1010,7 +1180,7 @@ void disk_print_info(struct disk_info *info, int source)
if (info->name) {
printf(" Device name.....................: %s",
info->name);
if (info->targetbase == defined_as_name)
if (info->targetbase_def == defined_as_name)
printf("%s", footnote);
printf("\n");
}
@@ -1030,7 +1200,7 @@ void disk_print_info(struct disk_info *info, int source)
(info->partnum != 0) ? "partition" : "device");
printf(" Disk layout.....................: %s%s\n",
disk_get_type_name(info->type), footnote);
if (disk_is_eckd(info->type)) {
if (disk_type_is_eckd(info->type)) {
printf(" Geometry - heads................: %d%s\n",
info->geo.heads, footnote);
printf(" Geometry - sectors..............: %d%s\n",
@@ -1053,21 +1223,7 @@ void disk_print_info(struct disk_info *info, int source)
info->phy_block_size, footnote);
printf(" Device size in physical blocks..: %ld\n",
(long) info->phy_blocks);
if (source == source_user)
printf(" *) Data provided by user.\n");
if (source == source_script)
printf(" *) Data provided by script.\n");
}
/* Print textual representation of geo structure. */
void
disk_print_geo(struct disk_info *data)
{
printf(" geo.heads.........:%u\n", data->geo.heads);
printf(" geo.sectors.......:%u\n", data->geo.sectors);
printf(" geo.cylinders.....:%u\n", data->geo.cylinders);
printf(" geo.start.........:%lu\n", data->geo.start);
printf(" blksize...........:%u\n", data->phy_block_size);
print_footnote_ref(source, " ");
}
/* Check whether a block is a zero block which identifies a hole in a file.

View File

@@ -434,11 +434,14 @@ int install_bootloader(struct job_data *job, struct install_set *bis)
{
disk_blockptr_t *scsi_dump_sb_blockptr = &bis->scsi_dump_sb_blockptr;
struct disk_info *info = bis->info;
char *device = bis->device;
int fd, rc;
char footnote[4];
int rc;
int i;
if (!info)
return 0;
prepare_footnote_ptr(job->target.source, footnote);
/* Inform user about what we're up to */
printf("Preparing boot device for %s%s: ",
disk_get_ipl_type(info->type,
@@ -455,40 +458,58 @@ int install_bootloader(struct job_data *job, struct install_set *bis)
disk_print_devt(info->device);
printf(".\n");
}
/* Open device file */
fd = open(device, O_RDWR);
if (fd == -1) {
error_reason(strerror(errno));
error_text("Could not open temporary device file '%s'",
device);
return -1;
}
/* Ensure that potential cache inconsistencies between disk and
* partition are resolved by flushing the corresponding buffers. */
if (!dry_run) {
if (ioctl(fd, BLKFLSBUF)) {
fprintf(stderr, "Warning: Could not flush disk "
"caches.\n");
}
}
/*
* Depending on disk type, install one or two program tables
* for CCW-type IPL and (or) for List-Directed IPL (see the
* picture in comments above)
*/
if (job->id == job_dump_partition) {
rc = install_bootloader_dump(bis->tables, info,
scsi_dump_sb_blockptr,
is_ngdump_enabled(job),
fd);
} else {
rc = install_bootloader_ipl(bis->tables, info, fd);
}
/* Install independently on each physical target base */
if (fsync(fd))
error_text("Could not sync device file '%s'", device);
if (close(fd))
error_text("Could not close device file '%s'", device);
for (i = 0; i < job_get_nr_targets(job); i++) {
int fd;
if (verbose) {
printf("Installing on base disk: ");
disk_print_devname(info->basedisks[i]);
printf("%s.\n", footnote);
}
/* Open device file */
fd = open(bis->basetmp[i], O_RDWR);
if (fd == -1) {
error_reason(strerror(errno));
error_text("Could not open temporary device file '%s'",
bis->basetmp[i]);
return -1;
}
/* Ensure that potential cache inconsistencies between disk and
* partition are resolved by flushing the corresponding buffers.
*/
if (!dry_run) {
if (ioctl(fd, BLKFLSBUF)) {
fprintf(stderr, "Warning: Could not flush disk "
"caches.\n");
}
}
/*
* Depending on disk type, install one or two program tables
* for CCW-type IPL and (or) for List-Directed IPL (see the
* picture in comments above)
*/
if (job->id == job_dump_partition) {
rc = install_bootloader_dump(bis->tables, info,
scsi_dump_sb_blockptr,
job_dump_is_ngdump(job),
fd);
} else {
rc = install_bootloader_ipl(bis->tables, info,
fd);
}
if (fsync(fd))
error_text("Could not sync device file '%s'",
bis->basetmp[i]);
if (close(fd))
error_text("Could not close device file '%s'",
bis->basetmp[i]);
if (rc)
break;
}
if (verbose)
print_footnote_ref(job->target.source, "");
if (!dry_run && rc == 0) {
if (info->devno >= 0)

View File

@@ -369,11 +369,13 @@ get_command_line(int argc, char* argv[], struct command_line* line)
return 0;
}
void free_target_data(struct job_target_data *data)
{
int i;
free(data->bootmap_dir);
free(data->targetbase);
for (i = 0; i < data->nr_targets; i++)
free(get_targetbase(data, i));
}
static void
@@ -1345,6 +1347,27 @@ type_from_target(char *target, disk_type_t *type)
}
}
int set_targettype(struct job_target_data *data, int index, char *value)
{
return type_from_target(value,
&target_at(data, index)->targettype);
}
int job_set_targettype(struct job_data *job, char *value)
{
return set_targettype(&job->target, 0, value);
}
static int job_set_target(struct job_data *job, char *value)
{
job_set_targetbase(job, value);
if (!job_get_targetbase(job))
return -1;
job_set_nr_targets(job, 1);
job->target.source = source_user;
return 0;
}
static int
get_job_from_section_data(char* data[], struct job_data* job, char* section)
{
@@ -1361,32 +1384,28 @@ get_job_from_section_data(char* data[], struct job_data* job, char* section)
return -1;
/* Fill in target */
if (data[(int) scan_keyword_targetbase] != NULL) {
job->target.targetbase =
misc_strdup(data[(int)
scan_keyword_targetbase]);
if (job->target.targetbase == NULL)
if (job_set_target(job, misc_strdup(data[(int)
scan_keyword_targetbase])))
return -1;
job->target.source = source_user;
}
if (data[(int) scan_keyword_targettype] != NULL) {
if (type_from_target(
data[(int) scan_keyword_targettype],
&job->target.targettype))
if (job_set_targettype(job,
data[(int) scan_keyword_targettype]))
return -1;
}
if (data[(int) scan_keyword_targetgeometry] != NULL) {
job->target.targetcylinders =
job_set_targetcylinders(job,
atoi(strtok(data[(int)
scan_keyword_targetgeometry], ","));
job->target.targetheads = atoi(strtok(NULL, ","));
job->target.targetsectors = atoi(strtok(NULL, ","));
scan_keyword_targetgeometry], ",")));
job_set_targetheads(job, atoi(strtok(NULL, ",")));
job_set_targetsectors(job, atoi(strtok(NULL, ",")));
}
if (data[(int) scan_keyword_targetblocksize] != NULL)
job->target.targetblocksize =
atoi(data[(int) scan_keyword_targetblocksize]);
job_set_targetblocksize(job,
atoi(data[(int) scan_keyword_targetblocksize]));
if (data[(int) scan_keyword_targetoffset] != NULL)
job->target.targetoffset =
atol(data[(int) scan_keyword_targetoffset]);
job_set_targetoffset(job,
atol(data[(int) scan_keyword_targetoffset]));
/* Fill in name and address of image file */
job->data.ipl.common.image = misc_strdup(
@@ -1614,37 +1633,32 @@ get_menu_job(struct scan_token* scan, char* menu, struct job_data* job)
return -1;
break;
case scan_keyword_targetbase:
job->target.targetbase = misc_strdup(
scan[i].content.keyword.value);
if (job->target.targetbase == NULL)
if (job_set_target(job, misc_strdup(
scan[i].content.keyword.value)))
return -1;
job->target.source = source_user;
break;
case scan_keyword_targettype:
if (type_from_target(
scan[i].content.keyword.value,
&job->target.targettype))
if (job_set_targettype(job,
scan[i].content.keyword.value))
return -1;
break;
case scan_keyword_targetgeometry:
job->target.targetcylinders =
job_set_targetcylinders(job,
atoi(strtok(
scan[i].content.keyword.value,
","));
job->target.targetheads =
atoi(strtok(NULL, ","));
job->target.targetsectors =
atoi(strtok(NULL, ","));
",")));
job_set_targetheads(job,
atoi(strtok(NULL, ",")));
job_set_targetsectors(job,
atoi(strtok(NULL, ",")));
break;
case scan_keyword_targetblocksize:
job->target.targetblocksize =
atoi(
scan[i].content.keyword.value);
job_set_targetblocksize(job, atoi(
scan[i].content.keyword.value));
break;
case scan_keyword_targetoffset:
job->target.targetoffset =
atol(
scan[i].content.keyword.value);
job_set_targetoffset(job, atol(
scan[i].content.keyword.value));
break;
default:
/* Should not happen */
@@ -2043,10 +2057,18 @@ job_get(int argc, char* argv[], struct job_data** data)
return rc;
}
bool
is_ngdump_enabled(struct job_data *job)
void job_dump_check_set_ngdump(struct job_data *job,
struct disk_ext_type *ext_type)
{
if (job->is_ldipl_dump)
return true;
return disk_is_nvme(job->data.dump.device, &job->target);
assert(job->id == job_dump_partition);
if (job->is_ldipl_dump || disk_type_is_nvme(ext_type))
job->data.dump.is_ngdump = true;
}
bool job_dump_is_ngdump(struct job_data *job)
{
assert(job->id == job_dump_partition);
return job->data.dump.is_ngdump;
}

View File

@@ -128,6 +128,7 @@ check_for_root(void)
int
main(int argc, char* argv[])
{
struct disk_ext_type ext_type = {0};
struct install_set bis;
struct job_data* job;
int rc;
@@ -173,9 +174,18 @@ main(int argc, char* argv[])
/* Do it */
switch (job->id) {
case job_dump_partition:
if (!is_ngdump_enabled(job) &&
rc = disk_get_ext_type(job->data.dump.device, &ext_type);
if (rc)
break;
job_dump_check_set_ngdump(job, &ext_type);
if (!job_dump_is_ngdump(job) &&
(disk_is_tape(job->data.dump.device) ||
!disk_is_scsi(job->data.dump.device, &job->target))) {
!disk_type_is_scsi(&ext_type))) {
if (dry_run) {
error_text("Option '--dry-run' is not implemented for this type of dump");
rc = -1;
break;
}
rc = install_dump(job->data.dump.device, &job->target,
job->data.dump.mem, job->data.dump.no_compress);
break;
@@ -187,8 +197,8 @@ main(int argc, char* argv[])
rc = -1;
break;
}
if (is_ngdump_enabled(job)) {
if (disk_is_eckd_ldl(job->data.dump.device, &job->target)) {
if (job_dump_is_ngdump(job)) {
if (disk_type_is_eckd_ldl(&ext_type)) {
error_reason("List-directed dump on ECKD with LDL not supported");
rc = -1;
break;

File diff suppressed because it is too large Load Diff

View File

@@ -908,7 +908,7 @@ static const struct util_opt configure_options[] = {
"server's certificate. For self signed EKMF Web server "
"certificates, this is the default. Use option "
"'--tls-pin-server-cert' to ensure the self signed "
"certificate's authenticity explicitely. CA signed "
"certificate's authenticity explicitly. CA signed "
"EKMF Web server certificates are verified by default. "
"This option disables the verification.",
.command = KMS_COMMAND_CONFIGURE,

View File

@@ -1382,7 +1382,7 @@ static int _keystore_lock_repository(struct keystore *keystore)
if (fchown(keystore->lock_fd, geteuid(),
keystore->owner) != 0) {
rc = -errno;
warnx("chown faild on file '%s': %s", lock_file_name,
warnx("chown failed on file '%s': %s", lock_file_name,
strerror(-rc));
return rc;
}

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