Compare commits

..

186 Commits

Author SHA1 Message Date
Jan Höppner
04407d24fc New release s390-tools-2.19.0
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-11-10 17:05:37 +01:00
Jan Höppner
bcb8ea09d1 lshwc: Fix compile error for gcc <8.1
With gcc < 8.1 the following compile error occurs:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Supported keys are:

  ZDEV_NEST_LEVEL=n
    Virtualization nesting level of running system

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

This will be used by a later patch.

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

This will be used by a later patch.

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

This fixes the following segmentation fault:

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

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

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

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

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

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

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

AFL +  ASAN findings:

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

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

valgrind findings:

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

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

This problem was found with AFL fuzzing and ASAN.

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

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

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

This bug was found with AFL fuzzing and ASAN.

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

[snip]

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

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

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

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

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

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

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

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

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

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

clang's static code analyzer reports the following problem:

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

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

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

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

This issue was found with AFL fuzzing.

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

Memory map:
  0000000000000000 - 00000000000f423f (1 MB)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

util_sysdir();
util_sysdir_path()

and their special cases supplied for users:

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

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

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

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

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

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

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

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

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

i.e the current lscss shows

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

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

With this patch,

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

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

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

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

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

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

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

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

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

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

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

Examples:
$ lszfcp -He
0.0.194a host3 linkdown

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

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

The TELA test dump_with_zero_sized_segments.sh can reproduce this bug.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-27 11:46:39 +02:00
Jan Höppner
fe5753d34d Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-27 11:46:39 +02:00
Jan Höppner
fe187eb3d3 New release s390-tools-2.17.0
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 15:18:51 +02:00
Jan Höppner
4a8afd4ed6 README.md: Add lshwc description
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 15:18:51 +02:00
Jan Höppner
74e6ebe1df libdasd: Free memory for previously used sysfs path
util_path_sysfs() allocates memory for the created path which must be
freed by the user.

Fixes: 8023a72b11 ("libdasd: Provide function to read ese sysfs attribute")
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 14:02:13 +02:00
Ingo Franzki
ec83da3a39 zkey-kmip: Add man page for the KMIP plugin
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 14:02:13 +02:00
Ingo Franzki
c11b0cdcaa zkey-kmip: List and import keys managed by KMIP
List (find) and import a key that exists in a KMIP server into the zkey
repository. Retrieve the key attributes of a key stored in a KMIP server,
and extract the zkey properties from it.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 14:02:13 +02:00
Ingo Franzki
4f3cba406e zkey-kmip: Remove keys and optionally set its state in KMIP
When a key is removed from the zkey repository, it is usually not removed
from the KMIP server. Optionally, the state of a KMIP key can be changed
when it is removed by zkey.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 14:02:13 +02:00
Ingo Franzki
c55ac2c016 zkey-kmip: Set properties of an existing key
Change the attributes of a key at the KMIP server when the properties
of a key are changed in zkey.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 14:01:49 +02:00
Ingo Franzki
4eab80ef44 zkey-kmip: Generate keys in the KMIP server and retrieve them
Allow to generate a new AES key at the KMIP server, and retrieved it.
Keys are always retrieved in wrapped format, wrapped by the public RSA
wrapping key used by the KMIP plugin. The KMIP plugin can then unwrap
the retrieved key with its secure private RSA key, and can then import
the retrieved AES key into the zkey repository as secure key. That way,
the retrieved AES key is never in clear, once it leaves the KMIP server.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 13:53:06 +02:00
Ingo Franzki
41ddd35bc1 zkey-kmip: Re-encipher identity and wrapping keys on MK change
When the master keys of the configured APQNs are changed, the secure
identity key as well as the secure wrapping key must be re-enciphered.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 13:53:06 +02:00
Ingo Franzki
bdc44cafb6 zkey-kmip: Generate and register wrapping key
Keys retrieved from a KMIP server are wrapped with an RSA key. The
RSA wrapping key is a secure key generated by the KMIP plugin. The
public RSA key is registered at the KMIP server, and the KMIP server
can then wrap the keys with it. The KMIP plugin can unwrap the retrieved
key with the private RSA key and import it as secure key into the zkey
repository.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 13:53:06 +02:00
Ingo Franzki
46583b4db6 zkey-kmip: Configure connection to KMIP server
Configure a connection to a KMIP server, establish trust between
server and client, query the KMIP server and verify if it supports
the required KMIP operations. Also, the profile to be used with this
KMIP server is tried to matched. If not specified in the profile,
the KMIP protocol version to be used is discovered.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 13:53:06 +02:00
Ingo Franzki
a2359dbe5f zkey-kmip: Add support for KMIP server profiles
KMIP server profiles (not to be confused with profiles defined by
the KMIP standard) define how the KMIP plugin talks to the KMIP
server. Profiles can be used to configure certain KMIP usages for
certain KMIP servers.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 13:53:06 +02:00
Ingo Franzki
52b6e57743 zkey: Allow comments and empty lines in properties files
Lines with '#' as first character are treated as comments, and are
skipped. Empty lines are also skipped.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 13:53:06 +02:00
Ingo Franzki
b1997c7aac zkey-kmip: Generate CSR or self signed certificate
For the client certificate to authenticate with the KMIP server,
a certificate signing request (CSR) or self signed certificate can be
generated. The generated CSR or certificate is signed with the secure
identity key of the KMIP plugin.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 13:53:06 +02:00
Ingo Franzki
c56aea0fa9 zkey-kmip: Generate an secure identity key
Authentication with KMIP servers is based on TLS client authentication.
To establish trust between zkey and the KMIP server, a client certificate
must be registered with the KMIP server before a client can communicate
with it.

The signature key of the client's certificate is a secure key created by
zkey. It can either be an RSA or an ECC key, using either CCA or EP11
type crypto adapters configured with the KMIP plugin.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 13:53:06 +02:00
Ingo Franzki
e24629b977 zkey-kmip: Configure APQNs
The KMIP plugin supports CCA and EP11 APQNs, but only it can only be
configured with one type. Once configured with one type of APQN, it accepts
only APQNs of the same type.

It supports key types matching to the APQn type it is configured with.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 13:53:06 +02:00
Ingo Franzki
268dcebe23 zkey-kmip: Add new zkey KMS plugin for KMIP
Add support to integrate the external key management systems based
on the KMIP protocol (KMIP: OASIS Key Management Interoperability
Protocol) into zkey by providing a zkey KMS plugin for KMIP. The
plugin communicates with KMIP servers using libkmipclient over a
TLS or HTTPS connection.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 13:53:06 +02:00
Ingo Franzki
030c0054b1 zkey-ekmfweb: Move some functions used by multiple KMS plugins to common code
Some functions are likely to be used by multiple plugins. Move them
into zkey common code (plugin-utils.c), this module is then linked
into the plugins.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 13:53:06 +02:00
Ingo Franzki
154914ee7a zkey: Allow KMS plugin to import a key of a specific type
KMS plugins that support multiple key types need to know which
key type to produce with the kms_import_key() function. Extend
the plugin API to allow a plugin to provide a kms_import_key2()
function, that accepts the key type as additional parameter.

Existing plugins do not need to be changed, as the old function
kms_import_key() still exists, and is still used when the plugin
does not provide a kms_import_key2() function.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 13:53:06 +02:00
Ingo Franzki
56fecf1832 libkmipclient: Add KMIP client shared library
libkmipclient is a shared library that provides an KMIP client to
communicate with an KMIP server. KMIP stands for Key Management
Interoperability Protocol, and is an extensible communication protocol
that defines message formats for the manipulation of cryptographic
keys on a key management server.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 13:53:06 +02:00
Ingo Franzki
081499f355 zkey-ekmfweb: Fix deprecation warnings with OpenSSL 3.0
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 13:53:06 +02:00
Ingo Franzki
26c34a49b1 libekmfweb: Make use of the new libseckey
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 13:53:06 +02:00
Ingo Franzki
e70cde2c5d libseckey: Add a secure key library
The libseckey is a secure key library to perform secure key operations
with OpenSSL. It provides a framework to create OpenSSL PKEYs with a
secure key attached. Such a PKEY contains the public key parts in clear,
but the private key as secure key blob. Only the private key operations
are actually performed with the secure key, public key operations are
performed in software by OpenSSL. It supports CCA and EP11 secure
keys for RSA and ECC crypto operations.

Because many PKEY method related functions are deprecated since OpenSSL
3.0, two versions of the OpenSSL secure key support are needed. One (using
a PKEY method override) for OpenSSL 1.1.1, and another one (using an own
OpenSSL provider) for OpenSSL 3.0 and later. The desired implementation is
selected automatically at compile time, using OpenSSL version defines. The
interface of both implementations is the same, so a user does not need to
care which one is used.

Reviewed-by: Juergen Christ <jchrist@linux.ibm.com>
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 13:53:06 +02:00
Alexander Egorenkov
fff83fc116 hsavmcore: Let make create list of object files instead of hard-coding it
Use idiomatic make constructs.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 13:53:06 +02:00
Alexander Egorenkov
5a7d2a58c8 hsavmcore: Fix fuse dependency checking
all target should not depend on check_dep but only objects which
use fuse header.

This fixes issues with parallel build of hsavmcore.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reported-by: Ingo Franzki <ifranzki@linux.ibm.com>
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 13:53:04 +02:00
Alexander Egorenkov
89d25559e0 hsavmcore: Disable systemd support during build if systemd header not found
Check for systemd C header and disable systemd support even if HAVE_SYSTEMD
make variable is set to 1.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 13:49:57 +02:00
Alexander Egorenkov
49901079d4 common.mak: Introduce user-defined function check_header_prereq()
The new user-defined function allows to check for C headers in
make's conditional statements.

Example:

ifeq ($(call check_header_prereq,"systemd/sd-daemon.h"),yes)
  $(warning "systemd support enabled")
else
  $(warning "systemd support disabled")
endif

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-07 13:49:57 +02:00
Ingo Franzki
317384b5c9 libekmfweb: Ensure that libcurl supports the OpenSSL backend
The callback function used for CURLOPT_SSL_CTX_FUNCTION requires
that OpenSSL is used as SSL backend.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-05 13:57:06 +02:00
Marc Hartmayer
8db32a8cb9 genprotimg: add --(enable|disable)-pckmo flag
Add the genprotimg flags `--(enable|disable)-pckmo` flag to enable/disable the
support for PCKMO-encrypt-DEA/TDEA/AES/ECC-key functions.

Acked-by: Viktor Mihajlovski <mihajlov@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-05 13:57:06 +02:00
Marc Hartmayer
4cf73238fc genprotimg: allow PCKMO functions by default
Allow the PCKMO-encrypt-DEA/TDEA/AES/ECC-key functions to be used in a protected
virtualization guest by default.

Acked-by: Viktor Mihajlovski <mihajlov@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-05 13:57:06 +02:00
Marc Hartmayer
27120f2824 genprotimg: rename PV_CFLAG_NO_DECRYPTION to PV_PCF_NO_DECRYPTION
The new name reflects that it's a plaintext control flag. While at it, use a
left shift operation to calculate the value.

Acked-by: Viktor Mihajlovski <mihajlov@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-05 13:57:06 +02:00
Alexander Egorenkov
8f32a60c22 zipl: Use util_arch_hsa_maxsize() to compute address limit for kdump
The HSA size, which limits the address space in kdump case, is not constant
and depends on the underlying architecture.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-05 13:57:06 +02:00
Alexander Egorenkov
0fa2f9acf7 cpumf: Use helpers from util_arch
Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-05 13:57:06 +02:00
Alexander Egorenkov
2ca7db75d3 libutil: Introduce util_arch module
The util_arch module is supposed to provide general information about
the underlying architecture of the machine in use.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-05 13:57:06 +02:00
Ingo Franzki
02aaff72fa zkey: Use secure_getenv() instead of getenv() for all environment variables
... to avoid vulnerabilities that could occur if set-user-ID or
set-group-ID programs accidentally trusted the environment.

zkey is usually NOT a set-user-ID or set-group-ID program, but its
safer to use secure_getenv() anyway.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-05 13:57:06 +02:00
Marc Hartmayer
8723dbce04 genprotimg: add OpenSSL 3.0 support
Add OpenSSL 3.0 support while still supporting OpenSSL 1.1.0 and newer. For this
set the OPENSSL_API_COMPAT user defined macro to OpenSSL 1.1.0 (see
https://www.openssl.org/docs/manmaster/man7/OPENSSL_API_COMPAT.html) so we don't
see any deprecation warnings when using OpenSSL 3.0. In addition, add an
compatibility layer for OpenSSL since some OpenSSL API functions were constified
with OpenSSL 3.0.

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/112
Reviewed-by: Patrick Steuer <patrick.steuer@de.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-05 13:57:06 +02:00
Marc Hartmayer
c5d566a4da genprotimg/crypto: use X509_get0_not(After|Before)
Use X509_get0_not(After|Before) since X509_get_notBefore() and
X509_get_notAfter() were deprecated in OpenSSL 1.1.0 (see
https://www.openssl.org/docs/man1.1.0/man3/X509_set1_notBefore.html).

Github-ID: https://github.com/ibm-s390-linux/s390-tools/issues/112
Reviewed-by: Patrick Steuer <patrick.steuer@de.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-05 13:57:06 +02:00
Marc Hartmayer
d90344a2d5 genprotimg: check return value of BIO_reset
Add missing return value checks for BIO_reset. Unfortunately, the OpenSSL
documentation says:

"BIO_reset() normally returns 1 for success and 0 or -1 for failure. File BIOs
are an exception, they return 0 for success and -1 for failure."

Github-ID: https://github.com/ibm-s390-linux/s390-tools/issues/112
Reviewed-by: Patrick Steuer <patrick.steuer@de.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-05 13:57:06 +02:00
Marc Hartmayer
71a667fbf0 genprotimg: add missing return values
Fixes: 65b9fc442c ("genprotimg: introduce new tool for the creation of PV images")
Reviewed-by: Patrick Steuer <patrick.steuer@de.ibm.com>
Reviewed-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-05 13:57:06 +02:00
Alexander Egorenkov
d2611b472b gitignore: Ignore all example executables in libutil/
Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-05 13:57:06 +02:00
Alexander Egorenkov
34482d67c0 libutil: Refactor and clean up Makefile
Use idiomatic make constructs.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-05 13:57:00 +02:00
Alexander Egorenkov
b77523ab4d libutil: Fix typo in doxygen group of util_log
Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-05 13:55:54 +02:00
Jan Höppner
802e5f6607 libutil: Remove /proc/mount related functions
The only user of util_proc_mnt_get_entry() so far was util_path_sysfs().
With the simplified version there is no user left. Remove
util_proc_mnt_get_entry() and related code.

Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-05 13:55:54 +02:00
Jan Höppner
5e5d49264f libutil: Simplify util_path_sysfs and helper functions
Using util_path_sysfs always leaves 5 bytes of memory unfreed as the
value for the sysfs mount point is stored in a static variable to avoid
multiple queries of /proc/mount.

$ valgrind ./util_path_example sysfs
==3629315== Memcheck, a memory error detector
==3629315== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==3629315== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==3629315== Command: ./util_path_example sysfs
==3629315==
Path for    cpu: "/sys/devices/system/cpu"
Path for memory: "/sys/devices/system/memory"
==3629315==
==3629315== HEAP SUMMARY:
==3629315==     in use at exit: 5 bytes in 1 blocks
==3629315==   total heap usage: 22 allocs, 21 frees, 18,435 bytes allocated
==3629315==
==3629315== LEAK SUMMARY:
==3629315==    definitely lost: 0 bytes in 0 blocks
==3629315==    indirectly lost: 0 bytes in 0 blocks
==3629315==      possibly lost: 0 bytes in 0 blocks
==3629315==    still reachable: 5 bytes in 1 blocks
==3629315==         suppressed: 0 bytes in 0 blocks
==3629315== Rerun with --leak-check=full to see details of leaked memory
==3629315==
==3629315== For lists of detected and suppressed errors, rerun with: -s
==3629315== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

As per the Kernel rules for accessing sysfs information [1], searching
for the sysfs mount point is a waste of time and systems that don't have
sysfs mounted at /sys are considered broken.

With those things in mind, util_path_sysfs() and especially
sys_mount_point() can be simplified. sys_mount_point() will always
return '/sys' unless the environment variable SYSFS_ROOT is set.

With SYSFS_ROOT still being present, special container setups or test
case scenarios are still possible but might need to be modified if they
previously relied on util_path_sysfs() automatically finding the correct
sysfs mount point.

To make things more secure against malicious strings in SYSFS_ROOT,
secure_getenv() is being used and the ordering of creating the formatted
path string in util_path_sysfs() is changed slightly.

Furthermore, the static variable is removed as no complicated query of
the /proc fs is required anymore. Memory for the sysfs mount point value
is properly freed now at the end of util_path_sysfs().

[1] https://www.kernel.org/doc/html/latest/admin-guide/sysfs-rules.html
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-05 13:55:54 +02:00
Ingo Franzki
3e818c53b2 zconf/zcrypt: Fix sparse warnings
A compile with sparse (make C=1) shows a couple of warnings:
like:

  chzcrypt.c:36:3: warning: symbol 'l' was not declared.
  Should it be static?

  lszcrypt.c: In function 'show_device':
  lszcrypt.c:556:9: warning: 'card' may be used uninitialized
  [-Wmaybe-uninitialized]

Fix those warnings.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-05 13:55:54 +02:00
Ingo Franzki
9100d6f40e libutil/util_rec: Declare internal only functions static
A compile with sparse (make C=1) shows the following warnings:

  util_rec.c:211:6: warning: symbol 'rec_print_wide' was not declared.
  Should it be static?
  util_rec.c:383:6: warning: symbol 'rec_print_csv_hdr' was not declared.
  Should it be static?
  util_rec.c:404:6: warning: symbol 'rec_print_csv' was not declared.
  Should it be static?

These functions are only used internally from function util_rec_print_hdr(),
declare them as static.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-05 13:55:54 +02:00
Ingo Franzki
8bcb93673e libutil/util_opt: Remove unused global variables
A compile with sparse (make C=1) shows the following warnings:

  util_opt.c:42:19: warning: symbol 'util_opt_l' was not declared.
  Should it be static?
  util_prg.c:28:19: warning: symbol 'util_prg_l' was not declared.
  Should it be static?

util_opt_l and util_prg_l are not used anywhere, and also not declared in
any header file. Looks like they are superfluous, remove them.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-07-05 13:55:54 +02:00
Jan Höppner
21fe08ad23 gitignore: Add ctags files
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-06-18 13:20:08 +02:00
Alexander Egorenkov
f8d3e5069a hsavmcore: add dracut modules and systemd services for kdump initramfs
* Provide a dracut module and a systemd service for Fedora, RHEL and SLES.
* Provide a systemd service for Ubuntu.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-06-18 13:20:08 +02:00
Alexander Egorenkov
9fb2568134 hsavmcore: add man pages for hsavmcore and hsavmcore.conf
Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-06-18 13:20:08 +02:00
Alexander Egorenkov
a38d82e8f9 hsavmcore: add hsavmcore.conf example
Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-06-18 13:20:08 +02:00
Alexander Egorenkov
8c9cc6e12a s390-tools: add hsavmcore utility
hsavmcore is designed to make the dump process with kdump more efficient.
With hsavmcore, the HSA memory that contains a part of the production
kernel's memory can be released early in the process. Depending on the size
of the production kernel's memory, writing the dump to persistent storage
can be time consuming and prevent the HSA memory from being reused
by other LPARs.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-06-18 13:20:08 +02:00
Ingo Franzki
ce8383e5ac zkey: Fix conversion of CCA DATA keys to CCA CIPHER keys
The CCA Key Translate2 verb needs a pre-built AES CIPHER key token skeleton
with XPRTCPAC set in the output buffer, to produce an AES CIPHER key
that can be exported to CAPCF.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-06-18 13:20:08 +02:00
Jan Höppner
9696b4c9b5 gitignore: Add lshwc binary
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-06-18 13:20:08 +02:00
Ingo Franzki
466ceb02a1 libekmfweb: Fix certificate extensions compare function
Correctly dereference the extensions passed to the compare function.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-06-18 13:20:08 +02:00
Alexander Egorenkov
f6ab7f6cda libutil: Add an example for util_log
Build:
$ make -C libutil/util_log_example

* Every time a -V option is passed, the verbosity level increases and extra
messages are enabled.

Test:
$ ./libutil/util_log_example
 # No output
$ ./libutil/util_log_example -V
ERROR: This is an ERROR message
$ ./libutil/util_log_example -VV
ERROR: This is an ERROR message
 WARN: This is a WARN message
$ ./libutil/util_log_example -VVV
ERROR: This is an ERROR message
 WARN: This is a WARN message
 INFO: This is an INFO message
$ ./libutil/util_log_example -VVVV
ERROR: This is an ERROR message
 WARN: This is a WARN message
 INFO: This is an INFO message
DEBUG: This is a DEBUG message
$ ./libutil/util_log_example -VVVVV
ERROR: This is an ERROR message
 WARN: This is a WARN message
 INFO: This is an INFO message
DEBUG: This is a DEBUG message
TRACE: This is a TRACE message

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-06-18 13:20:08 +02:00
Alexander Egorenkov
568caa0501 libutil: Introduce multi-level message logging
The goal of util_log is to provide a facility for a multi-level message
logging on stderr. This allows to selectively enable/disable log messages
via a log level which can be adjusted at runtime.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-06-18 13:20:08 +02:00
Stefan Haberland
2ece47ee1a zdsfs: fix out of bound access in config file parsing
The tmp buffer is one byte too short missing space for the final \0 byte
leading to out of bound access.
Fix by increasing the buffer by one.

Reported-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-05-21 12:24:27 +02:00
Stefan Haberland
0fafbcf3bb zdsfs: add dataset conversion to manpage
Update zdsfs manpage to include information about dataset conversion.

Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-05-21 12:24:27 +02:00
Stefan Haberland
7244785279 zdsfs: transparent codepage conversion
Add transparent codepage conversion feature to zdsfs.
Add options to specify that codepage conversion should be done using
default codepages from 'CP1047' to 'UTF-8' or using user defined codepage
tables.
Also add a new config file allowing the user to specify codepage conversion
options on a per dataset basis.

When a dataset is opened and codepage conversion settings match this
dataset an iconv handle is created and the conversion itself is performed
by the lzds_dshandle_read() function.

Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-05-21 12:23:57 +02:00
Stefan Haberland
cdf716a7a9 libzds: add codepage conversion
Add codepage conversion capabilities to libzds.
Whenever a dataset is read and an appropriate iconv handle is set for the
dataset the conversion is automatically performed.

Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-05-21 12:21:09 +02:00
Thomas Richter
529ad4000e cpumf/lscpumf.c: Replace function linux_error by err/warn
Replace function linux_error() by err/warn family.
Delete function linux_error() which is not used anymore.
Also fix some checkpatch warnings regarding comparison to zero.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-05-20 18:50:53 +02:00
Thomas Richter
0772c0f01b cpumf/chcpumf: Simplify function read_sfb
Simplify function read_sfb(). Convert it to type void
and return only when no errors occurred.
On error print error message and exit instead of return.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-05-20 18:50:53 +02:00
Thomas Richter
27a562da0a cpumf/lshwc: Program to extract complete counter sets
Program reads complete counter sets from any CPU by opening
device /dev/hwctr which is available with linux version 5.12.
The counter sets and CPUs can be specified on the command line.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Reviewed-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-05-20 18:50:48 +02:00
Thomas Richter
cd532cb6cd cpumf/chcpumf: Replace linux_error by err/warn
Replace function linux_error() by err/warn functions.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Reviewed-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-05-20 18:49:45 +02:00
Thomas Richter
80b1306102 cpumf/chcpumf: Replace fprintf to stderr by err/warn
Replace fprintf(stderr,...) by warnx and errx.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Reviewed-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-05-20 18:49:45 +02:00
Stefan Haberland
4b0403a963 zdsfs: improve man page for coordinated read access
Incorporate some ID feedback.

Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-05-20 18:49:44 +02:00
Thomas Richter
1d9e7b614c cpumf/chcpumf: Use util_opt_print_parse_error function
Use function util_opt_print_parse_error() instead of fprintf to stderr.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-05-20 18:49:44 +02:00
Thomas Richter
44de579311 cpumf/chcpumf: Simplify comparison against 0
Simplify comparison against 0 or NULL and fix a checkpatch.pl
warning.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-05-20 18:49:44 +02:00
Wenjia Zhang
4fb18a1e7b znetconf: avoid conflict with "chzdev -e"
Using "chzdev -e" to configurate a device persistently, the
corresponding udev rule is also created, which will trigger a uevent
that sets the device online as soon as the group device is created.

If 'znetconf -r/R' is first used to remove such a configured device
(which won't remove the corresponding udev rule) and then
'znetconf -a/A' afterwards on the same device, either the error
"Failed to make <device> online" or "Failed to configure layer2=1"
will occur.

For the first error, the udev queue might not have been fully processed
and hence the check whether a device is online may fail due to that
race. Call 'udevadm settle' to ensure a fully processed queue before
checking whether a device is online.

The second error occurs, because configure_ccwgroupdev_option() does
not check whether the device is online. Add the check and set the
device offline if necessary. Also, log any details for debugging
purposes.

Signed-off-by: Wenjia Zhang <wenjia@linux.ibm.com>
Reviewed-by: Alexandra Winter <wintera@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-05-20 18:49:44 +02:00
Thomas Richter
59206b88d8 cpumf/lscpumf: Use util_opt_print_parse_error function
Use function util_opt_print_parse_error() instead of
fprintf to stdout.

Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-05-20 18:49:44 +02:00
Thomas Richter
7a64b88396 cpumf/lscpumf: Use warnx instead of fprintf
Use function warnx() instead of fprintf() to stderr.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-05-20 18:49:44 +02:00
Siglen
b7807d0195 dbginfo.sh: Add KVM commands and rework data collection
Add virsh commands for KVM debug data collection and rework the domain
data collection and step numbering. Update the man page accordingly.

[hoeppner@linux.ibm.com: Reword commit message]
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-05-20 18:49:44 +02:00
Siglen
2f436d6ee0 CHANGELOG.md: Add dbginfo changes
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-05-20 18:49:44 +02:00
Siglen
302cd4ed7e dbginfo.sh: fix typo
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-05-20 18:49:44 +02:00
Jan Höppner
69526998f0 libdasd: Check return value for util_file_read_l
The return code of util_file_read_l() isn't checked and therefore
'value' could contain anything in case of an error. Check the return
code and set 'value' to 0 in the error case.

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/110
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-05-20 18:49:44 +02:00
Stefan Haberland
a65bc51cf4 udev/dasd: change DASD udev-rule to set none scheduler
Performance evaluation showed that using the mq-deadline scheduler for DASD
devices leads to a significantly higher CPU consumption compared to using
none scheduler while having the same amount of throughput.
Setting none scheduler as default in the dasd udev rule.

Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-03-16 17:18:51 +01:00
Mario Held
eb1fd47a85 dbginfo: Added and removed commands
Added kallsyms and lscpu -ye, added vmcp commands
q memassist, q pcifunction, q vmrelocate and removed q cache

Signed-off-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-03-16 17:18:51 +01:00
Ingo Franzki
c4918fe713 zkey: Fix typos in man pages
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-03-16 17:18:51 +01:00
Jan Höppner
d23558f1d1 ttyrun-getty: Avoid conflicts with serial-getty@
Starting ttyrun-getty@ will fail as it conflicts with the serial-getty@
service. Add Conflicts= option to avoid any conflicts.

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/105
Suggested-by: Dan Horák <dan@danny.cz>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-03-16 17:18:51 +01:00
Fabrice Fontaine
3d79a542d4 osasnmpd/Makefile: fix cross-compilation
Fix the following build failure by allowing the user to provide
NET_SNMP_CONFIG:

/bin/sh: net-snmp-config: command not found
/home/buildroot/autobuild/run/instance-2/output-1/host/lib/gcc/s390x-buildroot-linux-gnu/9.3.0/../../../../s390x-buildroot-linux-gnu/bin/ld: osasnmpd.o: in function `main':
osasnmpd.c:(.text.startup+0xcc): undefined reference to `snmp_log_perror'

Fixes: http://autobuild.buildroot.org/results/00796f2ebd5fb0e08ac7a05a9ee566f2bc4bd1c3
Closes: https://github.com/ibm-s390-linux/s390-tools/pull/99
Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-24 18:34:27 +01:00
Marc Hartmayer
b6bdd7744a genprotimg: use pv_ namespace for our Buffer implementation
Use `pv_` namespace for our Buffer implementation so a symbol clash with other
libraries is less likely.

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/109
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-24 18:33:44 +01:00
Ingo Franzki
3f3f063c98 zkey: Fix build error when the compiler flags are overridden
When the compiler flags are overridden, the build of zkey may fail with:

kms.c:44:2: error: #error KMS_PLUGIN_LOCATION must be defined
   44 | #error KMS_PLUGIN_LOCATION must be defined
      |  ^~~~~

The Makefile uses CFLAGS variable for defining the KMS_PLUGIN_LOCATION,
but it should rather use ALL_CFLAGS.

Also use ALL_CPPFLAGS for defining HAVE_LUKS2_SUPPORT.

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

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-23 16:49:09 +01:00
Jan Höppner
78d63f2333 Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-23 16:49:09 +01:00
257 changed files with 54772 additions and 6633 deletions

33
.gitignore vendored
View File

@@ -5,6 +5,14 @@
*.a
*.o.d
# ctags files
tags
TAGS
# Ignore coverage data
*.gcda
*.gcno
#
# Ignore generated executables and other generated files
#
@@ -13,6 +21,7 @@ cpacfstats/cpacfstats
cpacfstats/cpacfstatsd
cpumf/chcpumf
cpumf/lscpumf
cpumf/lshwc
cpuplugd/cpuplugd
dasdfmt/dasdfmt
dasdinfo/dasdinfo
@@ -20,6 +29,8 @@ dasdview/dasdview
dump2tar/src/dump2tar
fdasd/fdasd
hmcdrvfs/hmcdrvfs
hsavmcore/check-dep-fuse
hsavmcore/hsavmcore
hyptop/hyptop
ip_watcher/xcec-bridge
ipl_tools/chreipl
@@ -39,16 +50,14 @@ libekmfweb/detect-openssl-version.dep
libekmfweb/libekmfweb.so
libekmfweb/libekmfweb.so.1
libekmfweb/libekmfweb.so.1.0
libutil/util_base_example
libutil/util_file_example
libutil/util_libc_example
libutil/util_opt_command_example
libutil/util_opt_example
libutil/util_panic_example
libutil/util_path_example
libutil/util_prg_example
libutil/util_rec_example
libutil/util_scandir_example
libkmipclient/check-dep-libkmipclient
libkmipclient/detect-openssl-version.dep
libkmipclient/libkmipclient.so
libkmipclient/libkmipclient.so.1
libkmipclient/libkmipclient.so.1.0
libseckey/check-dep-libseckey
libseckey/detect-openssl-version.dep
libutil/*_example
libvmcp/vmcp_example
libzds/libzds.a
lsstp/lsstp
@@ -94,13 +103,17 @@ zipl/boot/*.bin
zipl/boot/*.exec
zipl/boot/data.h
zipl/src/chreipl_helper.device-mapper
zdev/src/zdev_id
zipl/src/zipl
zipl/src/zipl-editenv
zipl/src/zipl_helper.device-mapper
zkey/check-dep-zkey
zkey/check-dep-zkey-cryptsetup
zkey/detect-libcryptsetup.dep
zkey/ekmfweb/libekmfweb.dep
zkey/ekmfweb/zkey-ekmfweb.so
zkey/kmip/libkmipclient.dep
zkey/kmip/zkey-kmip.so
zkey/zkey
zkey/zkey-cryptsetup
zpcictl/zpcictl

View File

@@ -2,6 +2,7 @@ List of all individuals having contributed content to s390-tools
----------------------------------------------------------------
- Alexander Egorenkov
- Alexandra Winter
- Alexey Ishchuk
- Andreas Herrmann
- Andre Wild
@@ -27,6 +28,7 @@ List of all individuals having contributed content to s390-tools
- Erwin Vicari
- Eugene Crosser
- Eugene Dvurechenski
- Fabrice Fontaine
- Farhan Ali
- Fedor Loshakov
- Felix Beck
@@ -57,6 +59,7 @@ List of all individuals having contributed content to s390-tools
- Jean-Baptiste Joret
- Jens Remus
- Jochen Roehrig
- Joern Siglen
- Juergen Christ
- Julian Wiedmann
- Karsten Graul
@@ -64,6 +67,7 @@ List of all individuals having contributed content to s390-tools
- Klaus-Dieter Wacker
- Lakhvich Dmitriy
- Marc Hartmayer
- Mario Held
- Mark Dettinger
- Mark Post
- Martin Kammerer
@@ -107,6 +111,7 @@ List of all individuals having contributed content to s390-tools
- Swen Schillig
- Taraka R. Bodireddy
- Thomas Heidrich
- Thomas Huth
- Thomas Richter
- Thomas Spatzier
- Thomas Weber

View File

@@ -1,5 +1,81 @@
Release history for s390-tools (MIT version)
--------------------------------------------
* __v2.19.0 (2021-11-10)__
For Linux kernel version: 5.15
Add new tools / libraries:
- chreipl-fcp-mpath: New toolset that uses multipath information to change
the configured FCP re-IPL path on detecting issues with the current path
Changes of existing tools:
- dbginfo.sh: Add retry timeout and remove possible blocking "blockdev --report"
- dbginfo.sh: Collect config- and debug-data for chreipl-fcp-mpath
- hsci: Add support for multiple MAC addresses
Bug Fixes:
- lshwc: Fix compile error for gcc <8.1
- zdump: Various clean-ups and fixes
- ziomon: Correct throughput calculation in ziorep_printers
- zipl: Fix segmentation fault when setting stage3_parms
* __v2.18.0 (2021-10-01)__
For Linux kernel version: 5.14
Add new tools:
- scripts: Add tool for parsing sclp s390dbf logs
- zdev: Add udev rule helper tool
- zipl-editenv: Add tool to operate with zIPL environment installed in the boot record
Changes of existing tools:
- Makefile: Fix order of build of libraries for parallel builds
- dbginfo.sh: Add collection in area of timedate, coredump and --check option
- dbginfo.sh: Add exception on dump2tar for /sys/kernel/mm/page_idle/bitmap
- dbginfo.sh: Cleanup of outdated sections and general code rework
- dbginfo.sh: Collect zipl boot menu entries from boot loader specification
- lszcrypt: Add support for vfio-ap status field
- lszcrypt: Improved output for deconfig cards and queues
- lszfcp: Add linkdown case to host marker of extended output
- zdev: Add auto-config for PCI and crypto devices
- zdump: Introduce multi-level message logging
- zipl: Add support for environment block interpretation
- zkey-cryptsetup: Support LUKS2 volumes with integrity support enabled
Bug Fixes:
- hsavmcore: Avoid recompilation of overlay during install step
- libkmipclient: Fix parsing of hex values for XML and JSON encoding
- vmur/vmur.cpp: Fix error handling on transfer failure
- zdump: Lots of smaller fixes across the board
* __v2.17.0 (2021-07-07)__
For Linux kernel version: 5.12 / 5.13
Add new tools / libraries:
- hsavmcore: New utility to make the dump process with kdump more efficient
- libkmipclient: Add KMIP client shared library
- libseckey: Add a secure key library
- lshwc: New tool to extract and list complete counter sets
Changes of existing tools:
- genprotimg: Add '--(enable|disable)-pckmo' options
- genprotimg: Add OpenSSL 3.0 support
- genprotimg: Change plaintext control flags defaults so PCKMO functions are allowed
- libutil: Introduce multi-level message logging (util_log)
- libutil: Introduce util_arch module
- udev/dasd: Change DASD udev-rule to set none scheduler
- zdsfs: Add transparent codepage conversion
- zkey: Add support for KMIP-based key management systems
Bug Fixes:
- ttyrun-getty: Avoid conflicts with serial-getty@
- dbginfo: add /proc/kallsyms - refresh zVM, lscpu - fix WORKARCHIVE handling
- dbginfo: add KVM data collection for server and guest - fix lszdev
- genprotimg: Add missing return values in error paths
- zkey: Fix conversion of CCA DATA keys to CCA CIPHER keys
- znetconf: avoid conflict with "chzdev -e"
* __v2.16.0 (2021-02-19)__
For Linux kernel version: 5.10 / 5.11

View File

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

View File

@@ -109,6 +109,9 @@ Package contents
feature. Those traces are filtered with the zfcpdbf script, i.e. merge
several traces, make it more readable etc.
* sclpdbf:
Display debug data for the sclp kernel component.
* scsi_logging_level:
Create, get or set the logging level for the SCSI logging facility.
@@ -223,7 +226,8 @@ Package contents
* CPU-measurement facilities (CPU-MF) tools:
Use the lscpumf tool to display information about the CPU-measurement
counter and sampling facilities. Use the chcpumf tool to control the
sampling facility support.
sampling facility support. Use lshwc to extract complete counter sets from
the CPU Measurement Facilities.
* cpacfstats:
The cpacfstats tools provide a client/server application set to monitor
@@ -249,9 +253,27 @@ Package contents
Management Foundation - Web Edition, and is used to manage keys in an
enterprise.
* libkmipclient:
A shared library that provides an KMIP client to communicate with an KMIP
server. KMIP stands for Key Management Interoperability Protocol, and is an
extensible communication protocol that defines message formats for the
manipulation of cryptographic keys on a key management server.
* hsci:
Manage HiperSockets Converged Interfaces (HSCI).
* hsavmcore:
hsavmcore is designed to make the dump process with kdump more efficient.
With hsavmcore, the HSA memory that contains a part of the production
kernel's memory can be released early in the process. Depending on the size
of the production kernel's memory, writing the dump to persistent storage
can be time consuming and prevent the HSA memory from being reused
by other LPARs.
* chreipl-fcp-mpath:
Use multipath information to change the configured FCP re-IPL path on
detecting issues with the current path.
For more information refer to the following publications:
* "Device Drivers, Features, and Commands" chapter "Useful Linux commands"
@@ -270,25 +292,30 @@ build options:
| __LIBRARY__ | __BUILD OPTION__ | __TOOLS__ |
|----------------|:------------------:|:-------------------------------------:|
| fuse | `HAVE_FUSE` | cmsfs-fuse, zdsfs, hmcdrvfs, zgetdump |
| fuse | `HAVE_FUSE` | cmsfs-fuse, zdsfs, hmcdrvfs, zgetdump,|
| | | hsavmcore |
| zlib | `HAVE_ZLIB` | zgetdump, dump2tar |
| ncurses | `HAVE_NCURSES` | hyptop |
| pfm | `HAVE_PFM` | cpacfstats |
| net-snmp | `HAVE_SNMP` | osasnmpd |
| glibc-static | `HAVE_LIBC_STATIC` | zfcpdump |
| openssl | `HAVE_OPENSSL` | genprotimg, zkey, libekmfweb |
| openssl | `HAVE_OPENSSL` | genprotimg, zkey, libekmfweb, |
| | | libkmipclient |
| cryptsetup | `HAVE_CRYPTSETUP2` | zkey-cryptsetup |
| json-c | `HAVE_JSONC` | zkey-cryptsetup, libekmfweb |
| json-c | `HAVE_JSONC` | zkey-cryptsetup, libekmfweb, |
| | | libkmipclient |
| glib2 | `HAVE_GLIB2` | genprotimg |
| libcurl | `HAVE_LIBCURL` | genprotimg, libekmfweb |
| libcurl | `HAVE_LIBCURL` | genprotimg, libekmfweb, libkmipclient |
| libxml2 | `HAVE_LIBXML2` | libkmipclient |
| systemd | `HAVE_SYSTEMD` | hsavmcore |
This table lists additional build or install options:
| __COMPONENT__ | __OPTION__ | __TOOLS__ |
|------------------|:----------------------------:|:--------------:|
| dracut | `HAVE_DRACUT` | zdev |
| initramfs-tools | `HAVE_INITRAMFS` | zdev |
| | `ZDEV_ALWAYS_UPDATE_INITRD` | zdev |
| __COMPONENT__ | __OPTION__ | __TOOLS__ |
|------------------|:----------------------------:|:-----------------------:|
| dracut | `HAVE_DRACUT` | zdev, chreipl-fcp-mpath |
| initramfs-tools | `HAVE_INITRAMFS` | zdev |
| | `ZDEV_ALWAYS_UPDATE_INITRD` | zdev |
The s390-tools build process uses "pkg-config" if available and hard-coded
compiler and linker options otherwise.
@@ -427,3 +454,29 @@ the different tools are provided:
(libcurl-devel.rpm).
Tip: you may skip the libekmfweb build by adding `HAVE_OPENSSL=0`,
`HAVE_JSONC=0`, or `HAVE_LIBCURL=0` to the make invocation.
* hsavmcore:
For building the hsavmcore tool you need fuse version 2.6 and optionally
systemd which is enabled by default, to disable systemd support,
add `HAVE_SYSTEMD=0` to the make invocation.
Tip: you may skip the hsavmcore build by adding `HAVE_FUSE=0`
to the make invocation.
* libkmipclient:
For building the libkmipclient shared library you need openssl version 1.1.1
or newer installed (openssl-devel.rpm). Also required are json-c version 0.13
or newer (json-c-devel.rpm), libxml2 version 2.9.10 or newer
(libxml2-devel.rpm), and libcurl version 7.59 or newer (libcurl-devel.rpm).
Tip: you may skip the libkmipclient build by adding `HAVE_OPENSSL=0`,
`HAVE_JSONC=0`, `HAVE_LIBXML2=0`, or `HAVE_LIBCURL=0` to the make invocation.
* chreipl-fcp-mpath:
For a complete list and documentation of the requirements, installation and
uninstallation, please see
[chreipl-fcp-mpath/README.md](chreipl-fcp-mpath/README.md).
Summarized: chreipl-fcp-mpath requires GNU Bash, GNU Core Utilities,
util-linux, udev, and multipath-tools. When using `HAVE_DRACUT=1` with the
make invocation, it also requires dracut. When using `ENABLE_DOC=1` with the
make invocation to build a man page and render the README.md as HTML, make
further requires pandoc, GNU awk, and GNU Gzip for the build process.

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

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

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

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -5,7 +5,7 @@ COMMON_INCLUDED = true
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
VERSION = 2
RELEASE = 16
RELEASE = 19
PATCHLEVEL = 0
DISTRELEASE = build-$(shell date +%Y%m%d)
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
@@ -111,6 +111,20 @@ ifeq ("${ASAN}","1")
DEFAULT_LDFLAGS += -fsanitize=address
endif
#
# Check for header prerequisite
#
# $1: Name of include file to check
# $2: Additional compiler & linker options (optional)
#
# Returns "yes" on success and nothing otherwise
#
define check_header_prereq
$(shell printf "#include <%s>\n int main(void) {return 0;}" $1 | \
( $(CC) $(filter-out --coverage, $(ALL_CFLAGS)) $(ALL_CPPFLAGS) \
$2 -o /dev/null -xc - ) >/dev/null 2>&1 && echo -n yes)
endef
#
# Check for build dependency
#
@@ -168,6 +182,7 @@ USRSBINDIR = $(INSTALLDIR)/usr/sbin
USRBINDIR = $(INSTALLDIR)/usr/bin
BINDIR = $(INSTALLDIR)/sbin
LIBDIR = $(INSTALLDIR)/lib
USRLIBDIR = $(INSTALLDIR)/usr/lib
USRLIB64DIR = $(INSTALLDIR)/usr/lib64
SYSCONFDIR = $(INSTALLDIR)/etc
MANDIR = $(INSTALLDIR)/usr/share/man
@@ -192,10 +207,10 @@ INSTDIRS = $(USRSBINDIR) $(USRBINDIR) $(BINDIR) $(LIBDIR) $(MANDIR) \
$(TOOLS_LIBDIR) $(TOOLS_DATADIR) \
$(ZFCPDUMP_DIR) $(SYSTEMDSYSTEMUNITDIR) \
$(USRLIB64DIR) $(USRINCLUDEDIR) $(ZKEYKMSPLUGINDIR) \
$(SOINSTALLDIR)
$(SOINSTALLDIR) $(USRLIBDIR)
OWNER = $(shell id -un)
GROUP = $(shell id -gn)
export INSTALLDIR BINDIR LIBDIR USRLIB64DIR MANDIR OWNER GROUP
export INSTALLDIR BINDIR LIBDIR USRLIBDIR USRLIB64DIR MANDIR OWNER GROUP
# Special defines for zfcpdump
ZFCPDUMP_IMAGE = zfcpdump-image
@@ -360,6 +375,14 @@ $(rootdir)/libekmfweb/libekmfweb.so: $(rootdir)/libekmfweb
$(MAKE) -C $(rootdir)/libekmfweb/ libekmfweb.so
.PHONY: $(rootdir)/libekmfweb
$(rootdir)/libseckey/libseckey.a: $(rootdir)/libseckey
$(MAKE) -C $(rootdir)/libseckey/ libseckey.a
.PHONY: $(rootdir)/libseckey
$(rootdir)/libkmipclient/libkmipclient.so: $(rootdir)/libkmipclient
$(MAKE) -C $(rootdir)/libkmipclient/ libkmipclient.so
.PHONY: $(rootdir)/libkmipclient
$(rootdir)/zipl/boot/data.o:
$(MAKE) -C $(rootdir)/zipl/boot/ data.o

View File

@@ -1,7 +1,7 @@
include ../common.mak
BIN_FILES = lscpumf chcpumf
MAN_FILES = lscpumf.1 chcpumf.8
BIN_FILES = lscpumf chcpumf lshwc
MAN_FILES = lscpumf.1 chcpumf.8 lshwc.1
all: $(BIN_FILES)
@@ -9,6 +9,7 @@ libs = $(rootdir)/libutil/libutil.a
lscpumf: lscpumf.o $(libs)
chcpumf: chcpumf.o $(libs)
lshwc: lshwc.o $(libs)
install: all install-man
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8

View File

@@ -85,25 +85,19 @@ static long parse_buffersize(char *string)
return bytes;
}
static int read_sfb(unsigned long *min, unsigned long *max)
static void read_sfb(unsigned long *min, unsigned long *max)
{
unsigned long cur_min_sdb, cur_max_sdb;
int rc = EXIT_SUCCESS;
FILE *fp;
if (geteuid()) {
fprintf(stderr, "Error: Must run as root\n");
return EXIT_FAILURE;
}
if (geteuid())
errx(EXIT_FAILURE, "Must run as root");
fp = fopen(PERF_SFB_SIZE, "r");
if (fp == NULL) {
linux_error(PERF_SFB_SIZE);
return EXIT_FAILURE;
}
if (!fp)
err(EXIT_FAILURE, PERF_SFB_SIZE);
if (fscanf(fp, "%ld,%ld", &cur_min_sdb, &cur_max_sdb) != 2) {
fprintf(stderr, "Error: Can not parse file " PERF_SFB_SIZE
"\n");
rc = EXIT_FAILURE;
fclose(fp);
errx(EXIT_FAILURE, "Can not parse file " PERF_SFB_SIZE);
} else {
if (*min == 0)
*min = cur_min_sdb;
@@ -111,7 +105,9 @@ static int read_sfb(unsigned long *min, unsigned long *max)
*max = cur_max_sdb;
}
fclose(fp);
return rc;
if (*min >= *max)
errx(EXIT_FAILURE,
"The specified maximum must be greater than the minimum");
}
static int write_sfb(unsigned long min, unsigned long max)
@@ -122,25 +118,23 @@ static int write_sfb(unsigned long min, unsigned long max)
FILE *fp;
fp = fopen(PERF_SFB_SIZE, "w");
if (fp == NULL) {
linux_error(PERF_SFB_SIZE);
return EXIT_FAILURE;
}
if (!fp)
err(EXIT_FAILURE, PERF_SFB_SIZE);
snprintf(text, sizeof text, "%ld,%ld", min, max);
len = strlen(text) + 1;
if (fwrite(text, 1, len, fp) != len) {
linux_error(PERF_SFB_SIZE);
warn(PERF_SFB_SIZE);
rc = EXIT_FAILURE;
}
if (fclose(fp)) {
linux_error(PERF_SFB_SIZE);
warn(PERF_SFB_SIZE);
rc = EXIT_FAILURE;
}
if (verbose && rc != EXIT_FAILURE)
fprintf(stderr, "Sampling buffer sizes:\n"
" Minimum:%7ld sample-data-blocks\n"
" Maximum:%7ld sample-data-blocks\n",
min, max);
warnx("Sampling buffer sizes:\n"
" Minimum:%7ld sample-data-blocks\n"
" Maximum:%7ld sample-data-blocks\n",
min, max);
return rc;
}
@@ -160,61 +154,44 @@ static int parse_args(int argc, char **argv)
exit(EXIT_SUCCESS);
case 'x':
new = parse_buffersize(optarg);
if (new < 1) {
fprintf(stderr, "The specified number(s)"
" are not valid\n");
exit(EXIT_FAILURE);
}
if (new < 1)
errx(EXIT_FAILURE,
"The specified number(s) are not valid");
max_sdb = new;
action = 1;
break;
case 'm':
new = parse_buffersize(optarg);
if (new < 1) {
fprintf(stderr, "The specified number(s)"
" are not valid\n");
exit(EXIT_FAILURE);
}
if (new < 1)
errx(EXIT_FAILURE,
"The specified number(s) are not valid");
min_sdb = new;
action = 1;
break;
case 'V':
verbose = 1;
break;
case '?':
fprintf(stderr, "One or more options are not valid\n");
fprintf(stderr, "Try 'chcpumf --help' for more"
" information\n");
default:
util_opt_print_parse_error(opt, argv);
exit(EXIT_FAILURE);
}
}
if (!action) {
fprintf(stderr, "You must specify a valid option\n");
exit(EXIT_FAILURE);
}
if (!action)
errx(EXIT_FAILURE, "You must specify a valid option");
return action;
}
int main(int argc, char **argv)
{
int ret = EXIT_FAILURE;
struct stat sbuf;
util_prg_init(&prg);
util_opt_init(opt_vec, NULL);
parse_args(argc, argv);
if (stat(PERF_PATH PERF_SF, &sbuf) != 0) {
fprintf(stderr,
"No CPU-measurement sampling facility detected\n");
return ret;
}
if (read_sfb(&min_sdb, &max_sdb))
return ret;
if (min_sdb >= max_sdb) {
fprintf(stderr, "The specified maximum must be greater "
"than the minimum\n");
return ret;
}
if (stat(PERF_PATH PERF_SF, &sbuf))
errx(EXIT_FAILURE,
"No CPU-measurement sampling facility detected");
read_sfb(&min_sdb, &max_sdb);
return write_sfb(min_sdb, max_sdb);
}

View File

@@ -15,9 +15,4 @@
#define PERF_SF "cpum_sf"
#define PERF_CF "cpum_cf"
static inline void linux_error(const char *message)
{
fprintf(stderr, "Error: %s: %s\n", message, strerror(errno));
}
#endif

View File

@@ -23,9 +23,10 @@
#include <linux/perf_event.h>
#include "lib/util_arch.h"
#include "lib/util_base.h"
#include "lib/util_opt.h"
#include "lib/util_prg.h"
#include "lib/util_base.h"
#include "defines.h"
@@ -2558,25 +2559,6 @@ static struct counters cpumcf_z15_counters[] = {
},
};
static const char *machine_name(void)
{
switch (cpumf.machine_type) {
case 2097: return "IBM System z10 EC";
case 2098: return "IBM System z10 BC";
case 2817: return "IBM zEnterprise 196";
case 2818: return "IBM zEnterprise 114";
case 2827: return "IBM zEnterprise EC12";
case 2828: return "IBM zEnterprise BC12";
case 2964: return "IBM z13";
case 2965: return "IBM z13s";
case 3906: return "IBM z14";
case 3907: return "IBM z14 ZR1";
case 8561: return "IBM z15";
case 8562: return "IBM z15 Model T02";
}
return "Unknown hardware model";
}
/* Return the type number of the CPU Measurement facility from the sysfs file.
* If the type number is equal to PERF_TYPE_RAW, then the prefix is 'r' to
* specify the raw counter number by the perf tool.
@@ -2589,13 +2571,12 @@ static int read_cpumf_type(const char *filename, const char *type)
FILE *fp = fopen(filename, "r");
if (fp == NULL) {
fprintf(stderr, "No CPU-measurement %s facility detected\n",
type);
warnx("No CPU-measurement %s facility detected", type);
return rc;
}
if (fscanf(fp, "%d", &nr) != 1)
fprintf(stderr, "Can not parse file %s\n", filename);
else {
if (fscanf(fp, "%d", &nr) != 1) {
warnx("Can not parse file %s", filename);
} else {
rc = EXIT_SUCCESS;
if (nr == PERF_TYPE_RAW)
strcat(prefix, "r");
@@ -2639,10 +2620,8 @@ static int parse_args(int argc, char **argv)
case 'C':
actions[ACTION_CNTALL] = true;
break;
case '?':
fprintf(stderr, "One or more options are not valid\n");
fprintf(stderr, "Try 'lscpumf --help' for more"
" information.\n");
default:
util_opt_print_parse_error(opt, argv);
exit(EXIT_FAILURE);
}
}
@@ -2685,7 +2664,7 @@ static void show_info(struct cpumf_info *p, int details)
struct stat sbuf;
if (!p->have_counter && !p->have_samples) {
fprintf(stderr, "No CPU-measurement facilities detected\n");
warnx("No CPU-measurement facilities detected");
return;
}
if (p->have_counter) {
@@ -2710,13 +2689,12 @@ static void show_info(struct cpumf_info *p, int details)
if (0x8000 & p->authorization)
printf(" Coprocessor Group counter Set\n");
printf("\nLinux perf event support: %s\n\n",
(stat(PERF_PATH PERF_CF, &sbuf) != 0) ? "No" :
(stat(PERF_PATH PERF_CF, &sbuf)) ? "No" :
"Yes (PMU: " PERF_CF ")");
}
} else
fprintf(stderr,
"No CPU-measurement counter facility detected\n");
warnx("No CPU-measurement counter facility detected");
if (p->have_samples) {
unsigned long total, fdiag;
char text[32];
@@ -2740,7 +2718,7 @@ static void show_info(struct cpumf_info *p, int details)
p->diag_sample_sz);
printf("\nLinux perf event support: %s\n\n",
(stat(PERF_PATH PERF_SF, &sbuf) != 0) ? "No" :
(stat(PERF_PATH PERF_SF, &sbuf)) ? "No" :
"Yes (PMU: " PERF_SF ")");
printf("Current sampling buffer settings for %s:\n",
@@ -2774,40 +2752,7 @@ static void show_info(struct cpumf_info *p, int details)
printf(" Size factor: %2ld\n", fdiag);
}
} else
fprintf(stderr,
"No CPU-measurement sampling facility detected\n");
}
/* Funktion to read machine type */
#define SYSINFO "/proc/sysinfo"
#define MACH_TYPE "Type:"
static int read_machine(unsigned short *mt)
{
int rc = EXIT_FAILURE;
char *linep = NULL;
size_t line_sz;
ssize_t nbytes;
FILE *fp;
fp = fopen(SYSINFO, "r");
if (fp == NULL) {
linux_error(SYSINFO);
return rc;
}
while ((nbytes = getline(&linep, &line_sz, fp)) != EOF) {
if (!strncmp(linep, MACH_TYPE, sizeof MACH_TYPE - 1)) {
int rc_scan = sscanf(linep, MACH_TYPE "%hd", mt);
if (rc_scan != 1)
fprintf(stderr, "Can not parse line %s", linep);
else
rc = EXIT_SUCCESS;
break;
}
}
fclose(fp);
free(linep);
return rc;
warnx("No CPU-measurement sampling facility detected");
}
/* Read CPU Measurement sampling facility device driver minimum and maximum
@@ -2815,16 +2760,16 @@ static int read_machine(unsigned short *mt)
*/
static int read_sfb(struct cpumf_info *p)
{
FILE *fp;
int rc = EXIT_SUCCESS;
FILE *fp;
fp = fopen(PERF_SFB_SIZE, "r");
if (fp == NULL) {
linux_error(PERF_SFB_SIZE);
if (!fp) {
warn(PERF_SFB_SIZE);
return EXIT_FAILURE;
}
if (fscanf(fp, "%d,%d", &p->min_sfb, &p->max_sfb) != 2) {
fprintf(stderr, "Can not parse %s\n", PERF_SFB_SIZE);
warnx("Can not parse %s", PERF_SFB_SIZE);
rc = EXIT_FAILURE;
}
fclose(fp);
@@ -2843,7 +2788,7 @@ static void read_ccerror(struct counters *cp, size_t cp_cnt)
char *ctrname;
size_t i = 0;
if (stat(CCERROR, &sbuf) == 0)
if (!stat(CCERROR, &sbuf))
ctrname = "DFLT_CCERROR";
else
ctrname = "DFLT_CCFINISH";
@@ -2866,8 +2811,8 @@ static int read_info(void)
memset(&cpumf, 0, sizeof cpumf);
slp = fopen(SERVICELEVEL, "r");
if (slp == NULL) {
linux_error(SERVICELEVEL);
if (!slp) {
warn(SERVICELEVEL);
return EXIT_FAILURE;
}
@@ -2877,7 +2822,7 @@ static int read_info(void)
" version=%f authorization=%x",
&cpumf.version, &cpumf.authorization);
if (rc != 2) {
fprintf(stderr, "Can not parse line %s", linep);
warnx("Can not parse line %s", linep);
rc = EXIT_FAILURE;
goto out;
}
@@ -2891,7 +2836,7 @@ static int read_info(void)
&cpumf.min_rate, &cpumf.max_rate,
&cpumf.cpu_speed);
if (rc != 3) {
fprintf(stderr, "Can not parse line %s", linep);
warnx("Can not parse line %s", linep);
rc = EXIT_FAILURE;
goto out;
}
@@ -2902,7 +2847,7 @@ static int read_info(void)
" mode=basic sample_size=%u",
&cpumf.basic_sample_sz);
if (rc != 1) {
fprintf(stderr, "Can not parse line %s", linep);
warnx("Can not parse line %s", linep);
rc = EXIT_FAILURE;
goto out;
}
@@ -2912,7 +2857,7 @@ static int read_info(void)
" mode=diagnostic sample_size=%u",
&cpumf.diag_sample_sz);
if (rc != 1) {
fprintf(stderr, "Can not parse line %s", linep);
warnx("Can not parse line %s", linep);
rc = EXIT_FAILURE;
goto out;
}
@@ -2923,9 +2868,11 @@ static int read_info(void)
if (rc == EXIT_FAILURE)
goto out;
}
rc = read_machine(&cpumf.machine_type);
if (rc == EXIT_FAILURE)
cpumf.machine_type = util_arch_machine_type();
if (cpumf.machine_type == UTIL_ARCH_MACHINE_TYPE_UNKNOWN) {
rc = EXIT_FAILURE;
goto out;
}
rc = EXIT_SUCCESS;
out:
fclose(slp);
@@ -3013,33 +2960,33 @@ static struct counters *get_counter(int ctrset, size_t *len)
break;
case CPUMF_CTRSET_EXTENDED:
switch (cpumf.machine_type) {
case 2097:
case 2098:
case UTIL_ARCH_MACHINE_TYPE_Z10_EC:
case UTIL_ARCH_MACHINE_TYPE_Z10_BC:
cp = cpumcf_z10_counters;
*len = ARRAY_SIZE(cpumcf_z10_counters);
break;
case 2817:
case 2818:
case UTIL_ARCH_MACHINE_TYPE_ZE_196:
case UTIL_ARCH_MACHINE_TYPE_ZE_114:
cp = cpumcf_z196_counters;
*len = ARRAY_SIZE(cpumcf_z196_counters);
break;
case 2827:
case 2828:
case UTIL_ARCH_MACHINE_TYPE_ZE_EC12:
case UTIL_ARCH_MACHINE_TYPE_ZE_BC12:
cp = cpumcf_zec12_counters;
*len = ARRAY_SIZE(cpumcf_zec12_counters);
break;
case 2964:
case 2965:
case UTIL_ARCH_MACHINE_TYPE_Z13:
case UTIL_ARCH_MACHINE_TYPE_Z13_S:
cp = cpumcf_z13_counters;
*len = ARRAY_SIZE(cpumcf_z13_counters);
break;
case 3906:
case 3907:
case UTIL_ARCH_MACHINE_TYPE_Z14:
case UTIL_ARCH_MACHINE_TYPE_Z14_ZR1:
cp = cpumcf_z14_counters;
*len = ARRAY_SIZE(cpumcf_z14_counters);
break;
case 8561:
case 8562:
case UTIL_ARCH_MACHINE_TYPE_Z15:
case UTIL_ARCH_MACHINE_TYPE_Z15_T02:
cp = cpumcf_z15_counters;
*len = ARRAY_SIZE(cpumcf_z15_counters);
read_ccerror(cp, *len);
@@ -3074,7 +3021,8 @@ static void show_counter(bool all)
struct counters *cp;
size_t cp_cnt;
printf("perf event counter list for %s\n", machine_name());
printf("perf event counter list for %s\n",
util_arch_machine_type_str());
show_hdr();
/* Basic counter set */
cp = get_counter(CPUMF_CTRSET_BASIC, &cp_cnt);

776
cpumf/lshwc.c Normal file
View File

@@ -0,0 +1,776 @@
/* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
/* CPU Measurements counter facility counter sets can be extracted by a
* device driver accessible by opening device /dev/hwctr.
* This program extracts complete counter set using this device.
* Counter sets are per CPU, the interface allows to specify counter sets
* for individual CPUs. The supported flags are executed from left to
* right, the first error encountered stops the execution of the program.
*/
#include <ctype.h>
#include <dirent.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <linux/limits.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/user.h>
#include <time.h>
#include <unistd.h>
#include "lib/util_opt.h"
#include "lib/util_prg.h"
#include "lib/util_base.h"
#include "lib/util_path.h"
#include "lib/util_scandir.h"
#include "lib/util_libc.h"
#include "lshwc.h"
#define SERVICELEVEL "/proc/service_levels"
#define CPUS_ONLINE "/sys/devices/system/cpu/online"
#define CPUS_POSSIBLE "/sys/devices/system/cpu/possible"
#define CPUS_KERNELMAX "/sys/devices/system/cpu/kernel_max"
#define MAXCTRS 512
#define IOCTLSLEEP 60U
static unsigned int read_interval = IOCTLSLEEP, cfvn, csvn, authorization;
static unsigned long loop_count = 1;
static unsigned char *ioctlbuffer;
static bool allcpu;
static unsigned int max_possible_cpus; /* No of possible CPUs */
static struct ctrname { /* List of defined counters */
char *name; /* Counter name */
bool hitcnt; /* Counter number read from ioctl() */
unsigned long total; /* Total counter value */
unsigned long *ccv; /* Per CPU counter value */
} ctrname[MAXCTRS];
/* Open file and extract counter number */
static int read_counter(const char *p)
{
FILE *fp = fopen(p, "r");
int rc = 0, ctr;
if (fp) {
rc = fscanf(fp, "event=%x", &ctr);
fclose(fp);
}
return rc == 1 ? ctr : -EINVAL;
}
static int add_countername(char *name, int nr)
{
ctrname[nr].name = strdup(name);
return ctrname[nr].name ? 0 : -ENOMEM;
}
static bool read_counternames(void)
{
struct dirent **namelist = NULL;
int i, ctr = 0, count = 0;
char *path, *ctrpath;
path = util_path_sysfs("/bus/event_source/devices/cpum_cf/events/");
count = util_scandir(&namelist, alphasort, path, "[^.]");
if (count <= 0) {
warnx("Cannot open %s", path);
free(path);
return false;
}
for (i = 0; i < count && ctr >= 0; i++) {
util_asprintf(&ctrpath, "%s/%s", path, namelist[i]->d_name);
ctr = read_counter(ctrpath);
free(ctrpath);
if (ctr >= 0)
ctr = add_countername(namelist[i]->d_name, ctr);
}
if (ctr < 0)
warnx("Cannot parse %s", path);
util_scandir_free(namelist, count);
free(path);
return ctr < 0 ? false : true;
}
static void free_counternames(void)
{
for (size_t i = 0; i < ARRAY_SIZE(ctrname); ++i) {
free(ctrname[i].name);
free(ctrname[i].ccv);
}
}
static struct check_result {
bool cpu_pos; /* CPU Number possible */
bool cpu_req; /* CPU Number requested */
bool cpu_hit; /* CPU Number received */
unsigned char sets_req; /* Counters sets requested */
unsigned char sets_hit; /* Counters sets received */
} *check;
static bool check_set(unsigned long a, unsigned long b, unsigned long sets)
{
if (a > b)
return false;
for (; a <= b; ++a) {
if (a >= max_possible_cpus || !check[a].cpu_pos)
return false;
check[a].cpu_req = true;
check[a].sets_req = sets;
}
return true;
}
/*
* Functions to parse command line parameters
* Convert a number from ascii to int.
*/
static unsigned long getnumber(char *word, char stopchar)
{
unsigned long no;
char *endp;
no = strtoul(word, &endp, 0);
if (*endp != stopchar)
errx(EXIT_FAILURE, "Invalid parameter %s", word);
return no;
}
/* Remove all whitespace from string. */
static void kill_whitespace(char *s)
{
char *cp = s;
for (; *s != '\0'; ++s) {
if (isspace(*s))
continue;
if (isprint(*s))
*cp++ = *s;
}
*cp = '\0';
}
/* Read file to get all online CPUs */
static bool get_cpus(char *file, char *buf, size_t bufsz)
{
char fmt[16];
FILE *slp;
int rc;
slp = fopen(file, "r");
if (!slp) {
warnx("Cannot open %s", file);
return false;
}
snprintf(fmt, sizeof(fmt), "%%%zus", bufsz - 1);
rc = fscanf(slp, fmt, buf);
fclose(slp);
if (rc != 1)
warnx("Cannot parse %s", file);
return rc == 1 ? true : false;
}
/* Parse counter set specification */
static unsigned long parse_ctrset(char *cp)
{
unsigned long x = 0;
for (; *cp; ++cp) {
switch (tolower(*cp)) {
case 'b':
x |= S390_HWCTR_BASIC;
break;
case 'c':
x |= S390_HWCTR_CRYPTO;
break;
case 'e':
x |= S390_HWCTR_EXT;
break;
case 'm':
x |= S390_HWCTR_MT_DIAG;
break;
case 'p':
case 'u':
x |= S390_HWCTR_USER;
break;
case 'a':
x |= S390_HWCTR_ALL;
break;
default:
errx(EXIT_FAILURE,
"Invalid counter set specification '%c'", *cp);
}
}
return x;
}
static char *show_ctrset(unsigned long set)
{
static char text[16];
int i = 0;
if (set & S390_HWCTR_BASIC)
text[i++] = 'B';
if (set & S390_HWCTR_CRYPTO)
text[i++] = 'C';
if (set & S390_HWCTR_EXT)
text[i++] = 'E';
if (set & S390_HWCTR_MT_DIAG)
text[i++] = 'M';
if (set & S390_HWCTR_USER)
text[i++] = 'U';
text[i] = '\0';
return text;
}
/* Parse CPU list and counter sets */
static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
{
uint64_t *words = start->cpumask;
unsigned long i, no_a, no_b;
char *cp, *tokens[16]; /* Used to parse command line params */
char cpubuf[256];
start->data_bytes = 0;
if (parm)
kill_whitespace(parm);
if (!parm || *parm == ':') {
/* No CPU list or just counter sets */
if (!get_cpus(CPUS_ONLINE, cpubuf, sizeof(cpubuf)))
exit(EXIT_FAILURE);
if (parm)
strcat(cpubuf, parm);
parm = cpubuf;
}
cp = strchr(parm, ':');
if (cp) { /* Handle counter set */
*cp = '\0';
start->counter_sets = parse_ctrset(++cp);
} else {
start->counter_sets = S390_HWCTR_ALL;
}
/* Check with authorized counter sets */
if ((start->counter_sets & authorization) != start->counter_sets) {
unsigned int noton = ~(start->counter_sets & authorization);
start->counter_sets &= authorization;
if (!start->counter_sets)
errx(EXIT_FAILURE, "No counter sets are authorized");
warnx("One or more counter sets are not authorized: %s",
show_ctrset(noton));
}
for (i = 0; i < ARRAY_SIZE(tokens) && (tokens[i] = strtok(parm, ","));
++i, parm = NULL) {
cp = strchr(tokens[i], '-'); /* Range character? */
if (cp) {
no_a = getnumber(tokens[i], *cp);
no_b = getnumber(++cp, '\0');
} else {
no_b = getnumber(tokens[i], '\0');
no_a = no_b;
}
if (!check_set(no_a, no_b, start->counter_sets))
errx(EXIT_FAILURE, "Invalid CPU list %s", tokens[i]);
}
/* Convert the CPU list to a bitmask for kernel cpumask_t */
for (i = 0, no_b = 0; i < max_possible_cpus; ++i) {
if (check[i].cpu_req) {
no_a = i % LONG_BIT;
no_b = i / LONG_BIT;
words[no_b] |= 1ULL << no_a;
}
}
/* no_b is highest used index, swap array */
start->cpumask_len = (no_b + 1) * 8;
for (no_a = 0; no_a < no_b; ++no_a, --no_b) {
uint64_t tmp = words[no_a];
words[no_a] = words[no_b];
words[no_b] = tmp;
}
start->version = S390_HWCTR_START_VERSION;
}
static bool check_setpossible(void)
{
char *cp, *parm, *tokens[16]; /* Used to parse command line params */
unsigned long i, no_a, no_b;
char cpubuf[1024];
if (!get_cpus(CPUS_KERNELMAX, cpubuf, sizeof(cpubuf)))
return false;
max_possible_cpus = getnumber(cpubuf, '\0') + 1;
check = calloc(max_possible_cpus, sizeof(*check));
if (!check)
err(EXIT_FAILURE, "Maximum CPUs %u", max_possible_cpus);
if (!get_cpus(CPUS_POSSIBLE, cpubuf, sizeof(cpubuf))) {
free(check);
return false;
}
parm = cpubuf;
for (i = 0; i < ARRAY_SIZE(tokens) && (tokens[i] = strtok(parm, ","));
++i, parm = NULL) {
cp = strchr(tokens[i], '-');
if (cp) { /* Range */
no_a = getnumber(tokens[i], *cp);
no_b = getnumber(++cp, '\0');
} else {
no_b = getnumber(tokens[i], '\0');
no_a = no_b;
}
for (; no_a <= no_b; ++no_a)
check[no_a].cpu_pos = true;
}
return true;
}
static void show_header(void)
{
static bool header;
bool comma = false;
if (header)
return; /* Printed already */
printf("Date,Time,CPU,"); /* Print counter name and number */
for (size_t i = 0; i < ARRAY_SIZE(ctrname); ++i) {
if (!ctrname[i].hitcnt)
continue;
if (comma)
putchar(',');
printf("%s(%ld)", ctrname[i].name ?: "Counter", i);
comma = true;
}
putchar('\n');
header = true;
}
static void line(char *header)
{
bool comma;
show_header();
if (allcpu) {
for (unsigned int h = 0; h < max_possible_cpus; ++h) {
char txt[16];
if (!check[h].cpu_hit)
continue;
comma = false;
snprintf(txt, sizeof(txt), "CPU%d,", h);
printf("%s%s", header, txt);
for (size_t i = 0; i < ARRAY_SIZE(ctrname); ++i) {
if (!ctrname[i].hitcnt)
continue;
if (comma)
putchar(',');
printf("%ld", ctrname[i].ccv[h]);
comma = true;
}
putchar('\n');
}
}
/* Print total count of all CPUs */
printf("%sTotal,", header);
comma = false;
for (size_t i = 0; i < ARRAY_SIZE(ctrname); ++i) {
if (!ctrname[i].hitcnt)
continue;
if (comma)
putchar(',');
printf("%ld", ctrname[i].total);
comma = true;
}
putchar('\n');
}
static void show(void)
{
time_t now = time(NULL);
struct tm *now_tm;
char now_text[32];
now_tm = localtime(&now);
strftime(now_text, sizeof(now_text), "%F,%T,", now_tm);
line(now_text);
}
/* Return Counter set size numbers (in counters) */
static unsigned int ctrset_size(int set)
{
switch (set) {
case S390_HWCTR_BASIC:
return 6;
case S390_HWCTR_USER:
return (cfvn == 1) ? 6 : 2;
case S390_HWCTR_CRYPTO:
return (csvn <= 5) ? 16 : 20;
case S390_HWCTR_EXT:
switch (csvn) {
case 1: return 32;
case 2: return 48;
case 3:
case 4:
case 5: return 128;
}
return 160;
case S390_HWCTR_MT_DIAG:
switch (csvn) {
case 1:
case 2:
case 3: return 0;
}
return 48;
}
return 0;
}
/* Return counter set offset numbers */
static int ctrset_offset(int set)
{
switch (set) {
case S390_HWCTR_BASIC:
return 0;
case S390_HWCTR_USER:
return 32;
case S390_HWCTR_CRYPTO:
return 64;
case S390_HWCTR_EXT:
return 128;
case S390_HWCTR_MT_DIAG:
return 448;
}
return 0;
}
static bool set_and_size_ok(struct s390_hwctr_setdata *p)
{
switch (p->set) {
case S390_HWCTR_BASIC:
case S390_HWCTR_USER:
case S390_HWCTR_CRYPTO:
case S390_HWCTR_EXT:
case S390_HWCTR_MT_DIAG:
return p->no_cnts == ctrset_size(p->set);
}
return false;
}
static bool add_countervalue(size_t idx, unsigned int cpu, unsigned long value)
{
if (idx >= ARRAY_SIZE(ctrname)) {
warnx("Invalid counter number %zu", idx);
return false;
}
if (cpu >= max_possible_cpus) {
warnx("Invalid CPU number %d", cpu);
return false;
}
if (!ctrname[idx].ccv) /* Unknown counter */
ctrname[idx].ccv = calloc(max_possible_cpus,
sizeof(unsigned long));
if (ctrname[idx].ccv)
ctrname[idx].ccv[cpu] += value;
ctrname[idx].total += value;
ctrname[idx].hitcnt = true;
return true;
}
static int test_read(struct s390_hwctr_read *read)
{
void *base = &read->data;
size_t offset = 0;
/* Clear previous hit counters */
for (unsigned int i = 0; i < max_possible_cpus; ++i) {
check[i].sets_hit = 0;
check[i].cpu_hit = false;
}
/* Iterate over all CPUs */
for (unsigned int i = 0; i < read->no_cpus; ++i) {
struct s390_hwctr_cpudata *cp = base + offset;
check[cp->cpu_nr].cpu_hit = true;
check[cp->cpu_nr].sets_hit = 0;
offset += sizeof(cp->cpu_nr) + sizeof(cp->no_sets);
/* Iterate over all counter sets */
for (unsigned int j = 0; j < cp->no_sets; ++j) {
struct s390_hwctr_setdata *sp = base + offset;
check[cp->cpu_nr].sets_hit |= sp->set;
offset += sizeof(sp->set) + sizeof(sp->no_cnts);
if (!set_and_size_ok(sp)) {
warnx("CPU %d inconsistent set %d size %d",
cp->cpu_nr, sp->set, sp->no_cnts);
return -1;
}
/* Iterate over all counters in each set */
for (unsigned int k = 0; k < sp->no_cnts; ++k) {
uint64_t value;
void *addr = base + offset;
size_t idx = ctrset_offset(sp->set) + k;
memcpy(&value, addr, sizeof(value));
offset += sizeof(value);
if (!add_countervalue(idx, cp->cpu_nr, value))
return -1;
}
}
}
show();
return 0;
}
static int do_open(void)
{
int fd = open(S390_HWCTR_DEVICE, O_RDWR);
if (fd < 0)
warn(S390_HWCTR_DEVICE);
return fd;
}
static int do_stop(int ioctlfd)
{
int rc = ioctl(ioctlfd, S390_HWCTR_STOP, 0);
if (rc < 0)
warn("ioctl S390_HWCTR_STOP");
return rc;
}
static int do_start(int ioctlfd, struct s390_hwctr_start *start)
{
int rc = ioctl(ioctlfd, S390_HWCTR_START, start);
if (rc < 0)
warn("ioctl S390_HWCTR_START");
return rc;
}
static int do_read(int ioctlfd)
{
size_t ioctlbuffer_len = PAGE_SIZE * max_possible_cpus +
sizeof(struct s390_hwctr_read);
struct s390_hwctr_read *read;
int rc;
if (!ioctlbuffer) {
ioctlbuffer = malloc(ioctlbuffer_len);
if (!ioctlbuffer) {
warn("ioctl S390_HWCTR_START");
return -ENOMEM;
}
}
read = (struct s390_hwctr_read *)ioctlbuffer;
rc = ioctl(ioctlfd, S390_HWCTR_READ, read);
if (!rc)
rc = test_read(read);
else
warn("ioctl S390_HWCTR_READ");
return rc;
}
static void do_sleep(void)
{
struct timespec req = {
.tv_sec = read_interval,
.tv_nsec = 0
};
nanosleep(&req, NULL);
}
/* Execute commands and report first error */
static int do_it(char *s)
{
struct s390_hwctr_start start;
int ioctlfd;
int rc;
memset(&start, 0, sizeof(start));
rc = max_possible_cpus / sizeof(uint64_t);
start.cpumask = alloca(max_possible_cpus / sizeof(uint64_t));
memset(start.cpumask, 0, rc);
parse_cpulist(s, &start);
errno = 0;
ioctlfd = do_open();
if (ioctlfd < 0)
return EXIT_FAILURE;
rc = do_start(ioctlfd, &start);
if (rc < 0) {
close(ioctlfd);
return EXIT_FAILURE;
}
for (unsigned long i = 0; !rc && i < loop_count; ++i) {
rc = do_read(ioctlfd);
if (rc) {
close(ioctlfd);
return EXIT_FAILURE;
}
if (read_interval && i + 1 < loop_count)
do_sleep();
}
rc = do_stop(ioctlfd);
close(ioctlfd);
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
}
/* Read counter first and second version number */
static bool get_cvn(void)
{
char *linep = NULL;
bool good = false;
size_t line_sz;
ssize_t nbytes;
FILE *slp;
slp = fopen(SERVICELEVEL, "r");
if (!slp) {
warn(SERVICELEVEL);
return false;
}
while ((nbytes = getline(&linep, &line_sz, slp)) != EOF) {
if (!strncmp(linep, "CPU-MF: Counter facility:", 25)) {
int rc;
rc = sscanf(linep, "CPU-MF: Counter facility: version=%d.%d authorization=%x",
&cfvn, &csvn, &authorization);
good = rc == 3;
if (!good)
warnx("Cannot parse line %s", linep);
break;
}
}
fclose(slp);
free(linep);
return good;
}
static struct util_opt opt_vec[] = {
UTIL_OPT_SECTION("OPTIONS"),
{
.option = { "all", no_argument, NULL, 'a' },
.desc = "Displays all CPUs in output"
},
{
.option = { "loop", required_argument, NULL, 'l' },
.argument = "NUMBER",
.desc = "Specifies loop count for next read"
},
{
.option = { "interval", required_argument, NULL, 'i' },
.argument = "NUMBER",
.desc = "Specifies interval between read operations (seconds)"
},
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
};
static const struct util_prg prg = {
.desc = "Read CPU Measurement facility counter sets",
.copyright_vec = {
{
.owner = "IBM Corp.",
.pub_first = 2021,
.pub_last = 2021,
},
UTIL_PRG_COPYRIGHT_END
}
};
/* Check for hardware support and exit if not available */
static void have_support(void)
{
struct stat statbuf;
if (stat(S390_HWCTR_DEVICE, &statbuf) == -1)
errx(EXIT_FAILURE,
"No support for CPU Measurement Counter set facility");
}
int main(int argc, char **argv)
{
char *slash;
int ch;
util_prg_init(&prg);
util_opt_init(opt_vec, NULL);
while ((ch = util_opt_getopt_long(argc, argv)) != -1) {
switch (ch) {
default:
util_opt_print_parse_error(ch, argv);
return EXIT_FAILURE;
case 'h':
util_prg_print_help();
util_opt_print_help();
return EXIT_SUCCESS;
case 'v':
util_prg_print_version();
return EXIT_SUCCESS;
case 'l':
errno = 0;
loop_count = strtoul(optarg, &slash, 0);
if (errno || *slash)
errx(EXIT_FAILURE, "Invalid argument for -%c",
ch);
break;
case 'i':
errno = 0;
read_interval = (unsigned int)strtoul(optarg, &slash, 0);
if (errno || *slash)
errx(EXIT_FAILURE, "Invalid argument for -%c", ch);
break;
case 'a':
allcpu = true;
break;
}
}
have_support();
if (!get_cvn())
return EXIT_FAILURE;
if (!check_setpossible())
return EXIT_FAILURE;
if (!read_counternames()) {
free(check);
return EXIT_FAILURE;
}
if (optind >= argc) {
ch = do_it(NULL);
} else {
while (optind < argc) {
ch = do_it(argv[optind++]);
if (ch)
break;
}
}
free_counternames();
free(check);
return ch;
}

93
cpumf/lshwc.h Normal file
View File

@@ -0,0 +1,93 @@
/* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
/*
* CPU Measurement counter facility application for device driver.
*
* Ioctl system call definitions.
*/
#ifndef LSHWC_H
#define LSHWC_H
#include <stdint.h>
#include <sys/ioctl.h>
enum {
S390_HWCTR_BASIC = 0x2, /* BASIC counter set */
S390_HWCTR_USER = 0x4, /* Problem-State Counter Set */
S390_HWCTR_CRYPTO = 0x8, /* Crypto-Activity Counter Set */
S390_HWCTR_EXT = 0x1, /* Extended Counter Set */
S390_HWCTR_MT_DIAG = 0x20, /* MT-diagnostic Counter Set */
S390_HWCTR_ALL = S390_HWCTR_BASIC | S390_HWCTR_USER |
S390_HWCTR_CRYPTO | S390_HWCTR_EXT |
S390_HWCTR_MT_DIAG
};
/* The ioctl(..., S390_HWCTR_READ, ...) is the only subcommand which returns
* data. It requires member data_bytes to be positive and indicates the
* maximum amount of data available to store counter set data. The other
* ioctl() subcommands do not use this member and it should be set to zero.
*
* The cpuset data is flattened using the following scheme, stored in member
* data:
*
* 0x0 0x8 0xc 0x10 0x14 0x18 0x20 0x28 0xU-1
* +---------+-----+---------+-----+---------+-----+-----+------+------+
* | no_cpus | cpu | no_sets | set | no_cnts | cv1 | cv2 | .... | cv_n |
* +---------+-----+---------+-----+---------+-----+-----+------+------+
*
* 0xU 0xU+4 0xU+8 0xU+10 0xV-1
* +-----+---------+-----+-----+------+------+
* | set | no_cnts | cv1 | cv2 | .... | cv_n |
* +-----+---------+-----+-----+------+------+
*
* 0xV 0xV+4 0xV+8 0xV+c
* +-----+---------+-----+---------+-----+-----+------+------+
* | cpu | no_sets | set | no_cnts | cv1 | cv2 | .... | cv_n |
* +-----+---------+-----+---------+-----+-----+------+------+
*
* U and V denote arbitrary hexadezimal addresses.
* In fact the first int represents the number of CPUs data was extracted
* from. This is followed by CPU number and number of counter sets extracted.
* Both are two integer values. This is followed by the set number and number
* of counters extracted. Both are two integer values. This is followed by
* the counter values, each element is eight bytes in size.
*/
struct s390_hwctr_start { /* Set CPUs to operate on */
uint64_t version; /* Version of interface */
uint64_t data_bytes; /* # of bytes required */
uint64_t cpumask_len; /* Length of CPU mask in bytes */
uint64_t *cpumask; /* Pointer to CPU mask */
uint64_t counter_sets; /* Bit mask of counter set to get */
};
struct s390_hwctr_setdata { /* Counter set data */
uint32_t set; /* Counter set number */
uint32_t no_cnts; /* # of counters stored in cv[] */
uint64_t cv[0]; /* Counter values (variable length) */
};
struct s390_hwctr_cpudata { /* Counter set data per CPU */
uint32_t cpu_nr; /* Counter set number */
uint32_t no_sets; /* # of counters sets in data[] */
struct s390_hwctr_setdata data[0];
};
struct s390_hwctr_read { /* Structure to get all ctr sets */
uint64_t no_cpus; /* Total # of CPUs data taken from */
struct s390_hwctr_cpudata data[0];
};
#define S390_HWCTR_MAGIC 'C' /* Random magic # for ioctls */
#define S390_HWCTR_START _IOWR(S390_HWCTR_MAGIC, 1, struct s390_hwctr_start)
#define S390_HWCTR_STOP _IO(S390_HWCTR_MAGIC, 2)
#define S390_HWCTR_READ _IOWR(S390_HWCTR_MAGIC, 3, struct s390_hwctr_read)
#define S390_HWCTR_START_VERSION 1 /* Version # s390_hwctr_start */
#define S390_HWCTR_DEVICE "/dev/hwctr" /* Device name */
#endif

134
cpumf/man/lshwc.1 Normal file
View File

@@ -0,0 +1,134 @@
.\" lshwc.1
.\"
.\"
.\" Copyright IBM Corp. 2021
.\" s390-tools is free software; you can redistribute it and/or modify
.\" it under the terms of the MIT license. See LICENSE for details.
.\" ----------------------------------------------------------------------
.ds c \fBlshwc\fP
.
.TH \*c "1" "February 2021" "s390-tools" "CPU-MF management programs"
.
.SH NAME
\*c \- extract CPU Measurement Facilities counter sets
.
.SH SYNOPSIS
\*c
.RB [ \-a ]
.RB [ \-l
.IR count ]
.RB [ \-i
.IR interval ]
\fR[\fIcpulist\fR][:\fIsets\fR]\fP
.br
\*c
.BR \-h | \-\-help
.br
\*c
.BR \-v | \-\-version
.
.
.SH DESCRIPTION
The \*c command extracts complete counter sets from the CPU
Measurement Facilities for Linux on Z.
Counter sets can be specified and extracted for individual CPUs.
The output is a comma-separated values file.
Each line starts with a timestamp and the CPU number,
followed by the extracted counter values.
.
.SH OPTIONS
.TP
.BR \-h ", " \-\-help
Displays help information, then exits.
.
.TP
.BR \-v ", " \-\-version
Displays version information, then exits.
.
.TP
.BR \-a ", " \-\-allcpu
Displays counter values from each CPU.
The default is a total summary line of all counters from all CPUs.
.
.TP
.BR \-i ", " \-\-interval \fI\ seconds\fP
Specifies a time interval, in seconds,
that the command waits between read operations.
The default is 60 seconds.
.
.TP
.BR \-l ", " \-\-loop \fI\ count\fP
Performs the specified number of read operations.
.
.TP
\fR[\fIcpulist\fR][:\fIsets\fR]\fP
A comma-separated list of CPUs.
Each CPU can optionally be followed by characters that specify the counter set.
See below for details.
.
.SS "CPU List and counter-set specification"
In the comma-separated list of CPUs,
each element is a CPU or a range of CPUs.
By default, \*c lists all CPUs.
.P
The CPU list can be followed by an optional list
of characters that specify the counter sets to be extracted,
preceded by a colon.
The characters can be upper or lower case.
By default, all counter sets are used.
.IP b
Include the basic counter set.
.IP c
Include the crypto counter set.
.IP e
Include the extended counter set.
.IP m
Include the MT_Diagnostic counter set.
.IP p|u
Include the problem counter set.
.IP a
Include all known counter sets (default).
.SH "Concurrency with perf tool"
The \*c tool and the linux
.B perf
tool use the same hardware and cannot be used concurrently.
Both tools print an error message and abort when they
detect this situation.
.SH "EXAMPLES"
The first example enables the basic and problem counter sets on CPU 0 and 1.
Two read operations are performed and a summary line is printed for each
read operation.
.sp 1
.nf
.ft CW
# lshwc -l2 0-1:BP
Date,Time,CPU,CPU_CYCLES(0),INSTRUCTIONS(1),L1I_DIR_WRITES(2),L1I_PENALTY_CYCLES(3),L1D_DIR_WRITES(4),
L1D_PENALTY_CYCLES(5),PROBLEM_STATE_CPU_CYCLES(32),PROBLEM_STATE_INSTRUCTIONS(33)
2021-04-01,11:50:32,Total,125422,39421,304,13953,454,
97489,0,0
2021-04-01,11:51:32,Total,68074231,16386850,194028,21382384,317227,
104503489,777383,14198
.ft
.fi
.sp 1
This example shows the counter values of the problem state counter set
per CPU. CPU 0 and CPU 1 is selected.
.nf
.ft CW
.sp 1
# lshwc -l3 -a 0-1:P
Date,Time,CPU,PROBLEM_STATE_CPU_CYCLES(32),PROBLEM_STATE_INSTRUCTIONS(33)
2021-04-01,11:54:47,CPU0,0,0
2021-04-01,11:54:47,CPU1,0,0
2021-04-01,11:54:47,Total,0,0
2021-04-01,11:55:47,CPU0,818775,14198
2021-04-01,11:55:47,CPU1,125689,1306
2021-04-01,11:55:47,Total,944464,15504
2021-04-01,11:56:47,CPU0,3207071426,1489122591
2021-04-01,11:56:47,CPU1,3225092021,1489278312
2021-04-01,11:56:47,Total,6432163447,2978400903
.ft
.fi
.SH "SEE ALSO"
.BR lscpumf (1)
.BR chcpumf (8)

View File

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

25
etc/hsavmcore.conf Normal file
View File

@@ -0,0 +1,25 @@
# Example configuration for hsavmcore
# See hsavmcore.conf(8) for documentation
# 0 - ERROR
# 1 - WARN
# 2 - INFO
# 3 - DEBUG
# 4 - TRACE
#verbose = 0
#workdir = /var/crash
#mount_debugfs = 0
#use_hsa_mem = 0
#hsa_size = -1
#release_hsa = 1
#bind_mount_vmcore = 1
#swap = /dev/disk/by-uuid/3cf6630b-4c4d-49ac-a0ae-0f5484cb5721
#swap = /swap.img
#fuse_debug = 0

View File

@@ -26,10 +26,10 @@ KERNEL=="dasd*[0-9]", ENV{ID_XUID}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env
LABEL="dasd_symlinks_end"
# on device add set request queue scheduler to deadline
# on device add set request queue scheduler to none
SUBSYSTEM!="block", GOTO="sched_end"
ACTION!="change", GOTO="sched_end"
KERNEL=="dasd*[!0-9]", TEST=="queue/scheduler", ATTR{queue/scheduler}="deadline"
KERNEL=="dasd*[!0-9]", TEST=="queue/scheduler", ATTR{queue/scheduler}="none"
LABEL="sched_end"

View File

@@ -94,6 +94,14 @@ this only if you trust the specified certificate. Optional.
Do not require the host-key documents to be valid. For testing
purposes, do not use for a production image. Optional.
.TP
\fB\-\-enable\-pckmo\fR
Enable the support for the DEA, TDEA, AES, and ECC PCKMO key encryption
functions. This is the default. Optional.
.TP
\fB\-\-disable\-pckmo\fR
Disable the support for the DEA, TDEA, AES, and ECC PCKMO key encryption
functions. Optional.
.TP
\fB\-v\fR, \fB\-\-version\fR
Prints version information, then exits.

View File

@@ -29,6 +29,7 @@ $(bin_PROGRAM)_OBJS := $($(bin_PROGRAM)_SRCS:.c=.o)
ALL_CFLAGS += -std=gnu11 -DPKGDATADIR=$(PKGDATADIR) \
$(GLIB2_CFLAGS) $(LIBCRYPTO_CFLAGS) $(LIBCURL_CFLAGS) \
-DOPENSSL_API_COMPAT=0x10100000L \
$(WARNINGS) \
$(NULL)
ALL_CPPFLAGS += $(INCLUDE_PARMS)

View File

@@ -24,8 +24,11 @@
#define PV_MAGIC_NUMBER 0x49424d5365634578ULL
#define PV_VERSION_1 0x00000100U
/* prevent Ultravisor decryption during unpack operation */
#define PV_CFLAG_NO_DECRYPTION 0x10000000ULL
/* Plaintext control flags */
#define PV_PCF_PCKM_ECC (1ULL << 5) /* PCKMO encrypt-ECC-key functions allowed */
#define PV_PCF_PCKMO_AES (1ULL << 6) /* PCKMO encrypt-AES-key functions allowed */
#define PV_PCF_PCKMO_DEA_TDEA (1ULL << 7) /* PCKMO encrypt-DEA/TDEA-key functions allowed */
#define PV_PCF_NO_DECRYPTION (1ULL << 28) /* prevent Ultravisor decryption during unpack operation */
/* maxima for the PV version 1 */
#define PV_V1_IPIB_MAX_SIZE PAGE_SIZE

View File

@@ -64,6 +64,13 @@ static gint pv_args_validate_options(PvArgs *args, GError **err)
{
PvComponentType KERNEL = PV_COMP_TYPE_KERNEL;
if (args->pcf && args->allow_pckmo != PV_NOT_SET) {
g_set_error(err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
_("The '--x-pcf' and '--(enable|disable)-pckmo' options are mutually"
" exclusive.\nUse 'genprotimg --help' for more information"));
return -1;
}
if (args->unused_values->len > 0) {
g_autofree gchar *unused = NULL;
@@ -181,6 +188,19 @@ static gboolean cb_set_string_option(const gchar *option, const gchar *value,
return TRUE;
}
static gboolean cb_enable_disable_flag(const gchar *option, const gchar *value G_GNUC_UNUSED,
PvArgs *args, GError **err G_GNUC_UNUSED)
{
if (g_str_equal(option, "--enable-pckmo"))
args->allow_pckmo = PV_TRUE;
else if (g_str_equal(option, "--disable-pckmo"))
args->allow_pckmo = PV_FALSE;
else
g_assert_not_reached();
return TRUE;
}
static gboolean cb_set_log_level(const gchar *option G_GNUC_UNUSED,
const gchar *value G_GNUC_UNUSED, PvArgs *args,
GError **err G_GNUC_UNUSED)
@@ -262,6 +282,21 @@ gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
.description = _("Use the kernel parameters stored in PARMFILE\n" INDENT
"(optional)."),
.arg_description = _("PARMFILE") },
{.long_name = "enable-pckmo",
.short_name = 0,
.flags = G_OPTION_FLAG_NO_ARG,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = cb_enable_disable_flag,
.description = _("Enable the support for the DEA, TDEA, AES, and\n" INDENT
"ECC PCKMO key encryption functions (default)\n" INDENT
"(optional).")},
{.long_name = "disable-pckmo",
.short_name = 0,
.flags = G_OPTION_FLAG_NO_ARG,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = cb_enable_disable_flag,
.description = _("Disable the support for the DEA, TDEA, AES, and\n" INDENT
"ECC PCKMO key encryption functions (optional).")},
{ .long_name = "crl",
.short_name = 0,
.flags = G_OPTION_FLAG_NONE,
@@ -357,7 +392,8 @@ gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
.description =
_("Specify the plaintext control flags\n" INDENT
"as a hexadecimal value.\n" INDENT
"Optional; default: '0x0'."),
"Optional; mutually exclusive with\n" INDENT
"'--(enable|disable)-pckmo'; default: '0xe0'."),
.arg_description = _("VALUE") },
{ .long_name = "x-psw",
.short_name = 0,
@@ -410,6 +446,7 @@ PvArgs *pv_args_new(void)
g_autoptr(PvArgs) args = g_new0(PvArgs, 1);
args->unused_values = g_ptr_array_new_with_free_func(g_free);
args->allow_pckmo = PV_NOT_SET;
return g_steal_pointer(&args);
}

View File

@@ -22,12 +22,19 @@ typedef struct pv_arg {
PvArg *pv_arg_new(PvComponentType type, const gchar *path);
void pv_arg_free(PvArg *arg);
typedef enum pv_tristate {
PV_NOT_SET = 0,
PV_TRUE,
PV_FALSE,
} PvTristate;
typedef struct {
gint log_level;
gint no_verify;
gboolean offline;
gchar *pcf;
gchar *scf;
PvTristate allow_pckmo;
gchar *psw_addr; /* PSW address which will be used for the start of
* the actual component (e.g. Linux kernel)
*/

View File

@@ -73,12 +73,12 @@ PvComponent *pv_component_new_file(PvComponentType type, const gchar *path,
return pv_component_new(type, size, DATA_FILE, (void **)&file, err);
}
PvComponent *pv_component_new_buf(PvComponentType type, const Buffer *buf,
PvComponent *pv_component_new_buf(PvComponentType type, const PvBuffer *buf,
GError **err)
{
g_assert(buf);
g_autoptr(Buffer) dup_buf = buffer_dup(buf, FALSE);
g_autoptr(PvBuffer) dup_buf = pv_buffer_dup(buf, FALSE);
return pv_component_new(type, buf->size, DATA_BUFFER, (void **)&dup_buf,
err);
}
@@ -90,7 +90,7 @@ void pv_component_free(PvComponent *component)
switch ((PvComponentDataType)component->d_type) {
case DATA_BUFFER:
buffer_clear(&component->buf);
pv_buffer_clear(&component->buf);
break;
case DATA_FILE:
comp_file_free(component->file);
@@ -162,21 +162,21 @@ gint pv_component_align_and_encrypt(PvComponent *component, const gchar *tmp_pat
switch ((PvComponentDataType)component->d_type) {
case DATA_BUFFER: {
g_autoptr(Buffer) enc_buf = NULL;
g_autoptr(PvBuffer) enc_buf = NULL;
if (!(IS_PAGE_ALIGNED(pv_component_size(component)))) {
g_autoptr(Buffer) new = NULL;
g_autoptr(PvBuffer) new = NULL;
/* create a page aligned copy */
new = buffer_dup(component->buf, TRUE);
buffer_clear(&component->buf);
new = pv_buffer_dup(component->buf, TRUE);
pv_buffer_clear(&component->buf);
component->buf = g_steal_pointer(&new);
}
enc_buf = encrypt_buf(parms, component->buf, err);
if (!enc_buf)
return -1;
buffer_clear(&component->buf);
pv_buffer_clear(&component->buf);
component->buf = g_steal_pointer(&enc_buf);
return 0;
}
@@ -220,10 +220,10 @@ gint pv_component_align(PvComponent *component, const gchar *tmp_path,
switch (component->d_type) {
case DATA_BUFFER: {
g_autoptr(Buffer) buf = NULL;
g_autoptr(PvBuffer) buf = NULL;
buf = buffer_dup(component->buf, TRUE);
buffer_clear(&component->buf);
buf = pv_buffer_dup(component->buf, TRUE);
pv_buffer_clear(&component->buf);
component->buf = g_steal_pointer(&buf);
return 0;
} break;
@@ -301,7 +301,7 @@ int64_t pv_component_update_pld(const PvComponent *comp, EVP_MD_CTX *ctx,
switch (comp->d_type) {
case DATA_BUFFER: {
const Buffer *buf = comp->buf;
const PvBuffer *buf = comp->buf;
g_assert(buf->size <= INT64_MAX);
g_assert(buf->size == size);
@@ -383,6 +383,7 @@ int64_t pv_component_update_tld(const PvComponent *comp, EVP_MD_CTX *ctx,
g_set_error(err, PV_CRYPTO_ERROR,
PV_CRYPTO_ERROR_INTERNAL,
_("BN_bin2bn failed"));
return -1;
}
for (uint64_t cur = 0; cur < size; cur += PAGE_SIZE) {
@@ -395,6 +396,7 @@ int64_t pv_component_update_tld(const PvComponent *comp, EVP_MD_CTX *ctx,
g_set_error(err, PV_CRYPTO_ERROR,
PV_CRYPTO_ERROR_INTERNAL,
_("BN_bn2binpad failed"));
return -1;
}
if (EVP_DigestUpdate(ctx, tmp, sizeof(tmp)) != 1) {
@@ -409,6 +411,7 @@ int64_t pv_component_update_tld(const PvComponent *comp, EVP_MD_CTX *ctx,
g_set_error(err, PV_CRYPTO_ERROR,
PV_CRYPTO_ERROR_INTERNAL,
_("BN_add_word failed"));
return -1;
}
nep++;
@@ -425,7 +428,7 @@ gint pv_component_write(const PvComponent *component, FILE *f, GError **err)
switch (component->d_type) {
case DATA_BUFFER: {
const Buffer *buf = component->buf;
const PvBuffer *buf = component->buf;
if (seek_and_write_buffer(f, buf, offset, err) < 0)
return -1;

View File

@@ -41,7 +41,7 @@ typedef struct {
gint d_type; /* PvComponentDataType */
union {
struct comp_file *file;
Buffer *buf;
PvBuffer *buf;
void *data;
};
uint64_t src_addr;
@@ -51,7 +51,7 @@ typedef struct {
PvComponent *pv_component_new_file(PvComponentType type, const gchar *path,
GError **err);
PvComponent *pv_component_new_buf(PvComponentType type, const Buffer *buf,
PvComponent *pv_component_new_buf(PvComponentType type, const PvBuffer *buf,
GError **err);
void pv_component_free(PvComponent *component);
gint pv_component_type(const PvComponent *component);

View File

@@ -210,13 +210,13 @@ GSList *pv_img_comps_get_comps(const PvImgComps *comps)
return comps->comps;
}
gint pv_img_comps_finalize(PvImgComps *comps, Buffer **pld_digest,
Buffer **ald_digest, Buffer **tld_digest,
gint pv_img_comps_finalize(PvImgComps *comps, PvBuffer **pld_digest,
PvBuffer **ald_digest, PvBuffer **tld_digest,
uint64_t *nep, GError **err)
{
g_autoptr(Buffer) tmp_pld_digest = NULL;
g_autoptr(Buffer) tmp_ald_digest = NULL;
g_autoptr(Buffer) tmp_tld_digest = NULL;
g_autoptr(PvBuffer) tmp_pld_digest = NULL;
g_autoptr(PvBuffer) tmp_ald_digest = NULL;
g_autoptr(PvBuffer) tmp_tld_digest = NULL;
comps->finalized = TRUE;
for (GSList *iterator = comps->comps; iterator; iterator = iterator->next) {

View File

@@ -32,8 +32,8 @@ gint pv_img_comps_add_component(PvImgComps *comps, PvComponent **comp,
GError **err);
PvComponent *pv_img_comps_get_nth_comp(PvImgComps *comps, guint n);
gint pv_img_comps_set_offset(PvImgComps *comps, gsize offset, GError **err);
gint pv_img_comps_finalize(PvImgComps *comps, Buffer **pld_digest,
Buffer **ald_digest, Buffer **tld_digest,
gint pv_img_comps_finalize(PvImgComps *comps, PvBuffer **pld_digest,
PvBuffer **ald_digest, PvBuffer **tld_digest,
uint64_t *nep, GError **err);
void pv_img_comps_free(PvImgComps *comps);

View File

@@ -41,7 +41,7 @@ uint32_t pv_hdr_size(const PvHdr *hdr)
gboolean pv_hdr_uses_encryption(const PvHdr *hdr)
{
return !(GUINT64_FROM_BE(hdr->head.pcf) & PV_CFLAG_NO_DECRYPTION);
return !(GUINT64_FROM_BE(hdr->head.pcf) & PV_PCF_NO_DECRYPTION);
}
uint64_t pv_hdr_enc_size(const PvHdr *hdr)
@@ -76,17 +76,17 @@ uint64_t pv_hdr_get_nks(const PvHdr *hdr)
}
/* In-place modification of ``buf`` */
static gint pv_hdr_encrypt(const PvHdr *hdr, const PvImage *img, Buffer *buf,
static gint pv_hdr_encrypt(const PvHdr *hdr, const PvImage *img, PvBuffer *buf,
GError **err)
{
uint32_t hdr_len = pv_hdr_size(hdr);
uint32_t aad_len = pv_hdr_aad_size(hdr);
guint tag_len = pv_hdr_tag_size(hdr);
uint32_t enc_len = pv_hdr_enc_size_casted(hdr);
const Buffer aad_part = { .data = buf->data, .size = aad_len };
Buffer enc_part = { .data = (uint8_t *)buf->data + aad_len,
const PvBuffer aad_part = { .data = buf->data, .size = aad_len };
PvBuffer enc_part = { .data = (uint8_t *)buf->data + aad_len,
.size = enc_len };
Buffer tag_part = { .data = (uint8_t *)buf->data + hdr_len - tag_len,
PvBuffer tag_part = { .data = (uint8_t *)buf->data + hdr_len - tag_len,
.size = tag_len };
struct cipher_parms parms;
int64_t c_len;
@@ -119,9 +119,9 @@ static gint pv_hdr_aad_init(PvHdr *hdr, const PvImage *img, GError **err)
g_autofree union ecdh_pub_key *cust_pub_key = NULL;
struct pv_hdr_key_slot *hdr_slot = hdr->slots;
struct pv_hdr_head *head = &hdr->head;
g_autoptr(Buffer) pld = NULL;
g_autoptr(Buffer) ald = NULL;
g_autoptr(Buffer) tld = NULL;
g_autoptr(PvBuffer) pld = NULL;
g_autoptr(PvBuffer) ald = NULL;
g_autoptr(PvBuffer) tld = NULL;
uint64_t nep = 0;
g_assert(sizeof(head->iv) == img->gcm_iv->size);
@@ -250,7 +250,7 @@ PvHdr *pv_hdr_new(const PvImage *img, GError **err)
return g_steal_pointer(&ret);
}
static void pv_hdr_memcpy(const PvHdr *hdr, const Buffer *dst)
static void pv_hdr_memcpy(const PvHdr *hdr, const PvBuffer *dst)
{
uint64_t nks = pv_hdr_get_nks(hdr);
uint8_t *data;
@@ -270,13 +270,13 @@ static void pv_hdr_memcpy(const PvHdr *hdr, const Buffer *dst)
}
}
Buffer *pv_hdr_serialize(const PvHdr *hdr, const PvImage *img,
enum PvCryptoMode mode, GError **err)
PvBuffer *pv_hdr_serialize(const PvHdr *hdr, const PvImage *img,
enum PvCryptoMode mode, GError **err)
{
uint32_t hdr_size = pv_hdr_size(hdr);
g_autoptr(Buffer) ret = NULL;
g_autoptr(PvBuffer) ret = NULL;
ret = buffer_alloc(hdr_size);
ret = pv_buffer_alloc(hdr_size);
pv_hdr_memcpy(hdr, ret);
if (mode == PV_ENCRYPT) {

View File

@@ -23,8 +23,8 @@
PvHdr *pv_hdr_new(const PvImage *img, GError **err);
void pv_hdr_free(PvHdr *hdr);
G_GNUC_UNUSED gboolean pv_hdr_uses_encryption(const PvHdr *hdr);
Buffer *pv_hdr_serialize(const PvHdr *hdr, const PvImage *img,
enum PvCryptoMode mode, GError **err);
PvBuffer *pv_hdr_serialize(const PvHdr *hdr, const PvImage *img,
enum PvCryptoMode mode, GError **err);
uint32_t pv_hdr_size(const PvHdr *hdr);
uint32_t pv_hdr_aad_size(const PvHdr *hdr);
uint64_t pv_hdr_enc_size(const PvHdr *hdr);

View File

@@ -56,12 +56,12 @@ static gint pv_img_prepare_component(const PvImage *img, PvComponent *comp,
GError **err)
{
struct cipher_parms parms = { 0 };
g_autoptr(Buffer) tweak = NULL;
g_autoptr(PvBuffer) tweak = NULL;
prepare_func func = NULL;
void *opaque = NULL;
gint rc;
if (img->pcf & PV_CFLAG_NO_DECRYPTION) {
if (img->pcf & PV_PCF_NO_DECRYPTION) {
/* we only need to align the components */
func = pv_component_align;
opaque = NULL;
@@ -76,7 +76,7 @@ static gint pv_img_prepare_component(const PvImage *img, PvComponent *comp,
EVP_CIPHER_iv_length(cipher));
g_assert(img->xts_key->size <= UINT_MAX);
tweak = buffer_alloc(sizeof(comp->tweak.data));
tweak = pv_buffer_alloc(sizeof(comp->tweak.data));
memcpy(tweak->data, comp->tweak.data, tweak->size);
func = pv_component_align_and_encrypt;
parms.cipher = cipher;
@@ -93,11 +93,11 @@ static gint pv_img_prepare_component(const PvImage *img, PvComponent *comp,
return 0;
}
static Buffer *pv_img_read_key(const gchar *path, guint key_size,
GError **err)
static PvBuffer *pv_img_read_key(const gchar *path, guint key_size,
GError **err)
{
g_autoptr(Buffer) tmp_ret = NULL;
Buffer *ret = NULL;
g_autoptr(PvBuffer) tmp_ret = NULL;
PvBuffer *ret = NULL;
gsize bytes_read;
FILE *f = NULL;
gsize size;
@@ -116,7 +116,7 @@ static Buffer *pv_img_read_key(const gchar *path, guint key_size,
if (!f)
return NULL;
tmp_ret = buffer_alloc(size);
tmp_ret = pv_buffer_alloc(size);
if (file_read(f, tmp_ret->data, 1, tmp_ret->size, &bytes_read, err) < 0)
goto err;
@@ -160,8 +160,8 @@ static HostKeyList *pv_img_get_host_keys(GSList *host_keys_with_path, gint nid,
return g_steal_pointer(&ret);
}
static Buffer *pv_img_get_key(const EVP_CIPHER *cipher, const gchar *path,
GError **err)
static PvBuffer *pv_img_get_key(const EVP_CIPHER *cipher, const gchar *path,
GError **err)
{
gint key_len = EVP_CIPHER_key_length(cipher);
@@ -173,8 +173,8 @@ static Buffer *pv_img_get_key(const EVP_CIPHER *cipher, const gchar *path,
return generate_aes_key((guint)key_len, err);
}
static Buffer *pv_img_get_iv(const EVP_CIPHER *cipher, const gchar *path,
GError **err)
static PvBuffer *pv_img_get_iv(const EVP_CIPHER *cipher, const gchar *path,
GError **err)
{
gint iv_len = EVP_CIPHER_iv_length(cipher);
@@ -229,7 +229,7 @@ static gint pv_img_set_psw_addr(PvImage *img, const gchar *psw_addr_s,
}
static gint pv_img_set_control_flags(PvImage *img, const gchar *pcf_s,
const gchar *scf_s, GError **err)
const gchar *scf_s, PvTristate allow_pckmo, GError **err)
{
uint64_t flags;
@@ -247,6 +247,11 @@ static gint pv_img_set_control_flags(PvImage *img, const gchar *pcf_s,
img->scf = flags;
}
if (allow_pckmo == PV_TRUE)
img->pcf |= PV_PCF_PCKM_ECC | PV_PCF_PCKMO_AES | PV_PCF_PCKMO_DEA_TDEA;
else if (allow_pckmo == PV_FALSE)
img->pcf &= ~(PV_PCF_PCKM_ECC | PV_PCF_PCKMO_AES | PV_PCF_PCKMO_DEA_TDEA);
return 0;
}
@@ -485,23 +490,23 @@ static void pv_hdr_key_slot_free(PvHdrKeySlot *slot)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvHdrKeySlot, pv_hdr_key_slot_free)
static PvHdrKeySlot *pv_hdr_key_slot_new(const EVP_CIPHER *gcm_cipher,
const Buffer *cust_root_key,
const PvBuffer *cust_root_key,
EVP_PKEY *cust_key, EVP_PKEY *host_key,
GError **err)
{
g_autoptr(PvHdrKeySlot) ret = g_new0(PvHdrKeySlot, 1);
g_autofree union ecdh_pub_key *pub = NULL;
g_autoptr(Buffer) exchange_key = NULL;
g_autoptr(Buffer) digest_key = NULL;
g_autoptr(Buffer) iv = NULL;
Buffer pub_buf;
g_autoptr(PvBuffer) exchange_key = NULL;
g_autoptr(PvBuffer) digest_key = NULL;
g_autoptr(PvBuffer) iv = NULL;
PvBuffer pub_buf;
/* No AAD data is used */
Buffer aad = { .data = NULL, .size = 0 };
PvBuffer aad = { .data = NULL, .size = 0 };
/* Set the output buffers for the encrypted data and the
* generated GCM tag
*/
Buffer enc = { .data = ret->wrapped_key, .size = sizeof(ret->wrapped_key) };
Buffer tag = { .data = ret->tag, .size = sizeof(ret->tag) };
PvBuffer enc = { .data = ret->wrapped_key, .size = sizeof(ret->wrapped_key) };
PvBuffer tag = { .data = ret->tag, .size = sizeof(ret->tag) };
struct cipher_parms parms;
int64_t c_len = 0;
@@ -530,7 +535,7 @@ static PvHdrKeySlot *pv_hdr_key_slot_new(const EVP_CIPHER *gcm_cipher,
g_assert(exchange_key->size == (guint)EVP_CIPHER_key_length(gcm_cipher));
/* create zero IV */
iv = buffer_alloc((guint)EVP_CIPHER_iv_length(gcm_cipher));
iv = pv_buffer_alloc((guint)EVP_CIPHER_iv_length(gcm_cipher));
parms.iv_or_tweak = iv;
parms.key = exchange_key;
parms.cipher = gcm_cipher;
@@ -589,6 +594,7 @@ PvImage *pv_img_new(PvArgs *args, const gchar *stage3a_path, GError **err)
if (!ret->comps)
return NULL;
ret->pcf = PV_PCF_PCKMO_AES | PV_PCF_PCKMO_DEA_TDEA | PV_PCF_PCKM_ECC;
ret->cust_comm_cipher = EVP_aes_256_gcm();
ret->gcm_cipher = EVP_aes_256_gcm();
ret->initial_psw.addr = DEFAULT_INITIAL_PSW_ADDR;
@@ -602,7 +608,7 @@ PvImage *pv_img_new(PvArgs *args, const gchar *stage3a_path, GError **err)
return NULL;
/* set the control flags: PCF and SCF */
if (pv_img_set_control_flags(ret, args->pcf, args->scf, err) < 0)
if (pv_img_set_control_flags(ret, args->pcf, args->scf, args->allow_pckmo, err) < 0)
return NULL;
/* read in the keys */
@@ -637,13 +643,13 @@ void pv_img_free(PvImage *img)
g_slist_free_full(img->key_slots, (GDestroyNotify)pv_hdr_key_slot_free);
g_slist_free_full(img->host_pub_keys, (GDestroyNotify)EVP_PKEY_free);
EVP_PKEY_free(img->cust_pub_priv_key);
buffer_clear(&img->stage3a);
pv_buffer_clear(&img->stage3a);
pv_img_comps_free(img->comps);
g_free(img->tmp_dir);
buffer_free(img->xts_key);
buffer_free(img->cust_root_key);
buffer_free(img->gcm_iv);
buffer_free(img->cust_comm_key);
pv_buffer_free(img->xts_key);
pv_buffer_free(img->cust_root_key);
pv_buffer_free(img->gcm_iv);
pv_buffer_free(img->cust_comm_key);
g_free(img);
}
@@ -684,13 +690,13 @@ gint pv_img_add_component(PvImage *img, const PvArg *arg, GError **err)
return 0;
}
gint pv_img_calc_pld_ald_tld_nep(const PvImage *img, Buffer **pld, Buffer **ald,
Buffer **tld, uint64_t *nep, GError **err)
gint pv_img_calc_pld_ald_tld_nep(const PvImage *img, PvBuffer **pld, PvBuffer **ald,
PvBuffer **tld, uint64_t *nep, GError **err)
{
return pv_img_comps_finalize(img->comps, pld, ald, tld, nep, err);
}
static gint pv_img_build_stage3b(PvImage *img, Buffer *stage3b, GError **err)
static gint pv_img_build_stage3b(PvImage *img, PvBuffer *stage3b, GError **err)
{
g_autofree struct stage3b_args *args = NULL;
@@ -708,7 +714,7 @@ static gint pv_img_build_stage3b(PvImage *img, Buffer *stage3b, GError **err)
gint pv_img_add_stage3b_comp(PvImage *img, const gchar *path, GError **err)
{
g_autoptr(PvComponent) comp = NULL;
g_autoptr(Buffer) stage3b = NULL;
g_autoptr(PvBuffer) stage3b = NULL;
stage3b = stage3b_getblob(path, err);
if (!stage3b)
@@ -825,7 +831,7 @@ static gint get_stage3a_data_size(const PvImage *img, gsize *data_size,
gint pv_img_load_and_set_stage3a(PvImage *img, const gchar *path, GError **err)
{
g_autoptr(Buffer) stage3a = NULL;
g_autoptr(PvBuffer) stage3a = NULL;
gsize bin_size, data_size = 0;
if (get_stage3a_data_size(img, &data_size, err) < 0)
@@ -845,8 +851,8 @@ gint pv_img_load_and_set_stage3a(PvImage *img, const gchar *path, GError **err)
}
/* Creates the PV IPIB and sets the stage3a arguments */
static gint pv_img_build_stage3a(Buffer *stage3a, gsize stage3a_bin_size,
GSList *comps, const Buffer *hdr, GError **err)
static gint pv_img_build_stage3a(PvBuffer *stage3a, gsize stage3a_bin_size,
GSList *comps, const PvBuffer *hdr, GError **err)
{
g_autofree struct ipl_parameter_block *ipib = NULL;
@@ -866,9 +872,9 @@ static gint pv_img_build_stage3a(Buffer *stage3a, gsize stage3a_bin_size,
}
/* Creates the actual PV header (serialized and AES-GCM encrypted) */
static Buffer *pv_img_create_pv_hdr(PvImage *img, GError **err)
static PvBuffer *pv_img_create_pv_hdr(PvImage *img, GError **err)
{
g_autoptr(Buffer) hdr_buf = NULL;
g_autoptr(PvBuffer) hdr_buf = NULL;
g_autoptr(PvHdr) hdr = NULL;
hdr = pv_hdr_new(img, err);
@@ -887,7 +893,7 @@ static Buffer *pv_img_create_pv_hdr(PvImage *img, GError **err)
*/
gint pv_img_finalize(PvImage *pv, const gchar *stage3b_path, GError **err)
{
g_autoptr(Buffer) hdr = NULL;
g_autoptr(PvBuffer) hdr = NULL;
/* load stage3b template into memory and add it to the list of
* components. This must be done before calling

View File

@@ -25,7 +25,7 @@
typedef struct {
gchar *tmp_dir; /* directory used for temporary files */
Buffer *stage3a; /* stage3a containing IPIB and PV header */
PvBuffer *stage3a; /* stage3a containing IPIB and PV header */
gsize stage3a_bin_size; /* size of stage3a.bin */
struct psw_t stage3a_psw; /* (short) PSW that is written to
* location 0 of the created image
@@ -35,15 +35,15 @@ typedef struct {
GSList *host_pub_keys; /* public host keys */
gint nid; /* Elliptic Curve used for the key derivation */
/* keys and cipher used for the AES-GCM encryption */
Buffer *cust_root_key;
Buffer *gcm_iv;
PvBuffer *cust_root_key;
PvBuffer *gcm_iv;
const EVP_CIPHER *gcm_cipher;
/* Information for the IPIB and PV header */
uint64_t pcf;
uint64_t scf;
Buffer *cust_comm_key;
PvBuffer *cust_comm_key;
const EVP_CIPHER *cust_comm_cipher;
Buffer *xts_key;
PvBuffer *xts_key;
const EVP_CIPHER *xts_cipher;
GSList *key_slots;
GSList *optional_items;
@@ -54,8 +54,8 @@ PvImage *pv_img_new(PvArgs *args, const gchar *stage3a_path, GError **err);
void pv_img_free(PvImage *img);
gint pv_img_add_component(PvImage *img, const PvArg *arg, GError **err);
gint pv_img_finalize(PvImage *img, const gchar *stage3b_path, GError **err);
gint pv_img_calc_pld_ald_tld_nep(const PvImage *img, Buffer **pld, Buffer **ald,
Buffer **tld, uint64_t *nep, GError **err);
gint pv_img_calc_pld_ald_tld_nep(const PvImage *img, PvBuffer **pld, PvBuffer **ald,
PvBuffer **tld, uint64_t *nep, GError **err);
gint pv_img_load_and_set_stage3a(PvImage *img, const gchar *path, GError **err);
const PvComponent *pv_img_get_stage3b_comp(const PvImage *img, GError **err);
gint pv_img_add_stage3b_comp(PvImage *img, const gchar *path, GError **err);

View File

@@ -35,7 +35,7 @@ uint64_t pv_ipib_get_size(uint32_t num_comp)
}
static gint pv_ipib_init(IplParameterBlock *ipib, GSList *comps,
const Buffer *hdr)
const PvBuffer *hdr)
{
g_assert(sizeof(struct ipl_pl_hdr) <= UINT32_MAX);
g_assert(sizeof(struct ipl_pb0_pv_comp) <= UINT32_MAX);
@@ -100,7 +100,7 @@ static gint pv_ipib_init(IplParameterBlock *ipib, GSList *comps,
return 0;
}
IplParameterBlock *pv_ipib_new(GSList *comps, const Buffer *hdr, GError **err)
IplParameterBlock *pv_ipib_new(GSList *comps, const PvBuffer *hdr, GError **err)
{
uint64_t ipib_size = pv_ipib_get_size(g_slist_length(comps));
g_autoptr(IplParameterBlock) ret = NULL;

View File

@@ -19,7 +19,7 @@
typedef struct ipl_parameter_block IplParameterBlock;
uint64_t pv_ipib_get_size(uint32_t num_comp);
IplParameterBlock *pv_ipib_new(GSList *comps, const Buffer *hdr, GError **err);
IplParameterBlock *pv_ipib_new(GSList *comps, const PvBuffer *hdr, GError **err);
void pv_ipib_free(IplParameterBlock *ipib);
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(IplParameterBlock, pv_ipib_free)

View File

@@ -24,12 +24,12 @@
((struct stage3a_args *)((uint64_t)data_ptr + loader_size - \
sizeof(struct stage3a_args)))
static Buffer *loader_getblob(const gchar *filename, gsize *loader_size,
gsize args_size, gsize data_size,
gboolean data_aligned, GError **err)
static PvBuffer *loader_getblob(const gchar *filename, gsize *loader_size,
gsize args_size, gsize data_size,
gboolean data_aligned, GError **err)
{
g_autoptr(GMappedFile) mapped_file = NULL;
g_autoptr(Buffer) ret = NULL;
g_autoptr(PvBuffer) ret = NULL;
gsize size, tmp_loader_size;
gchar *loader_data;
@@ -60,7 +60,7 @@ static Buffer *loader_getblob(const gchar *filename, gsize *loader_size,
size = (data_aligned ? PAGE_ALIGN(tmp_loader_size) : tmp_loader_size) +
data_size;
ret = buffer_alloc(size);
ret = pv_buffer_alloc(size);
/* copy the loader "template" */
memcpy(ret->data, loader_data, tmp_loader_size);
@@ -71,8 +71,8 @@ static Buffer *loader_getblob(const gchar *filename, gsize *loader_size,
return g_steal_pointer(&ret);
}
Buffer *stage3a_getblob(const gchar *filename, gsize *loader_size,
gsize data_size, GError **err)
PvBuffer *stage3a_getblob(const gchar *filename, gsize *loader_size,
gsize data_size, GError **err)
{
return loader_getblob(filename, loader_size,
sizeof(struct stage3a_args), data_size, TRUE,
@@ -83,8 +83,8 @@ Buffer *stage3a_getblob(const gchar *filename, gsize *loader_size,
/* Set the right offsets and sizes in the stage3a template + add
* the IPIB block with the PV header
*/
static gint stage3a_set_data(Buffer *loader, gsize loader_size,
const Buffer *hdr, struct ipl_parameter_block *ipib,
static gint stage3a_set_data(PvBuffer *loader, gsize loader_size,
const PvBuffer *hdr, struct ipl_parameter_block *ipib,
GError **err)
{
uint32_t ipib_size = GUINT32_FROM_BE(ipib->hdr.len);
@@ -126,15 +126,15 @@ static gint stage3a_set_data(Buffer *loader, gsize loader_size,
return 0;
}
gint build_stage3a(Buffer *loader, gsize loader_size, const Buffer *hdr,
gint build_stage3a(PvBuffer *loader, gsize loader_size, const PvBuffer *hdr,
struct ipl_parameter_block *ipib, GError **err)
{
return stage3a_set_data(loader, loader_size, hdr, ipib, err);
}
Buffer *stage3b_getblob(const gchar *filename, GError **err)
PvBuffer *stage3b_getblob(const gchar *filename, GError **err)
{
g_autoptr(Buffer) ret = NULL;
g_autoptr(PvBuffer) ret = NULL;
gsize rb_size;
ret = loader_getblob(filename, &rb_size, sizeof(struct stage3b_args), 0,
@@ -146,7 +146,7 @@ Buffer *stage3b_getblob(const gchar *filename, GError **err)
return g_steal_pointer(&ret);
}
void build_stage3b(Buffer *stage3b, const struct stage3b_args *args)
void build_stage3b(PvBuffer *stage3b, const struct stage3b_args *args)
{
g_assert(stage3b->size > sizeof(*args));

View File

@@ -19,12 +19,12 @@
#include "boot/stage3b.h"
#include "utils/buffer.h"
Buffer *stage3a_getblob(const gchar *filename, gsize *loader_size,
gsize data_size, GError **err);
gint build_stage3a(Buffer *dc, gsize dc_size, const Buffer *hdr,
PvBuffer *stage3a_getblob(const gchar *filename, gsize *loader_size,
gsize data_size, GError **err);
gint build_stage3a(PvBuffer *dc, gsize dc_size, const PvBuffer *hdr,
struct ipl_parameter_block *ipib, GError **err);
Buffer *stage3b_getblob(const gchar *filename, GError **err);
void build_stage3b(Buffer *stage3b, const struct stage3b_args *args);
PvBuffer *stage3b_getblob(const gchar *filename, GError **err);
void build_stage3b(PvBuffer *stage3b, const struct stage3b_args *args);
void memblob_init(struct memblob *arg, uint64_t src, uint64_t size);
#endif

View File

@@ -17,18 +17,18 @@
#include "common.h"
#include "file_utils.h"
Buffer *buffer_alloc(gsize size)
PvBuffer *pv_buffer_alloc(gsize size)
{
Buffer *ret = g_new0(Buffer, 1);
PvBuffer *ret = g_new0(PvBuffer, 1);
ret->data = g_malloc0(size);
ret->size = size;
return ret;
}
Buffer *buffer_dup(const Buffer *buf, gboolean page_aligned)
PvBuffer *pv_buffer_dup(const PvBuffer *buf, gboolean page_aligned)
{
Buffer *ret;
PvBuffer *ret;
gsize size;
if (!buf)
@@ -38,19 +38,19 @@ Buffer *buffer_dup(const Buffer *buf, gboolean page_aligned)
if (page_aligned)
size = PAGE_ALIGN(size);
ret = buffer_alloc(size);
ret = pv_buffer_alloc(size);
/* content will be 0-right-padded */
memcpy(ret->data, buf->data, buf->size);
return ret;
}
gint buffer_write(const Buffer *buf, FILE *file, GError **err)
gint pv_buffer_write(const PvBuffer *buf, FILE *file, GError **err)
{
return file_write(file, buf->data, buf->size, 1, NULL, err);
}
void buffer_free(Buffer *buf)
void pv_buffer_free(PvBuffer *buf)
{
if (!buf)
return;
@@ -59,11 +59,11 @@ void buffer_free(Buffer *buf)
g_free(buf);
}
void buffer_clear(Buffer **buf)
void pv_buffer_clear(PvBuffer **buf)
{
if (!buf || !*buf)
return;
buffer_free(*buf);
pv_buffer_free(*buf);
*buf = NULL;
}

View File

@@ -15,17 +15,17 @@
#include "common.h"
typedef struct Buffer {
typedef struct PvBuffer {
void *data;
gsize size; /* in bytes */
} Buffer;
} PvBuffer;
Buffer *buffer_alloc(gsize size);
void buffer_free(Buffer *buf);
void buffer_clear(Buffer **buf);
gint buffer_write(const Buffer *buf, FILE *file, GError **err);
Buffer *buffer_dup(const Buffer *buf, gboolean page_aligned);
PvBuffer *pv_buffer_alloc(gsize size);
void pv_buffer_free(PvBuffer *buf);
void pv_buffer_clear(PvBuffer **buf);
gint pv_buffer_write(const PvBuffer *buf, FILE *file, GError **err);
PvBuffer *pv_buffer_dup(const PvBuffer *buf, gboolean page_aligned);
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(Buffer, buffer_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvBuffer, pv_buffer_free)
#endif

View File

@@ -31,6 +31,7 @@
#include "buffer.h"
#include "curl.h"
#include "openssl_compat.h"
#include "crypto.h"
#define DEFINE_GSLIST_MAP(t2, t1) \
@@ -89,15 +90,15 @@ EVP_MD_CTX *digest_ctx_new(const EVP_MD *md, GError **err)
return g_steal_pointer(&ctx);
}
Buffer *digest_ctx_finalize(EVP_MD_CTX *ctx, GError **err)
PvBuffer *digest_ctx_finalize(EVP_MD_CTX *ctx, GError **err)
{
gint md_size = EVP_MD_size(EVP_MD_CTX_md(ctx));
g_autoptr(Buffer) ret = NULL;
g_autoptr(PvBuffer) ret = NULL;
guint digest_size;
g_assert(md_size > 0);
ret = buffer_alloc((guint)md_size);
ret = pv_buffer_alloc((guint)md_size);
if (EVP_DigestFinal_ex(ctx, ret->data, &digest_size) != 1) {
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
_("EVP_DigestFinal_ex failed"));
@@ -110,10 +111,10 @@ Buffer *digest_ctx_finalize(EVP_MD_CTX *ctx, GError **err)
}
/* Returns the digest of @buf using the hash algorithm @md */
static Buffer *digest_buffer(const EVP_MD *md, const Buffer *buf, GError **err)
static PvBuffer *digest_buffer(const EVP_MD *md, const PvBuffer *buf, GError **err)
{
g_autoptr(EVP_MD_CTX) md_ctx = NULL;
g_autoptr(Buffer) ret = NULL;
g_autoptr(PvBuffer) ret = NULL;
g_assert(buf);
md_ctx = digest_ctx_new(md, err);
@@ -134,9 +135,9 @@ static Buffer *digest_buffer(const EVP_MD *md, const Buffer *buf, GError **err)
}
/* Returns the SHA256 digest of @buf */
Buffer *sha256_buffer(const Buffer *buf, GError **err)
PvBuffer *sha256_buffer(const PvBuffer *buf, GError **err)
{
g_autoptr(Buffer) ret = NULL;
g_autoptr(PvBuffer) ret = NULL;
ret = digest_buffer(EVP_sha256(), buf, err);
if (!ret)
@@ -207,10 +208,10 @@ union ecdh_pub_key *evp_pkey_to_ecdh_pub_key(EVP_PKEY *key, GError **err)
return g_steal_pointer(&ret);
}
static Buffer *derive_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err)
static PvBuffer *derive_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err)
{
g_autoptr(EVP_PKEY_CTX) ctx = NULL;
g_autoptr(Buffer) ret = NULL;
g_autoptr(PvBuffer) ret = NULL;
gsize key_size;
ctx = EVP_PKEY_CTX_new(cust, NULL);
@@ -236,7 +237,7 @@ static Buffer *derive_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err)
return NULL;
}
ret = buffer_alloc(key_size);
ret = pv_buffer_alloc(key_size);
if (EVP_PKEY_derive(ctx, ret->data, &key_size) != 1) {
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_DERIVE,
_("Key derivation failed"));
@@ -247,11 +248,11 @@ static Buffer *derive_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err)
return g_steal_pointer(&ret);
}
Buffer *compute_exchange_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err)
PvBuffer *compute_exchange_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err)
{
g_autoptr(Buffer) raw = buffer_alloc(70);
g_autoptr(Buffer) ret = NULL;
g_autoptr(Buffer) key = NULL;
g_autoptr(PvBuffer) raw = pv_buffer_alloc(70);
g_autoptr(PvBuffer) ret = NULL;
g_autoptr(PvBuffer) key = NULL;
guchar *data;
key = derive_key(cust, host, err);
@@ -290,10 +291,10 @@ gint generate_tweak(union tweak *tweak, uint16_t i, GError **err)
return 0;
}
static Buffer *generate_rand_data(guint size, const gchar *err_msg,
GError **err)
static PvBuffer *generate_rand_data(guint size, const gchar *err_msg,
GError **err)
{
g_autoptr(Buffer) buf = buffer_alloc(size);
g_autoptr(PvBuffer) buf = pv_buffer_alloc(size);
g_assert(size <= INT_MAX);
@@ -307,14 +308,14 @@ static Buffer *generate_rand_data(guint size, const gchar *err_msg,
return g_steal_pointer(&buf);
}
Buffer *generate_aes_iv(guint size, GError **err)
PvBuffer *generate_aes_iv(guint size, GError **err)
{
return generate_rand_data(size,
_("Generating a IV failed because the required amount of random data is not available"),
err);
}
Buffer *generate_aes_key(guint size, GError **err)
PvBuffer *generate_aes_key(guint size, GError **err)
{
return generate_rand_data(size,
_("Generating a key failed because the required amount of random data is not available"),
@@ -440,10 +441,14 @@ static int check_signature_algo_match(const EVP_PKEY *pkey, const X509 *subject,
static X509_CRL *load_crl_from_bio(BIO *bio)
{
g_autoptr(X509_CRL) crl = PEM_read_bio_X509_CRL(bio, NULL, 0, NULL);
gint rc;
if (crl)
return g_steal_pointer(&crl);
ERR_clear_error();
BIO_reset(bio);
rc = BIO_reset(bio);
if (rc != 1 || (rc != 0 && BIO_method_type(bio) == BIO_TYPE_FILE))
return NULL;
/* maybe the CRL is stored in DER format */
crl = d2i_X509_CRL_bio(bio, NULL);
@@ -514,6 +519,7 @@ X509 *load_cert_from_file(const char *path, GError **err)
{
g_autoptr(BIO) bio = bio_read_from_file(path);
g_autoptr(X509) cert = NULL;
gint rc;
if (!bio) {
g_set_error(err, PV_CRYPTO_ERROR,
@@ -526,7 +532,12 @@ X509 *load_cert_from_file(const char *path, GError **err)
if (cert)
return g_steal_pointer(&cert);
ERR_clear_error();
BIO_reset(bio);
rc = BIO_reset(bio);
if (rc != 1 || (rc != 0 && BIO_method_type(bio) == BIO_TYPE_FILE)) {
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_READ_CERTIFICATE,
_("unable to load certificate: '%s'"), path);
return NULL;
}
/* maybe the certificate is stored in DER format */
cert = d2i_X509_bio(bio, NULL);
@@ -1428,7 +1439,7 @@ static const char *get_first_dp_url(DIST_POINT *dp)
return NULL;
}
static gboolean insert_crl(X509_NAME *name, X509_CRL *crl)
static gboolean insert_crl(const X509_NAME *name, X509_CRL *crl)
{
g_autofree gchar *key = NULL;
@@ -1443,7 +1454,7 @@ static gboolean insert_crl(X509_NAME *name, X509_CRL *crl)
}
/* Caller is responsible for free'ing */
static X509_CRL *lookup_crl(X509_NAME *name)
static X509_CRL *lookup_crl(const X509_NAME *name)
{
g_autoptr(X509_CRL) crl = NULL;
g_autofree gchar *key = NULL;
@@ -1463,7 +1474,7 @@ static X509_CRL *lookup_crl(X509_NAME *name)
}
/* Returns empty stack if no CRL downloaded. */
static STACK_OF_X509_CRL *crls_download_cb(X509_STORE_CTX *ctx, X509_NAME *nm)
static STACK_OF_X509_CRL *crls_download_cb(const X509_STORE_CTX *ctx, const X509_NAME *nm)
{
g_autoptr(STACK_OF_X509_CRL) crls = NULL;
g_autoptr(X509_CRL) crl = NULL;
@@ -1473,7 +1484,7 @@ static STACK_OF_X509_CRL *crls_download_cb(X509_STORE_CTX *ctx, X509_NAME *nm)
crls = sk_X509_CRL_new_null();
if (!crls)
g_abort();
cert = X509_STORE_CTX_get_current_cert(ctx);
cert = Pv_X509_STORE_CTX_get_current_cert(ctx);
if (!cert)
return g_steal_pointer(&crls);
g_assert(X509_NAME_cmp(X509_get_issuer_name(cert), nm) == 0);
@@ -1517,19 +1528,19 @@ void STACK_OF_X509_CRL_free(STACK_OF_X509_CRL *stack)
/* Downloaded CRLs have a higher precedence than the CRLs specified on the
* command line.
*/
static STACK_OF_X509_CRL *crls_cb(X509_STORE_CTX *ctx, X509_NAME *nm)
static STACK_OF_X509_CRL *crls_cb(const X509_STORE_CTX *ctx, const X509_NAME *nm)
{
g_autoptr(STACK_OF_X509_CRL) crls = crls_download_cb(ctx, nm);
if (sk_X509_CRL_num(crls) > 0)
return g_steal_pointer(&crls);
return X509_STORE_CTX_get1_crls(ctx, nm);
return Pv_X509_STORE_CTX_get1_crls(ctx, nm);
}
/* Set up CRL lookup with download support */
void store_setup_crl_download(X509_STORE *st)
{
X509_STORE_set_lookup_crls(st, crls_cb);
Pv_X509_STORE_set_lookup_crls(st, crls_cb);
}
/* Download a CRL using the URI specified in the distribution @crldp */
@@ -1645,8 +1656,8 @@ gint verify_host_key(X509 *host_key, GSList *issuer_pairs,
}
if (!(verify_flags & X509_V_FLAG_NO_CHECK_TIME)) {
const ASN1_TIME *last = X509_get_notBefore(host_key);
const ASN1_TIME *next = X509_get_notAfter(host_key);
const ASN1_TIME *last = X509_get0_notBefore(host_key);
const ASN1_TIME *next = X509_get0_notAfter(host_key);
if (!last || !next || check_validity_period(last, next)) {
g_set_error(err, PV_CRYPTO_ERROR,
@@ -1756,8 +1767,8 @@ static gint __encrypt_decrypt_bio(const struct cipher_parms *parms, BIO *b_in,
gint cipher_block_size = EVP_CIPHER_block_size(cipher);
guchar in_buf[PAGE_SIZE],
out_buf[PAGE_SIZE + (guint)cipher_block_size];
const Buffer *key = parms->key;
const Buffer *tweak = parms->iv_or_tweak;
const PvBuffer *key = parms->key;
const PvBuffer *tweak = parms->iv_or_tweak;
g_autofree guchar *tmp_tweak = NULL;
gint out_len, tweak_size;
gsize tmp_size_in = 0, tmp_size_out = 0;
@@ -1847,6 +1858,7 @@ static gint __encrypt_decrypt_bio(const struct cipher_parms *parms, BIO *b_in,
g_set_error(err, PV_CRYPTO_ERROR,
PV_CRYPTO_ERROR_INTERNAL,
_("BN_add_word failed"));
return -1;
}
g_assert(BN_num_bytes(tweak_num) > 0);
g_assert(BN_num_bytes(tweak_num) <= tweak_size);
@@ -1855,6 +1867,7 @@ static gint __encrypt_decrypt_bio(const struct cipher_parms *parms, BIO *b_in,
g_set_error(err, PV_CRYPTO_ERROR,
PV_CRYPTO_ERROR_INTERNAL,
_("BN_bn2binpad failed"));
return -1;
};
/* set new tweak */
@@ -1895,11 +1908,11 @@ static gint __encrypt_decrypt_bio(const struct cipher_parms *parms, BIO *b_in,
return 0;
}
static Buffer *__encrypt_decrypt_buffer(const struct cipher_parms *parms,
const Buffer *in, gboolean encrypt,
GError **err)
static PvBuffer *__encrypt_decrypt_buffer(const struct cipher_parms *parms,
const PvBuffer *in, gboolean encrypt,
GError **err)
{
g_autoptr(Buffer) ret = NULL;
g_autoptr(PvBuffer) ret = NULL;
g_autoptr(BIO) b_out = NULL;
g_autoptr(BIO) b_in = NULL;
gsize in_size, out_size;
@@ -1927,19 +1940,19 @@ static Buffer *__encrypt_decrypt_buffer(const struct cipher_parms *parms,
return NULL;
}
ret = buffer_alloc((unsigned long)data_size);
ret = pv_buffer_alloc((unsigned long)data_size);
memcpy(ret->data, data, ret->size);
return g_steal_pointer(&ret);
}
Buffer *encrypt_buf(const struct cipher_parms *parms, const Buffer *in,
GError **err)
PvBuffer *encrypt_buf(const struct cipher_parms *parms, const PvBuffer *in,
GError **err)
{
return __encrypt_decrypt_buffer(parms, in, TRUE, err);
}
Buffer *decrypt_buf(const struct cipher_parms *parms, const Buffer *in,
GError **err)
PvBuffer *decrypt_buf(const struct cipher_parms *parms, const PvBuffer *in,
GError **err)
{
return __encrypt_decrypt_buffer(parms, in, FALSE, err);
}
@@ -1993,16 +2006,16 @@ G_GNUC_UNUSED static gint decrypt_file(const struct cipher_parms *parms,
}
/* GCM mode uses (zero-)padding */
static int64_t gcm_encrypt_decrypt(const Buffer *in, const Buffer *aad,
static int64_t gcm_encrypt_decrypt(const PvBuffer *in, const PvBuffer *aad,
const struct cipher_parms *parms,
Buffer *out, Buffer *tag,
PvBuffer *out, PvBuffer *tag,
enum PvCryptoMode mode, GError **err)
{
g_autoptr(EVP_CIPHER_CTX) ctx = NULL;
const EVP_CIPHER *cipher = parms->cipher;
const Buffer *iv = parms->iv_or_tweak;
const PvBuffer *iv = parms->iv_or_tweak;
gboolean encrypt = mode == PV_ENCRYPT;
const Buffer *key = parms->key;
const PvBuffer *key = parms->key;
int64_t ret = -1;
gint len = -1;
@@ -2097,8 +2110,8 @@ static int64_t gcm_encrypt_decrypt(const Buffer *in, const Buffer *aad,
return ret;
}
int64_t gcm_encrypt(const Buffer *in, const Buffer *aad,
const struct cipher_parms *parms, Buffer *out, Buffer *tag,
int64_t gcm_encrypt(const PvBuffer *in, const PvBuffer *aad,
const struct cipher_parms *parms, PvBuffer *out, PvBuffer *tag,
GError **err)
{
return gcm_encrypt_decrypt(in, aad, parms, out, tag, PV_ENCRYPT, err);

View File

@@ -117,8 +117,8 @@ union tweak {
struct cipher_parms {
const EVP_CIPHER *cipher;
const Buffer *key;
const Buffer *iv_or_tweak;
const PvBuffer *key;
const PvBuffer *iv_or_tweak;
};
int check_crl_valid_for_cert(X509_CRL *crl, X509 *cert,
@@ -152,24 +152,24 @@ X509_CRL *get_first_valid_crl(X509_STORE_CTX *ctx, X509 *cert, GError **err);
void store_setup_crl_download(X509_STORE *st);
EVP_PKEY *read_ec_pubkey_cert(X509 *cert, gint nid, GError **err);
Buffer *compute_exchange_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err);
Buffer *generate_aes_key(guint size, GError **err);
Buffer *generate_aes_iv(guint size, GError **err);
PvBuffer *compute_exchange_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err);
PvBuffer *generate_aes_key(guint size, GError **err);
PvBuffer *generate_aes_iv(guint size, GError **err);
EVP_PKEY *generate_ec_key(gint nid, GError **err);
gint generate_tweak(union tweak *tweak, uint16_t i, GError **err);
union ecdh_pub_key *evp_pkey_to_ecdh_pub_key(EVP_PKEY *key, GError **err);
EVP_MD_CTX *digest_ctx_new(const EVP_MD *md, GError **err);
Buffer *digest_ctx_finalize(EVP_MD_CTX *ctx, GError **err);
Buffer *sha256_buffer(const Buffer *buf, GError **err);
int64_t gcm_encrypt(const Buffer *in, const Buffer *aad,
const struct cipher_parms *parms, Buffer *out,
Buffer *tag, GError **err);
PvBuffer *digest_ctx_finalize(EVP_MD_CTX *ctx, GError **err);
PvBuffer *sha256_buffer(const PvBuffer *buf, GError **err);
int64_t gcm_encrypt(const PvBuffer *in, const PvBuffer *aad,
const struct cipher_parms *parms, PvBuffer *out,
PvBuffer *tag, GError **err);
gint encrypt_file(const struct cipher_parms *parms, const gchar *in_path,
const gchar *path_out, gsize *in_size, gsize *out_size,
GError **err);
Buffer *encrypt_buf(const struct cipher_parms *parms, const Buffer *in,
GError **err);
G_GNUC_UNUSED Buffer *decrypt_buf(const struct cipher_parms *parms,
const Buffer *in, GError **err);
PvBuffer *encrypt_buf(const struct cipher_parms *parms, const PvBuffer *in,
GError **err);
G_GNUC_UNUSED PvBuffer *decrypt_buf(const struct cipher_parms *parms,
const PvBuffer *in, GError **err);
#endif

View File

@@ -171,13 +171,13 @@ err:
return ret;
}
gint seek_and_write_buffer(FILE *o, const Buffer *buf, uint64_t offset,
gint seek_and_write_buffer(FILE *o, const PvBuffer *buf, uint64_t offset,
GError **err)
{
if (file_seek(o, offset, err) < 0)
return -1;
if (buffer_write(buf, o, err) < 0)
if (pv_buffer_write(buf, o, err) < 0)
return -1;
return 0;

View File

@@ -26,7 +26,7 @@ gint file_write(FILE *out, const void *ptr, gsize size, gsize count,
gsize *count_written, GError **err);
gint pad_file_right(const gchar *path_out, const gchar *path_in,
gsize *size_out, guint padding, GError **err);
gint seek_and_write_buffer(FILE *out, const Buffer *buf, uint64_t offset,
gint seek_and_write_buffer(FILE *out, const PvBuffer *buf, uint64_t offset,
GError **err);
gint seek_and_write_file(FILE *o, const CompFile *ifile, uint64_t offset,
GError **err);

View File

@@ -0,0 +1,33 @@
/*
* OpenSSL compatibility utils
*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PV_UTILS_OPENSSL_COMPAT_H
#define PV_UTILS_OPENSSL_COMPAT_H
#include <openssl/opensslv.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#if OPENSSL_VERSION_NUMBER < 0x30000000L
#define Pv_X509_STORE_CTX_get_current_cert(ctx) \
X509_STORE_CTX_get_current_cert((X509_STORE_CTX *)(ctx))
#define Pv_X509_STORE_CTX_get1_crls(ctx, nm) \
X509_STORE_CTX_get1_crls((X509_STORE_CTX *)(ctx), (X509_NAME *)(nm))
#define Pv_X509_STORE_set_lookup_crls(st, cb) \
X509_STORE_set_lookup_crls(st, (X509_STORE_CTX_lookup_crls_fn)(cb))
#else
#define Pv_X509_STORE_CTX_get_current_cert(ctx) \
X509_STORE_CTX_get_current_cert(ctx)
#define Pv_X509_STORE_CTX_get1_crls(ctx, nm) \
X509_STORE_CTX_get1_crls(ctx, nm)
#define Pv_X509_STORE_set_lookup_crls(st, cb) \
X509_STORE_set_lookup_crls(st, cb)
#endif
#endif

87
hsavmcore/Makefile Normal file
View File

@@ -0,0 +1,87 @@
#
# Copyright IBM Corp. 2021
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
#
include ../common.mak
ALL_CPPFLAGS += -D_FILE_OFFSET_BITS=64
ifeq (${HAVE_FUSE},0)
all:
$(SKIP) HAVE_FUSE=0
install:
$(SKIP) HAVE_FUSE=0
else # HAVE_FUSE
#
# FUSE
#
ifneq ($(shell sh -c 'command -v pkg-config'),)
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse)
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse)
else
FUSE_CFLAGS = -I/usr/include/fuse
FUSE_LDLIBS = -lfuse
endif
#
# systemd
#
ifneq (${HAVE_SYSTEMD},0)
ifeq ($(call check_header_prereq,"systemd/sd-daemon.h"),yes)
ifneq ($(shell sh -c 'command -v pkg-config'),)
SYSTEMD_CFLAGS = $(shell pkg-config --silence-errors --cflags libsystemd)
SYSTEMD_LDLIBS = $(shell pkg-config --silence-errors --libs libsystemd)
else
SYSTEMD_CFLAGS =
SYSTEMD_LDLIBS = -lsystemd
endif
ALL_CPPFLAGS += -DHAVE_SYSTEMD
else
$(warning "systemd support disabled")
endif
endif
ALL_CFLAGS += $(FUSE_CFLAGS) $(SYSTEMD_CFLAGS)
LDLIBS += $(FUSE_LDLIBS) $(SYSTEMD_LDLIBS) -lpthread
sources := $(wildcard *.c)
objects := $(patsubst %.c,%.o,$(sources))
libs = $(rootdir)/libutil/libutil.a
all: hsavmcore
hsavmcore: $(objects) $(libs)
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
overlay.o: check-dep-fuse overlay.c overlay.h
check-dep-fuse:
$(call check_dep, \
"hsavmcore", \
"fuse.h", \
"fuse-devel or libfuse-dev", \
"HAVE_FUSE=0")
touch check-dep-fuse
install: all
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 hsavmcore \
$(DESTDIR)$(USRSBINDIR)
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 man/hsavmcore.8 \
$(DESTDIR)$(MANDIR)/man8
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 man/hsavmcore.conf.5 \
$(DESTDIR)$(MANDIR)/man5
endif # HAVE_FUSE
clean:
rm -f hsavmcore $(objects) check-dep-fuse
.PHONY: all install clean

219
hsavmcore/cmdline_options.c Normal file
View File

@@ -0,0 +1,219 @@
/*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lib/zt_common.h"
#include "lib/util_opt.h"
#include "lib/util_prg.h"
#include "lib/util_log.h"
#include "cmdline_options.h"
static const struct util_prg prg = {
.desc = "hsavmcore is designed to make the dump process with kdump more "
"efficient. The HSA memory contains a part of the production "
"kernel's memory. Use hsavmcore to cache this information and "
"release HSA memory early in the process.",
.copyright_vec = {
{
.owner = "IBM Corp.",
.pub_first = 2021,
.pub_last = 2021,
},
UTIL_PRG_COPYRIGHT_END
}
};
static struct util_opt opt_vec[] = {
UTIL_OPT_SECTION("CONFIGURATION"),
{
.option = { "config", required_argument, NULL, 'c' },
.argument = "CONFIGFILE",
.desc = "Path to the configuration file.\n"
"Default: no configuration file is used",
},
{
.option = { "vmcore", required_argument, NULL, 'C' },
.argument = "VMCOREFILE",
.desc = "Path to the vmcore file.\n"
"Default: " PROC_VMCORE,
},
{
.option = { "hsa", required_argument, NULL, 'H' },
.argument = "ZCOREHSAFILE",
.desc = "Path to the zcore HSA file.\n"
"Default: " ZCORE_HSA,
},
{
.option = { "workdir", required_argument, NULL, 'W' },
.argument = "WORKDIR",
.desc = "Path to the work directory where temporary files can be "
"stored.\nDefault: " WORKDIR,
},
{
.option = { "bmvmcore", required_argument, NULL, 'B' },
.argument = "VMCOREFILE",
.desc = "Path to the target of the bind mount for the vmcore "
"replacement.\nDefault: " PROC_VMCORE,
},
{
.option = { "swap", required_argument, NULL, 'S' },
.argument = "PATH",
.desc = "Path to a swap device or file. The specified swap "
"device or file must exist and have the proper swap "
"format.\nDefault: no swap device or file is activated",
},
{
.option = { "hsasize", required_argument, NULL, 'T' },
.argument = "HSASIZE",
.desc = "HSA size in bytes.\n"
"Default: -1 (read from the zcore HSA file)",
},
{
.option = { "dbgfsmnt", no_argument, NULL, 'D' },
.desc = "Mount the debug file system.\n"
"Default: the debug file system is not mounted",
},
{
.option = { "hsamem", no_argument, NULL, 'F' },
.desc = "Cache the HSA memory in regular memory.\n"
"Default: the HSA memory is cached as a file within "
"WORKDIR",
},
{
.option = { "norelhsa", no_argument, NULL, 'R' },
.desc = "Do NOT release the HSA memory after caching.\n"
"Default: the HSA memory is released",
},
{
.option = { "nobindmnt", no_argument, NULL, 'N' },
.desc = "Do NOT replace the system's vmcore.\n"
"Default: the system's vmcore is replaced",
},
UTIL_OPT_SECTION("LOGGING"),
{
.option = { "verbose", no_argument, NULL, 'V' },
.desc = "Print verbose messages to stdout. Repeat this option "
"for increased verbosity from just error messages to "
"also include warning, information, debug, and trace "
"messages. This option is intended for debugging",
},
{
.option = { "fusedbg", no_argument, NULL, 'G' },
.desc = "Enable FUSE debugging.\n"
"Default: FUSE debugging is disabled",
},
UTIL_OPT_SECTION("GENERAL OPTIONS"),
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
};
void parse_cmdline_options(int argc, char *argv[], struct config *config)
{
int opt, ret;
util_prg_init(&prg);
util_opt_init(opt_vec, NULL);
/* Parse given command-line config */
while (1) {
opt = util_opt_getopt_long(argc, argv);
if (opt == -1)
break;
switch (opt) {
case 'h':
util_prg_print_help();
util_opt_print_help();
exit(EXIT_SUCCESS);
case 'v':
util_prg_print_version();
exit(EXIT_SUCCESS);
case 'V':
config->verbose++;
util_log_set_level(config->verbose);
break;
case 'c':
ret = update_config_from_file(optarg, config);
if (ret < 0)
exit(EXIT_FAILURE);
util_log_set_level(config->verbose);
break;
case 'C':
strncpy(config->vmcore_path, optarg,
sizeof(config->vmcore_path) - 1);
/* Ensure null termination */
config->vmcore_path[sizeof(config->vmcore_path) - 1] =
'\0';
break;
case 'H':
strncpy(config->zcore_hsa_path, optarg,
sizeof(config->zcore_hsa_path) - 1);
/* Ensure null termination */
config->zcore_hsa_path[sizeof(config->zcore_hsa_path) -
1] = '\0';
break;
case 'W':
strncpy(config->workdir_path, optarg,
sizeof(config->workdir_path) - 1);
/* Ensure null termination */
config->workdir_path[sizeof(config->workdir_path) - 1] =
'\0';
break;
case 'B':
strncpy(config->bind_mount_vmcore_path, optarg,
sizeof(config->bind_mount_vmcore_path) - 1);
/* Ensure null termination */
config->bind_mount_vmcore_path
[sizeof(config->bind_mount_vmcore_path) - 1] =
'\0';
break;
case 'S':
strncpy(config->swap, optarg, sizeof(config->swap) - 1);
/* Ensure null termination */
config->swap[sizeof(config->swap) - 1] = '\0';
break;
case 'T': {
char *endptr;
long hsa_size = strtol(optarg, &endptr, 0);
if (*endptr != '\0' || hsa_size < -1 ||
hsa_size > INT_MAX) {
fprintf(stderr,
"The given HSA size is invalid.\n");
exit(EXIT_FAILURE);
}
config->hsa_size = hsa_size;
break;
}
case 'D':
config->mount_debugfs = true;
break;
case 'F':
config->use_hsa_mem = true;
break;
case 'R':
config->release_hsa = false;
break;
case 'N':
config->bind_mount_vmcore = false;
break;
case 'G':
config->fuse_debug = true;
break;
case '?':
default:
util_opt_print_parse_error(opt, argv);
exit(EXIT_FAILURE);
}
}
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef _HSAVMCORE_CMDLINE_OPTIONS_H
#define _HSAVMCORE_CMDLINE_OPTIONS_H
#include "config.h"
/*
* Parses the given command-line options and adjusts the application's
* configuration accordingly.
*/
void parse_cmdline_options(int argc, char *argv[], struct config *config);
#endif

27
hsavmcore/common.h Normal file
View File

@@ -0,0 +1,27 @@
/*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef _HSAVMCORE_COMMON_H
#define _HSAVMCORE_COMMON_H
#define NAME "hsavmcore"
#define DEBUGFS_MOUNT_POINT "/sys/kernel/debug"
#define ZCORE_HSA DEBUGFS_MOUNT_POINT "/zcore/hsa"
#define VMCORE_FILE "vmcore"
#define PROC_VMCORE "/proc/" VMCORE_FILE
#define WORKDIR "/var/crash"
#define HSA_CACHE_FILE NAME "-hsa-cache.bin"
#define OVERLAY_MOUNT_POINT "/tmp/" NAME "-overlay/"
#endif

242
hsavmcore/config.c Normal file
View File

@@ -0,0 +1,242 @@
/*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "lib/util_libc.h"
#include "lib/util_log.h"
#include "config.h"
#define CONFIG_LINE_MAX_SIZE 1024
/*
* Supported configuration parameters
*/
#define CONFIG_VERBOSE "verbose"
#define CONFIG_WORKDIR "workdir"
#define CONFIG_HSA_SIZE "hsa_size"
#define CONFIG_MOUNT_DEBUGFS "mount_debugfs"
#define CONFIG_USE_HSA_MEM "use_hsa_mem"
#define CONFIG_RELEASE_HSA "release_hsa"
#define CONFIG_BIND_MOUNT_VMCORE "bind_mount_vmcore"
#define CONFIG_FUSE_DEBUG "fuse_debug"
#define CONFIG_SWAP "swap"
static char *get_value_str(char *line)
{
char *ptr = strchr(line, '=');
if (!ptr)
return NULL;
return util_strstrip(ptr + 1);
}
static int parse_bool(char *line, int linenum, const char *name, bool *value)
{
const char *value_str;
unsigned long value_num;
char *endptr;
value_str = get_value_str(line);
if (!value_str) {
util_log_print(UTIL_LOG_ERROR,
"config line %d: value expected for %s\n",
linenum, name);
return -1;
}
util_log_print(UTIL_LOG_DEBUG, "config parse bool: %s\n", value_str);
value_num = strtoul(value_str, &endptr, 0);
if (*endptr != '\0' || (value_num != 0 && value_num != 1)) {
util_log_print(UTIL_LOG_ERROR,
"config line %d: invalid value for %s\n",
linenum, name);
return -1;
}
*value = value_num;
return 0;
}
static int parse_int(char *line, int linenum, const char *name, int min_value,
int max_value, int *value)
{
const char *value_str;
long value_num;
char *endptr;
value_str = get_value_str(line);
if (!value_str) {
util_log_print(UTIL_LOG_ERROR,
"config line %d: value expected for %s\n",
linenum, name);
return -1;
}
util_log_print(UTIL_LOG_DEBUG, "config parse int: %s\n", value_str);
value_num = strtol(value_str, &endptr, 0);
if (*endptr != '\0' || value_num < min_value || value_num > max_value) {
util_log_print(UTIL_LOG_ERROR,
"config line %d: invalid value for %s\n",
linenum, name);
return -1;
}
*value = value_num;
return 0;
}
static int parse_str(char *line, int linenum, const char *name, int min_size,
int max_size, char *value)
{
const char *value_str;
int size;
value_str = get_value_str(line);
if (!value_str) {
util_log_print(UTIL_LOG_ERROR,
"config line %d: value expected for %s\n",
linenum, name);
return -1;
}
util_log_print(UTIL_LOG_DEBUG, "config parse string: %s\n", value_str);
size = strlen(value_str);
if ((min_size >= 0 && size < min_size) || size > max_size) {
util_log_print(UTIL_LOG_ERROR,
"config line %d: invalid value for %s\n",
linenum, name);
return -1;
}
strncpy(value, value_str, max_size);
/* Ensure null termination */
value[max_size] = '\0';
return 0;
}
static int parse_line(char *line, int linenum, struct config *config)
{
if (strncmp(line, CONFIG_VERBOSE, strlen(CONFIG_VERBOSE)) == 0) {
if (parse_int(line, linenum, CONFIG_VERBOSE, UTIL_LOG_ERROR,
UTIL_LOG_TRACE, &config->verbose))
return -1;
} else if (strncmp(line, CONFIG_WORKDIR, strlen(CONFIG_WORKDIR)) == 0) {
if (parse_str(line, linenum, CONFIG_WORKDIR, 0,
sizeof(config->workdir_path) - 1,
config->workdir_path))
return -1;
} else if (strncmp(line, CONFIG_HSA_SIZE, strlen(CONFIG_HSA_SIZE)) ==
0) {
if (parse_int(line, linenum, CONFIG_HSA_SIZE, -1, INT_MAX,
&config->hsa_size))
return -1;
} else if (strncmp(line, CONFIG_MOUNT_DEBUGFS,
strlen(CONFIG_MOUNT_DEBUGFS)) == 0) {
if (parse_bool(line, linenum, CONFIG_MOUNT_DEBUGFS,
&config->mount_debugfs))
return -1;
} else if (strncmp(line, CONFIG_USE_HSA_MEM,
strlen(CONFIG_USE_HSA_MEM)) == 0) {
if (parse_bool(line, linenum, CONFIG_USE_HSA_MEM,
&config->use_hsa_mem))
return -1;
} else if (strncmp(line, CONFIG_RELEASE_HSA,
strlen(CONFIG_RELEASE_HSA)) == 0) {
if (parse_bool(line, linenum, CONFIG_RELEASE_HSA,
&config->release_hsa))
return -1;
} else if (strncmp(line, CONFIG_BIND_MOUNT_VMCORE,
strlen(CONFIG_BIND_MOUNT_VMCORE)) == 0) {
if (parse_bool(line, linenum, CONFIG_BIND_MOUNT_VMCORE,
&config->bind_mount_vmcore))
return -1;
} else if (strncmp(line, CONFIG_FUSE_DEBUG,
strlen(CONFIG_FUSE_DEBUG)) == 0) {
if (parse_bool(line, linenum, CONFIG_FUSE_DEBUG,
&config->fuse_debug))
return -1;
} else if (strncmp(line, CONFIG_SWAP, strlen(CONFIG_SWAP)) == 0) {
if (parse_str(line, linenum, CONFIG_SWAP, 0,
sizeof(config->swap) - 1, config->swap))
return -1;
} else {
util_log_print(UTIL_LOG_ERROR,
"config line %d: unknown configuration '%s'\n",
linenum, line);
return -1;
}
return 0;
}
void init_config(struct config *config)
{
memset(config, 0, sizeof(struct config));
strncpy(config->vmcore_path, PROC_VMCORE,
sizeof(config->vmcore_path) - 1);
strncpy(config->zcore_hsa_path, ZCORE_HSA,
sizeof(config->zcore_hsa_path) - 1);
strncpy(config->workdir_path, WORKDIR,
sizeof(config->workdir_path) - 1);
strncpy(config->bind_mount_vmcore_path, PROC_VMCORE,
sizeof(config->bind_mount_vmcore_path) - 1);
config->hsa_size = -1;
config->mount_debugfs = false;
config->use_hsa_mem = false;
config->release_hsa = true;
config->bind_mount_vmcore = true;
config->fuse_debug = false;
}
int update_config_from_file(const char *config_path, struct config *config)
{
char line[CONFIG_LINE_MAX_SIZE], *ptr;
int ret = 0, linenum;
FILE *fp;
fp = fopen(config_path, "r");
if (!fp) {
util_log_print(UTIL_LOG_ERROR, "Couldn't open config file %s\n",
config_path);
return -1;
}
/* Read the given configuration file linewise and parse parameters */
linenum = 0;
while (fgets(line, sizeof(line), fp)) {
linenum++;
ptr = util_strstrip(line);
/* Skip empty or comment lines */
if (ptr[0] == '\0' || ptr[0] == '#')
continue;
util_log_print(UTIL_LOG_DEBUG, "config line %d: %s\n", linenum,
ptr);
ret = parse_line(ptr, linenum, config);
if (ret < 0)
break;
}
fclose(fp);
return ret;
}

59
hsavmcore/config.h Normal file
View File

@@ -0,0 +1,59 @@
/*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef _HSAVMCORE_CONFIG_H
#define _HSAVMCORE_CONFIG_H
#include <limits.h>
#include <stdbool.h>
#include "common.h"
/*
* This represents the application's configuration.
*/
struct config {
/* Log message level */
int verbose;
/* Path to the system's vmcore file */
char vmcore_path[PATH_MAX];
/* Path to the system's zcore hsa file */
char zcore_hsa_path[PATH_MAX];
/*
* Path to a directory where the application could create temporary
* files.
*/
char workdir_path[PATH_MAX];
/* Path to a bind-mount target for vmcore Overlay */
char bind_mount_vmcore_path[PATH_MAX];
/* Path to a swap device/file */
char swap[PATH_MAX];
/* HSA memory size */
int hsa_size;
/* Indicates whether the debugfs shall be mounted */
bool mount_debugfs;
/* Indicates whether the HSA memory file reader shall be used */
bool use_hsa_mem;
/* Indicates whether the HSA memory shall be released after caching */
bool release_hsa;
/* Indicates whether a bind-mount of vmcore Proxy shall be enabled */
bool bind_mount_vmcore;
/* Indicates whether the FUSE debug messages shall be enabled */
bool fuse_debug;
};
/*
* Initializes the application's configuration to its default values.
*/
void init_config(struct config *config);
/*
* Updates the application's configuration from the given configuration file.
*/
int update_config_from_file(const char *config_path, struct config *config);
#endif

172
hsavmcore/hsa.c Normal file
View File

@@ -0,0 +1,172 @@
/*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <elf.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "lib/util_file.h"
#include "lib/util_log.h"
#include "hsa.h"
long get_hsa_size(const char *zcore_hsa_path)
{
long size;
int ret;
util_log_print(UTIL_LOG_DEBUG, "Reading HSA memory size from %s\n",
zcore_hsa_path);
/* Read HSA size */
ret = util_file_read_l(&size, 16, zcore_hsa_path);
if (ret < 0) {
util_log_print(UTIL_LOG_ERROR, "File read failed (%s)\n",
strerror(errno));
return -1;
}
return size;
}
long get_hsa_vmcore_offset(const char *vmcore_path)
{
Elf64_Ehdr elf_hdr;
int fd = -1, n, i;
long offset = -1;
util_log_print(UTIL_LOG_DEBUG,
"Reading HSA memory offset from vmcore %s\n",
vmcore_path);
/* Open vmcore file */
fd = open(vmcore_path, O_RDONLY);
if (fd < 0) {
util_log_print(UTIL_LOG_ERROR, "open syscall failed (%s)\n",
strerror(errno));
goto fail;
}
util_log_print(UTIL_LOG_DEBUG, "Reading vmcore ELF header\n");
/* Read ELF header */
n = read(fd, &elf_hdr, sizeof(Elf64_Ehdr));
if (n < 0) {
util_log_print(UTIL_LOG_ERROR, "read syscall failed (%s)\n",
strerror(errno));
goto fail;
} else if (n != sizeof(Elf64_Ehdr)) {
util_log_print(UTIL_LOG_ERROR,
"read syscall read less data than expected (%s)\n",
strerror(errno));
goto fail;
}
/* Verify ELF header */
if ((memcmp(elf_hdr.e_ident, ELFMAG, SELFMAG) != 0) ||
elf_hdr.e_type != ET_CORE || elf_hdr.e_machine != EM_S390 ||
elf_hdr.e_ident[EI_CLASS] != ELFCLASS64) {
util_log_print(UTIL_LOG_ERROR, "Invalid vmcore ELF header\n");
goto fail;
}
util_log_print(UTIL_LOG_DEBUG,
"Reading vmcore ELF program header(s)\n");
/* Read ELF program header(s) */
n = lseek(fd, elf_hdr.e_phoff, SEEK_SET);
if (n < 0) {
util_log_print(UTIL_LOG_ERROR, "lseek syscall failed (%s)\n",
strerror(errno));
goto fail;
}
/*
* Go through all ELF program headers and find one
* that starts at physical/virtual address 0x0.
*/
for (i = 0; i < elf_hdr.e_phnum; i++) {
Elf64_Phdr elf_phdr;
util_log_print(UTIL_LOG_DEBUG,
"Reading vmcore ELF program header #%d\n", i);
n = read(fd, &elf_phdr, sizeof(Elf64_Phdr));
if (n < 0) {
util_log_print(UTIL_LOG_ERROR,
"read syscall failed (%s)\n",
strerror(errno));
goto fail;
} else if (n != sizeof(Elf64_Phdr)) {
util_log_print(UTIL_LOG_ERROR,
"read syscall read less data than expected (%s)\n",
strerror(errno));
goto fail;
}
util_log_print(UTIL_LOG_DEBUG,
"vmcore ELF program segment #%d: type=%lx vaddr=%lx paddr=%lx offset=%lx\n",
i, elf_phdr.p_type, elf_phdr.p_vaddr,
elf_phdr.p_paddr, elf_phdr.p_offset);
/* HSA memory starts at physical/virtual address 0x0 */
if (elf_phdr.p_type == PT_LOAD && elf_phdr.p_vaddr == 0 &&
elf_phdr.p_paddr == 0) {
offset = elf_phdr.p_offset;
break;
}
}
if (offset < 0) {
util_log_print(UTIL_LOG_ERROR,
"Couldn't find HSA memory offset in vmcore\n");
goto fail;
}
util_log_print(UTIL_LOG_DEBUG, "HSA memory vmcore offset %lx\n",
offset);
close(fd);
return offset;
fail:
if (fd >= 0)
close(fd);
return -1;
}
int release_hsa(const char *zcore_hsa_path)
{
int ret;
util_log_print(UTIL_LOG_INFO, "Release HSA memory via %s\n",
zcore_hsa_path);
/* Release HSA memory */
ret = util_file_write_s("0", zcore_hsa_path);
if (ret < 0) {
util_log_print(UTIL_LOG_ERROR, "File write failed (%s)\n",
strerror(errno));
return -1;
}
/* Verify that HSA memory has been released */
if (get_hsa_size(zcore_hsa_path) > 0) {
util_log_print(UTIL_LOG_ERROR, "HSA memory release failed\n");
return -1;
}
util_log_print(UTIL_LOG_INFO, "HSA memory successfully released\n");
return 0;
}

75
hsavmcore/hsa.h Normal file
View File

@@ -0,0 +1,75 @@
/*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef _HSAVMCORE_HSA_H
#define _HSAVMCORE_HSA_H
#include <stddef.h>
/*
* The interface to a HSA memory reader.
* This interface must be implemented by a concrete HSA memory reader.
*/
struct hsa_reader {
/* Total HSA memory size */
long hsa_size;
/* Offset of HSA memory in /proc/vmcore */
long hsa_vmcore_offset;
/* Destroys a concrete HSA memory reader */
void (*destroy)(struct hsa_reader *self);
/* Reads a HSA memory block given by offset and size */
int (*read_at)(struct hsa_reader *self, long offset, void *buf,
int size);
};
static inline long hsa_get_size(struct hsa_reader *self)
{
return self->hsa_size;
}
static inline long hsa_get_vmcore_offset(struct hsa_reader *self)
{
return self->hsa_vmcore_offset;
}
static inline void destroy_hsa_reader(struct hsa_reader *self)
{
self->destroy(self);
}
static inline int read_hsa_at(struct hsa_reader *self, long offset, void *buf,
int size)
{
return self->read_at(self, offset, buf, size);
}
/*
* Reads total HSA memory size from /sys/kernel/debug/zcore/hsa.
*/
long get_hsa_size(const char *zcore_hsa_path);
/*
* Returns the offset of HSA memory in /proc/vmcore.
*/
long get_hsa_vmcore_offset(const char *vmcore_path);
/*
* Releases HSA memory.
*/
int release_hsa(const char *zcore_hsa_path);
/*
* Returns a pointer to the enclosing struct which contains
* the variable pointed to by the given pointer as a member.
*/
#define container_of(ptr, type, member) \
({ \
const typeof(((type *)NULL)->member) *mptr = (ptr); \
(type *)((char *)mptr - offsetof(type, member)); \
})
#endif

236
hsavmcore/hsa_file.c Normal file
View File

@@ -0,0 +1,236 @@
/*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "lib/zt_common.h"
#include "lib/util_log.h"
#include "common.h"
#include "hsa.h"
#include "hsa_file.h"
struct hsa_file_reader {
struct hsa_reader super;
/* Temporary file containing a copy of the HSA memory */
int fd;
};
static void destroy(struct hsa_reader *super)
{
struct hsa_file_reader *self =
container_of(super, struct hsa_file_reader, super);
close(self->fd);
free(self);
}
static int read_at(struct hsa_reader *super, long offset, void *buf, int size)
{
struct hsa_file_reader *self =
container_of(super, struct hsa_file_reader, super);
long n, nread = 0;
util_log_print(UTIL_LOG_DEBUG, "HSA file read: offset=%lx size=%x\n",
offset, size);
/* Validate given offset */
if (offset >= super->hsa_size)
return 0;
/* Validate given size */
size = MIN(super->hsa_size - offset, size);
n = lseek(self->fd, offset, SEEK_SET);
if (n < 0) {
util_log_print(UTIL_LOG_ERROR, "lseek syscall failed (%s)\n",
strerror(errno));
return -1;
}
while (size) {
n = read(self->fd, buf + nread, size);
if (n < 0) {
util_log_print(UTIL_LOG_ERROR,
"read syscall failed (%s)\n",
strerror(errno));
return -1;
} else if (n == 0) {
break;
}
nread += n;
size -= n;
}
return nread;
}
static int copy_hsa_to_file(const char *vmcore_path, const char *workdir_path,
long size, long offset)
{
int fd_in = -1, fd_out = -1;
char cache_file_path[PATH_MAX];
long n;
snprintf(cache_file_path, sizeof(cache_file_path), "%s/%s",
workdir_path, HSA_CACHE_FILE);
util_log_print(UTIL_LOG_DEBUG,
"Copy HSA memory from vmcore %s to cache file %s\n",
vmcore_path, cache_file_path);
/* Open vmcore file */
fd_in = open(vmcore_path, O_RDONLY);
if (fd_in < 0) {
util_log_print(UTIL_LOG_ERROR, "open syscall failed (%s)\n",
strerror(errno));
goto fail;
}
/* Open cache file */
fd_out = open(cache_file_path, O_RDWR | O_CREAT | O_TRUNC, 0644);
if (fd_out < 0) {
util_log_print(UTIL_LOG_ERROR, "open syscall failed (%s)\n",
strerror(errno));
goto fail;
}
/* Unlink cache file to auto-delete it on close */
n = unlink(cache_file_path);
if (n < 0) {
util_log_print(UTIL_LOG_ERROR, "unlink syscall failed (%s)\n",
strerror(errno));
goto fail;
}
/* Copy HSA memory to cache file */
n = lseek(fd_in, offset, SEEK_SET);
if (n < 0) {
util_log_print(UTIL_LOG_ERROR, "lseek syscall failed (%s)\n",
strerror(errno));
goto fail;
}
/* Copy HSA memory chunkwise to the temporary file */
while (size) {
char buf[1024];
long nread, nwrite;
/* Read a chunk from vmcore */
nread = MIN((long)sizeof(buf), size);
n = read(fd_in, buf, nread);
if (n < 0) {
util_log_print(UTIL_LOG_ERROR,
"read syscall failed (%s)\n",
strerror(errno));
goto fail;
} else if (n == 0) {
util_log_print(UTIL_LOG_ERROR,
"read syscall read less data than expected\n");
goto fail;
}
/* Write a chunk to cache file */
nwrite = n;
n = write(fd_out, buf, nwrite);
if (n < 0) {
util_log_print(UTIL_LOG_ERROR,
"write syscall failed (%s)\n",
strerror(errno));
goto fail;
} else if (n != nwrite) {
util_log_print(UTIL_LOG_ERROR,
"write syscall wrote less data than expected\n");
goto fail;
}
size -= n;
}
/* Reset cache file position */
n = lseek(fd_out, 0, SEEK_SET);
if (n < 0) {
util_log_print(UTIL_LOG_ERROR, "lseek syscall failed (%s)\n",
strerror(errno));
goto fail;
}
close(fd_in);
return fd_out;
fail:
if (fd_in >= 0)
close(fd_in);
if (fd_out >= 0)
close(fd_out);
return -1;
}
struct hsa_reader *make_hsa_file_reader(const char *zcore_hsa_path,
const char *vmcore_path,
const char *workdir_path, long hsa_size,
bool release_hsa_flag)
{
struct hsa_file_reader *self;
long hsa_vmcore_offset;
int fd;
/* Calculate HSA size if not given by user */
if (hsa_size < 0) {
hsa_size = get_hsa_size(zcore_hsa_path);
if (hsa_size <= 0)
return NULL;
}
hsa_vmcore_offset = get_hsa_vmcore_offset(vmcore_path);
if (hsa_vmcore_offset < 0)
return NULL;
util_log_print(UTIL_LOG_INFO, "HSA: size=%lx vmcore offset=%lx\n",
hsa_size, hsa_vmcore_offset);
/*
* Store the whole HSA memory from /proc/vmcore to a temporary file
* before releasing HSA.
*/
fd = copy_hsa_to_file(vmcore_path, workdir_path, hsa_size,
hsa_vmcore_offset);
if (fd < 0)
return NULL;
if (release_hsa_flag) {
if (release_hsa(zcore_hsa_path)) {
close(fd);
return NULL;
}
}
self = malloc(sizeof(struct hsa_file_reader));
if (!self) {
util_log_print(UTIL_LOG_ERROR, "malloc failed\n");
close(fd);
return NULL;
}
self->super.hsa_size = hsa_size;
self->super.hsa_vmcore_offset = hsa_vmcore_offset;
self->super.destroy = destroy;
self->super.read_at = read_at;
self->fd = fd;
return &self->super;
}

27
hsavmcore/hsa_file.h Normal file
View File

@@ -0,0 +1,27 @@
/*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef _HSAVMCORE_HSA_FILE_H
#define _HSAVMCORE_HSA_FILE_H
#include <stdbool.h>
#include "hsa.h"
/*
* This concrete HSA memory reader copies the whole HSA memory from /proc/vmcore
* to a temporary file.
* In order for it to work, the system must provide enough file storage.
* The advantage of this reader is that it doesn't require extra memory for
* caching.
*/
struct hsa_reader *make_hsa_file_reader(const char *zcore_hsa_path,
const char *vmcore_path,
const char *workdir_path, long hsa_size,
bool release_hsa_flag);
#endif

151
hsavmcore/hsa_mem.c Normal file
View File

@@ -0,0 +1,151 @@
/*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "lib/zt_common.h"
#include "lib/util_log.h"
#include "hsa.h"
#include "hsa_mem.h"
struct hsa_mem_reader {
struct hsa_reader super;
unsigned char cache[];
};
static void destroy(struct hsa_reader *super)
{
struct hsa_mem_reader *self =
container_of(super, struct hsa_mem_reader, super);
free(self);
}
static int read_at(struct hsa_reader *super, long offset, void *buf, int size)
{
struct hsa_mem_reader *self =
container_of(super, struct hsa_mem_reader, super);
util_log_print(UTIL_LOG_DEBUG, "HSA file read: offset=%lx size=%x\n",
offset, size);
/* Validate given offset */
if (offset >= super->hsa_size)
return 0;
/* Validate given size */
size = MIN(super->hsa_size - offset, size);
memcpy(buf, self->cache + offset, size);
return size;
}
static int read_hsa(const char *vmcore_path, long offset, void *buf, int size)
{
long n, nread = 0;
int fd = -1;
util_log_print(UTIL_LOG_DEBUG, "Read HSA memory from vmcore %s\n",
vmcore_path);
/* Open vmcore file */
fd = open(vmcore_path, O_RDONLY);
if (fd < 0) {
util_log_print(UTIL_LOG_ERROR, "open syscall failed (%s)\n",
strerror(errno));
goto fail;
}
n = lseek(fd, offset, SEEK_SET);
if (n < 0) {
util_log_print(UTIL_LOG_ERROR, "lseek syscall failed (%s)\n",
strerror(errno));
goto fail;
}
/* Read HSA memory */
while (size) {
n = read(fd, buf + nread, size);
if (n < 0) {
util_log_print(UTIL_LOG_ERROR,
"read syscall failed (%s)\n",
strerror(errno));
goto fail;
} else if (n == 0) {
util_log_print(UTIL_LOG_ERROR,
"read syscall read less data than expected\n");
goto fail;
}
nread += n;
size -= n;
}
close(fd);
return 0;
fail:
if (fd >= 0)
close(fd);
return -1;
}
struct hsa_reader *make_hsa_mem_reader(const char *zcore_hsa_path,
const char *vmcore_path, long hsa_size,
bool release_hsa_flag)
{
struct hsa_mem_reader *self;
long hsa_vmcore_offset;
/* Calculate HSA size if not given by user */
if (hsa_size < 0) {
hsa_size = get_hsa_size(zcore_hsa_path);
if (hsa_size <= 0)
return NULL;
}
hsa_vmcore_offset = get_hsa_vmcore_offset(vmcore_path);
if (hsa_vmcore_offset < 0)
return NULL;
util_log_print(UTIL_LOG_INFO, "HSA: size=%lx vmcore offset=%lx\n",
hsa_size, hsa_vmcore_offset);
self = malloc(sizeof(struct hsa_mem_reader) + hsa_size);
if (!self) {
util_log_print(UTIL_LOG_ERROR, "malloc failed\n");
return NULL;
}
/* Cache the whole HSA memory from /proc/vmcore before releasing HSA */
if (read_hsa(vmcore_path, hsa_vmcore_offset, self->cache, hsa_size)) {
free(self);
return NULL;
}
if (release_hsa_flag) {
if (release_hsa(zcore_hsa_path)) {
free(self);
return NULL;
}
}
self->super.hsa_size = hsa_size;
self->super.hsa_vmcore_offset = hsa_vmcore_offset;
self->super.destroy = destroy;
self->super.read_at = read_at;
return &self->super;
}

24
hsavmcore/hsa_mem.h Normal file
View File

@@ -0,0 +1,24 @@
/*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef _HSAVMCORE_HSA_MEM_H
#define _HSAVMCORE_HSA_MEM_H
#include <stdbool.h>
#include "hsa.h"
/*
* This concrete HSA memory reader reads the whole HSA memory from /proc/vmcore
* and caches it all in an internal memory buffer.
* In order for it to work, the system must provide enough memory or swap space.
*/
struct hsa_reader *make_hsa_mem_reader(const char *zcore_hsa_path,
const char *vmcore_path, long hsa_size,
bool release_hsa_flag);
#endif

View File

@@ -0,0 +1,147 @@
# Setup
## Configure crashkernel
```shell
sudo grubby --args "crashkernel=512M" --update-kernel=ALL
sudo reboot
```
## Production kernel's root file system
- kdump mounts the production kernel's root file system under **/sysroot**.
## Dependencies
```shell
sudo dnf install -y fuse fuse-devel systemd-devel
```
## Build hsavmcore
```shell
make -C s390-tools/hsavmcore
```
## Install hsavmcore
```shell
sudo cp s390-tools/hsavmcore/hsavmcore /usr/sbin/
```
## Create swap file
```shell
sudo dd if=/dev/zero of=/var/crash/swap.img bs=1M count=1024
sudo mkswap /var/crash/swap.img
```
## Install hsavmcore.conf
### Test configuration
- Doesn't require HSA support
#### HSA cache in file
```shell
cat <<EOF | sudo tee /etc/hsavmcore.conf
verbose = 2
workdir = /sysroot/var/crash
use_hsa_mem = 0
mount_debugfs = 1
hsa_size = 0x1ffff000
release_hsa = 0
bind_mount_vmcore = 1
EOF
```
#### HSA cache in memory
```shell
cat <<EOF | sudo tee /etc/hsavmcore.conf
verbose = 2
workdir = /sysroot/var/crash
use_hsa_mem = 1
mount_debugfs = 1
hsa_size = 0x1ffff000
release_hsa = 0
bind_mount_vmcore = 1
swap = /sysroot/var/crash/swap.img
EOF
```
### Production configuration
- Works only on s390x
#### HSA cache in file
```shell
cat <<EOF | sudo tee /etc/hsavmcore.conf
verbose = 2
workdir = /sysroot/var/crash
use_hsa_mem = 0
mount_debugfs = 1
hsa_size = -1
release_hsa = 1
bind_mount_vmcore = 1
EOF
```
#### HSA cache in memory
```shell
cat <<EOF | sudo tee /etc/hsavmcore.conf
verbose = 2
workdir = /sysroot/var/crash
use_hsa_mem = 1
mount_debugfs = 1
hsa_size = -1
release_hsa = 1
bind_mount_vmcore = 1
swap = /sysroot/var/crash/swap.img
EOF
```
## Install new dracut module
```shell
sudo cp -r s390-tools/hsavmcore/initramfs/fedora-rhel/dracut/modules.d/99hsavmcore /lib/dracut/modules.d/
```
## Add the new dracut module as a dependency to the dracut module *kdumpbase*
```shell
sudo sed -e 's#local _dep="base shutdown"#local _dep="base shutdown hsavmcore"#' \
-i /lib/dracut/modules.d/99kdumpbase/module-setup.sh
```
## Rebuild kdump initramfs
```shell
sudo kdumpctl rebuild
```
## Enable swap LVM in kdump
- Required if you want to use a swap device in kdump
```shell
sudo sed -e 's#^KDUMP_COMMANDLINE_APPEND="\(.*\)"$#KDUMP_COMMANDLINE_APPEND="\1 rd.lvm.lv=rhel/swap"#' \
-i /etc/sysconfig/kdump
```
## Reload kdump
```shell
sudo kdumpctl reload
```
# Test
```shell
echo N | sudo tee /sys/module/kernel/parameters/crash_kexec_post_notifiers
echo c | sudo tee /proc/sysrq-trigger
```

View File

@@ -0,0 +1,20 @@
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=hsavmcore Service
After=initrd.target initrd-parse-etc.service sysroot.mount
After=dracut-initqueue.service dracut-pre-mount.service dracut-mount.service dracut-pre-pivot.service
Before=kdump-capture.service
Before=initrd-cleanup.service
[Service]
Type=notify
ExecStart=/usr/sbin/hsavmcore -c /etc/hsavmcore.conf
StandardInput=null
StandardOutput=syslog
StandardError=syslog+console

View File

@@ -0,0 +1,37 @@
#!/usr/bin/bash
. $dracutfunctions
if ! [[ -d "${initdir}/tmp" ]]; then
mkdir -p "${initdir}/tmp"
fi
check() {
[[ $debug ]] && set -x
#kdumpctl sets this explicitly
if [ -z "$IN_KDUMP" ]
then
return 1
fi
return 0
}
depends() {
local _dep="base shutdown"
echo $_dep
return 0
}
installkernel() {
hostonly='' instmods fuse
}
install() {
inst "/usr/sbin/hsavmcore" "/usr/sbin/hsavmcore"
inst "/etc/hsavmcore.conf" "/etc/hsavmcore.conf"
inst "$moddir/hsavmcore.service" "$systemdsystemunitdir/hsavmcore.service"
mkdir -p "$initdir/$systemdsystemunitdir/initrd.target.wants"
ln_r "$systemdsystemunitdir/hsavmcore.service" "$systemdsystemunitdir/initrd.target.wants/hsavmcore.service"
inst_hook pre-mount 30 "$moddir/setup-fuse.sh"
}

View File

@@ -0,0 +1,3 @@
#!/bin/sh
modprobe fuse

View File

@@ -0,0 +1,141 @@
# Setup
## Configure crashkernel
```shell
sudo vim /etc/default/grub
sudo sed -e 's/GRUB_CMDLINE_LINUX_DEFAULT="\(.*\)"/GRUB_CMDLINE_LINUX_DEFAULT="\1 crashkernel=512M"/' \
-i /etc/default/grub
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
sudo reboot
```
## Production kernel's root file system
- kdump mounts the production kernel's root file system under **/kdump/mnt1**.
## Dependencies
```shell
sudo zypper install -y fuse fuse-devel systemd-devel
```
## Build hsavmcore
```shell
make -C s390-tools/hsavmcore
```
## Install hsavmcore
```shell
sudo cp s390-tools/hsavmcore/hsavmcore /usr/sbin/
```
## Create swap file
```shell
sudo dd if=/dev/zero of=/var/crash/swap.img bs=1M count=1024
sudo mkswap /var/crash/swap.img
```
## Install hsavmcore.conf
### Test configuration
- Doesn't require HSA support
#### HSA cache in file
```shell
cat <<EOF | sudo tee /etc/hsavmcore.conf
verbose = 2
workdir = /kdump/mnt1/var/crash
use_hsa_mem = 0
mount_debugfs = 1
hsa_size = 0x1ffff000
release_hsa = 0
bind_mount_vmcore = 1
EOF
```
#### HSA cache in memory
```shell
cat <<EOF | sudo tee /etc/hsavmcore.conf
verbose = 2
workdir = /kdump/mnt1/var/crash
use_hsa_mem = 1
mount_debugfs = 1
hsa_size = 0x1ffff000
release_hsa = 0
bind_mount_vmcore = 1
swap = /kdump/mnt1/var/crash/swap.img
EOF
```
### Production configuration
- Works only on s390x
#### HSA cache in file
```shell
cat <<EOF | sudo tee /etc/hsavmcore.conf
verbose = 2
workdir = /kdump/mnt1/var/crash
use_hsa_mem = 0
mount_debugfs = 1
hsa_size = -1
release_hsa = 1
bind_mount_vmcore = 1
EOF
```
#### HSA cache in memory
```shell
cat <<EOF | sudo tee /etc/hsavmcore.conf
verbose = 2
workdir = /kdump/mnt1/var/crash
use_hsa_mem = 1
mount_debugfs = 1
hsa_size = -1
release_hsa = 1
bind_mount_vmcore = 1
swap = /kdump/mnt1/var/crash/swap.img
EOF
```
## Install new dracut module
```shell
sudo cp -r s390-tools/hsavmcore/initramfs/sles/dracut/modules.d/99hsavmcore /usr/lib/dracut/modules.d/
```
## Add the new dracut module as a dependency to the dracut module *kdump*
```shell
sudo sed -e 's/_modules\[drm\]=/_modules[drm]=\n _modules[hsavmcore]=/' \
-i /usr/lib/dracut/modules.d/99kdump/module-setup.sh
```
## Rebuild kdump initramfs
```shell
sudo mkdumprd -f
```
## Reload kdump
```shell
systemctl enable kdump
systemctl restart kdump
```
# Test
```shell
echo c | sudo tee /proc/sysrq-trigger
```

View File

@@ -0,0 +1,21 @@
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
# See systemd.special(7) for details
[Unit]
Description=hsavmcore Service
Before=kdump-save.service
ConditionPathExists=/etc/initrd-release
ConditionPathExists=/proc/vmcore
[Service]
Type=notify
ExecStart=/usr/sbin/hsavmcore -c /etc/hsavmcore.conf
StandardInput=null
StandardOutput=syslog
StandardError=syslog+console

View File

@@ -0,0 +1,47 @@
#!/bin/bash
. /lib/kdump/setup-kdump.functions
kdump_needed() {
# Building a kdump initrd?
if [[ " $dracutmodules $add_dracutmodules $force_add_dracutmodules" == *\ $_mod\ * ]]; then
return 0
fi
# Is FADUMP active?
if [ "$KDUMP_FADUMP" = "yes" ]; then
return 0
fi
# Do not include kdump by default
return 1
}
check() {
# Get configuration
kdump_get_config || return 1
kdump_needed || return 1
return 0
}
depends() {
echo "systemd"
return 0
}
installkernel() {
hostonly='' instmods fuse
}
install() {
inst_simple /usr/sbin/hsavmcore
inst_simple /etc/hsavmcore.conf
inst "$moddir/hsavmcore.service" "$systemdsystemunitdir/hsavmcore.service"
mkdir -p "$initdir/$systemdsystemunitdir/initrd.target.wants"
ln_r "$systemdsystemunitdir/hsavmcore.service" "$systemdsystemunitdir/initrd.target.wants/hsavmcore.service"
inst_hook pre-mount 30 "$moddir/setup-fuse.sh"
}

View File

@@ -0,0 +1,3 @@
#!/bin/sh
modprobe fuse

View File

@@ -0,0 +1,142 @@
# Setup
## Production kernel's root file system
- kdump mounts the production kernel's root file system under **/**.
## debugfs
- kdump mounts debugfs automatically.
## Dependencies
```shell
sudo apt-get install -y make gcc kdump-tools fuse libfuse-dev libsystemd-dev
```
## Build hsavmcore
```shell
make -C s390-tools/hsavmcore
```
## Install hsavmcore
```shell
sudo cp s390-tools/hsavmcore/hsavmcore /usr/sbin/
```
## Create swap file
```shell
sudo dd if=/dev/zero of=/var/crash/swap.img bs=1M count=1024
sudo mkswap /var/crash/swap.img
```
## Install hsavmcore.conf
### Test configuration
- Doesn't require HSA support
#### HSA cache in file
```shell
cat <<EOF | sudo tee /etc/hsavmcore.conf
verbose = 2
workdir = /sysroot/var/crash
use_hsa_mem = 0
mount_debugfs = 0
hsa_size = 0x1ffff000
release_hsa = 0
bind_mount_vmcore = 1
EOF
```
#### HSA cache in memory
```shell
cat <<EOF | sudo tee /etc/hsavmcore.conf
verbose = 2
workdir = /var/crash
use_hsa_mem = 1
mount_debugfs = 0
hsa_size = 0x1ffff000
release_hsa = 0
bind_mount_vmcore = 1
swap = /var/crash/swap.img
EOF
```
### Production configuration
- Works only on s390x
#### HSA cache in file
```shell
cat <<EOF | sudo tee /etc/hsavmcore.conf
verbose = 2
workdir = /var/crash
use_hsa_mem = 0
mount_debugfs = 0
hsa_size = -1
release_hsa = 1
bind_mount_vmcore = 1
EOF
```
#### HSA cache in memory
```shell
cat <<EOF | sudo tee /etc/hsavmcore.conf
verbose = 2
workdir = /sysroot/var/crash
use_hsa_mem = 1
mount_debugfs = 0
hsa_size = -1
release_hsa = 1
bind_mount_vmcore = 1
swap = /var/crash/swap.img
EOF
```
## Install new dracut module
```shell
sudo cp s390-tools/hsavmcore/initramfs/ubuntu/hsavmcore.service /usr/lib/systemd/system/
```
## Add the new systemd service as a dependency to the service *kdump-tools-dump*
```shell
Wants=network-online.target dbus.socket systemd-resolved.service hsavmcore.service
After=network-online.target dbus.socket systemd-resolved.service hsavmcore.service
sudo sed -e 's/Wants=\(.*\)$/Wants=\1 hsavmcore.service/' \
-e 's/After=\(.*\)$/After=\1 hsavmcore.service/' \
-i /usr/lib/systemd/system/kdump-tools-dump.service
```
## Rebuild kdump initramfs
```shell
sudo rm -rf /var/lib/kdump/initrd*
sudo kdump-config unload
sudo kdump-config load
sudo systemctl restart kdump-tools
```
## Reload kdump
```shell
sudo kdump-config unload
sudo kdump-config load
```
# Test
```shell
echo N | sudo tee /sys/module/kernel/parameters/crash_kexec_post_notifiers
echo c | sudo tee /proc/sysrq-trigger
```

View File

@@ -0,0 +1,22 @@
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=hsavmcore Service
Wants=network-online.target dbus.socket systemd-resolved.service
After=network-online.target dbus.socket systemd-resolved.service
Before=kdump-tools-dump.service
[Install]
WantedBy=kdump-tools-dump.service
[Service]
Type=notify
ExecStart=/usr/sbin/hsavmcore -c /etc/hsavmcore.conf
StandardInput=null
StandardOutput=syslog+console
StandardError=syslog+console

238
hsavmcore/main.c Normal file
View File

@@ -0,0 +1,238 @@
/*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#ifdef HAVE_SYSTEMD
#include <systemd/sd-daemon.h>
#endif
#include "lib/util_log.h"
#include "common.h"
#include "config.h"
#include "cmdline_options.h"
#include "mount.h"
#include "swap.h"
#include "hsa.h"
#include "hsa_mem.h"
#include "hsa_file.h"
#include "proxy.h"
#include "overlay.h"
#define MAX_WAIT_VMCORE_OVERLAY_SECS 5
static int bind_mount_vmcore(const char *src, const char *target,
int max_wait_secs)
{
struct stat st;
int ret;
util_log_print(UTIL_LOG_INFO, "Wait %d secs for %s to appear\n",
max_wait_secs, src);
while (max_wait_secs--) {
if (!stat(src, &st))
break;
sleep(1);
}
if (stat(src, &st)) {
util_log_print(UTIL_LOG_ERROR, "Timeout for appearance of %s\n",
src);
return -1;
}
ret = bind_mount(src, target);
if (ret < 0)
return -1;
return 0;
}
static void block_all_signals(void)
{
sigset_t signal_set;
sigfillset(&signal_set);
pthread_sigmask(SIG_BLOCK, &signal_set, NULL);
}
static void unblock_all_signals(void)
{
sigset_t signal_set;
sigfillset(&signal_set);
pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
}
static void *vmcore_overlay_server(void *arg)
{
struct vmcore_overlay *vmcore_overlay = (struct vmcore_overlay *)arg;
int ret;
util_log_print(UTIL_LOG_DEBUG, "vmcore overlay thread: start\n");
/* Unblock all signals because vmcore overlay handles them */
unblock_all_signals();
/* Blocks until a signal has been received or an error occurred */
ret = serve_vmcore_overlay(vmcore_overlay);
util_log_print(UTIL_LOG_DEBUG, "vmcore overlay thread: end (%d)\n",
ret);
return (void *)(long)ret;
}
static void terminate_vmcore_overlay(pthread_t tid)
{
pthread_kill(tid, SIGINT);
pthread_join(tid, NULL);
}
static int wait_for_vmcore_overlay(pthread_t tid)
{
int ret;
pthread_join(tid, (void **)&ret);
return ret;
}
int main(int argc, char *argv[])
{
struct vmcore_overlay *vmcore_overlay;
struct vmcore_proxy *vmcore_proxy;
int exit_code = EXIT_SUCCESS, ret;
struct hsa_reader *hsa_reader;
pthread_t vmcore_overlay_tid;
struct config config;
init_config(&config);
parse_cmdline_options(argc, argv, &config);
if (strlen(config.swap)) {
ret = swap_on(config.swap);
if (ret < 0) {
exit_code = EXIT_FAILURE;
goto done;
}
}
if (config.mount_debugfs) {
ret = mount_debugfs(DEBUGFS_MOUNT_POINT);
if (ret < 0) {
exit_code = EXIT_FAILURE;
goto swap_off;
}
}
if (config.use_hsa_mem)
hsa_reader =
make_hsa_mem_reader(config.zcore_hsa_path,
config.vmcore_path, config.hsa_size,
config.release_hsa);
else
hsa_reader = make_hsa_file_reader(config.zcore_hsa_path,
config.vmcore_path,
config.workdir_path,
config.hsa_size,
config.release_hsa);
if (!hsa_reader) {
exit_code = EXIT_FAILURE;
goto unmount_debugfs;
}
vmcore_proxy = make_vmcore_proxy(config.vmcore_path, hsa_reader);
if (!vmcore_proxy) {
exit_code = EXIT_FAILURE;
goto destroy_hsa_reader;
}
vmcore_overlay = make_vmcore_overlay(vmcore_proxy, OVERLAY_MOUNT_POINT,
config.fuse_debug);
if (!vmcore_overlay) {
exit_code = EXIT_FAILURE;
goto destroy_vmcore_proxy;
}
/* vmcore overlay thread handles all signals */
block_all_signals();
/* Start vmcore overlay thread which handles file system calls */
ret = pthread_create(&vmcore_overlay_tid, NULL, vmcore_overlay_server,
vmcore_overlay);
if (ret < 0) {
exit_code = EXIT_FAILURE;
goto destroy_vmcore_overlay;
}
/* Bind mount /proc/vmcore */
if (config.bind_mount_vmcore) {
ret = bind_mount_vmcore(OVERLAY_MOUNT_POINT "/" VMCORE_FILE,
config.bind_mount_vmcore_path,
MAX_WAIT_VMCORE_OVERLAY_SECS);
if (ret < 0) {
terminate_vmcore_overlay(vmcore_overlay_tid);
exit_code = EXIT_FAILURE;
goto destroy_vmcore_overlay;
}
}
#ifdef HAVE_SYSTEMD
/* Tell systemd that service is ready now */
ret = sd_notify(0, "READY=1");
if (ret <= 0)
util_log_print(UTIL_LOG_WARN, "Failed to notify systemd (%d)\n",
ret);
#endif
ret = wait_for_vmcore_overlay(vmcore_overlay_tid);
if (ret < 0)
exit_code = EXIT_FAILURE;
#ifdef HAVE_SYSTEMD
/* Tell systemd that service is stopping now */
ret = sd_notify(0, "STOPPING=1");
if (ret <= 0)
util_log_print(UTIL_LOG_WARN, "Failed to notify systemd (%d)\n",
ret);
#endif
unblock_all_signals();
if (config.bind_mount_vmcore)
unmount_detach(config.bind_mount_vmcore_path);
destroy_vmcore_overlay:
destroy_vmcore_overlay(vmcore_overlay);
destroy_vmcore_proxy:
destroy_vmcore_proxy(vmcore_proxy);
destroy_hsa_reader:
destroy_hsa_reader(hsa_reader);
unmount_debugfs:
if (config.mount_debugfs)
unmount_detach(DEBUGFS_MOUNT_POINT);
swap_off:
if (strlen(config.swap))
swap_off(config.swap);
done:
return exit_code;
}

139
hsavmcore/man/hsavmcore.8 Normal file
View File

@@ -0,0 +1,139 @@
.\" Copyright 2021 IBM Corp.
.\" s390-tools is free software; you can redistribute it and/or modify
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH HSAVMCORE 8 "May 2021" "s390-tools"
.
.SH NAME
hsavmcore - Enable kdump to release the HSA memory early in the dump process
.
.SH SYNOPSIS
.B hsavmcore
.RI [ OPTIONS ]
.
.SH DESCRIPTION
.B hsavmcore
is designed to make the dump process with kdump more efficient.
The HSA memory contains a part of the production kernel's memory.
Use hsavmcore to cache this information and release HSA memory early in the process.
.PP
Depending on the size of the production kernel's memory, writing the dump to persistent
storage can be time consuming and prevent the HSA memory from being reused by other LPARs.
.
The
.B hsavmcore
tool performs these steps:
.IP " 1)"
Read the size of the HSA memory from
.B /sys/kernel/debug/zcore/hsa.
.IP " 2)"
Cache the HSA memory content contained in
.B /proc/vmcore
either in regular memory or within the file system.
.IP " 3)"
Releases the HSA memory by writing to
.B /sys/kernel/debug/zcore/hsa.
.PP
At this stage, the HSA memory region is unavailable to
.B /proc/vmcore
and cannot be used by kdump.
.
The
.B hsavmcore
tool now combines the cached HSA memory and the non-HSA memory from the original
.B /proc/vmcore
to create a replacement for
.B /proc/vmcore.
.
The replacement
.B /proc/vmcore
can be processed as usual.
.
.SH OPTIONS
.TP
\fB\-h\fP or \fB\-\-help\fP
Print usage information and exit.
.
.TP
\fB\-v\fP or \fB\-\-version\fP
Print version information and exit.
.
.TP
\fB\-V\fP or \fB\-\-verbose\fP
Print verbose messages to stdout. Repeat this option for increased verbosity
from just error messages to also include warning, information, debug, and trace messages.
This option is intended for debugging.
.
.TP
\fB\-c\fP or \fB\-\-config\fP \fICONFIGFILE\fP
Path to the configuration file. By default, no configuration file is used.
.
.TP
\fB\-C\fP or \fB\-\-vmcore\fP \fIVMCOREFILE\fP
Path to the vmcore file. Default:
.B /proc/vmcore.
.
.TP
\fB\-H\fP or \fB\-\-hsa\fP \fIZCOREHSAFILE\fP
Path to the zcore HSA file. Default:
.B /sys/kernel/debug/zcore/hsa.
.
.TP
\fB\-W\fP or \fB\-\-workdir\fP \fIWORKDIR\fP
Path to the work directory where temporary files can be stored. Default:
.B /var/crash.
.
.TP
\fB\-B\fP or \fB\-\-bmvmcore\fP \fIVMCOREFILE\fP
Path to the target of the bind mount for the replacement vmcore file. Default:
.B /proc/vmcore.
.
.TP
\fB\-S\fP or \fB\-\-swap\fP \fIPATH\fP
Path to a swap device or file. The specified swap device or file must exist and have the proper
swap format. Default: no swap device or file is activated.
.
.TP
\fB\-T\fP or \fB\-\-hsasize\fP \fIHSASIZE\fP
HSA size in bytes. Used for testing purposes. Default: -1 (read from the zcore HSA file).
.
.TP
\fB\-D\fP or \fB\-\-dbgfsmnt\fP
Mount the debug file system. Default: the debug file system is not mounted.
.
.TP
\fB\-F\fP or \fB\-\-hsamem\fP
Cache the HSA memory in regular memory. Default: the HSA memory is cached as a file
within WORKDIR.
.
.TP
\fB\-R\fP or \fB\-\-norelhsa\fP
Do NOT release the HSA memory after caching. Default: the HSA memory is released.
.
.TP
\fB\-N\fP or \fB\-\-nobindmnt\fP
Do NOT replace the system's vmcore file. Default: the system's vmcore file is replaced.
.
.TP
\fB\-G\fP or \fB\-\-fusedbg\fP
Enable FUSE debugging. Default: FUSE debugging is disabled.
.RE
.
.SH EXAMPLES
.TP
.B To run hsavmcore on a kdump system during a stand-alone dump with default parameters:
.RS 4
hsavmcore
.br
makedumpfile \-d 31 /proc/vmcore test-dump.elf
.RE
.TP
.B To test hsavmcore with a vmcore copy and without being in a kdump system (for debugging):
.RS 4
hsavmcore \-VVV \-T 0x1ffff000 \-C vmcore-dump.elf \-N \-R
.br
makedumpfile \-d 31 /tmp/hsavmcore-overlay/vmcore test-dump.elf
.RE
.SH SEE ALSO
.BR hsavmcore.conf (5)

View File

@@ -0,0 +1,118 @@
.\" Copyright 2021 IBM Corp.
.\" s390-tools is free software; you can redistribute it and/or modify
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH HSAVMCORE.CONF 5 "May 2021" "s390-tools"
.SH NAME
hsavmcore.conf \- Configuration file for the hsavmcore tool
.
.SH DESCRIPTION
The
.B hsavmcore.conf
configuration file contains the configuration information for
the
.B hsavmcore
tool.
All specifications in the configuration file are optional.
The command defaults apply for omitted parameters.
.
.SS "verbose"
This parameter sets the verbosity level of the output messages.
The following pre-defined numeric values can be used:
.
.RS 2
.IP "-" 2
\fB0\fP - show only error messages (default)
.IP "-" 2
\fB1\fP - show error and warning messages
.IP "-" 2
\fB2\fP - show error, warning and information messages
.IP "-" 2
\fB3\fP - show error, warning, information and debug messages
.IP "-" 2
\fB4\fP - show error, warning, information, debug and trace messages
.RE
.PP
.
.SS "mount_debugfs"
Mount (1) or do not mount (0) debugfs. Use this configuration if the kdump kernel
does not mount the debugfs during the boot process.
.
.SS "workdir"
Specifies a work directory on the kdump system where the hsavmcore tool can create
temporary files. This specification is required if
.B use_hsa_mem
is set to 0.
.
.SS "use_hsa_mem"
Cache the HSA memory in regular memory (1) or in a file on a file system (0).
.
.SS "hsa_size"
Specify a value, in bytes, for the HSA memory size instead of reading the size
from
.B /sys/kernel/debug/zcore/hsa.
This parameter is intended only to test
the
.B hsavmcore
tool without being in a kdump kernel. Specifying -1 falls back
to reading the size from
.B /sys/kernel/debug/zcore/hsa.
.
.SS "release_hsa"
Release (1) or do not release (0) the HSA memory after it is cached by
the
.B hsavmcore
tool.
.
.SS "bind_mount_vmcore"
Replace (1) the original vmcore file with the new file created by the
.B hsavmcore
tool or keep the original file (0), which no longer contains the information
from the HSA memory. Set this parameter to 1 if you intend to use kdump tools to
create a core dump.
.
.SS "swap"
Specify a swap device or file through its path in a kdump system.
The specified swap device or file must exist and have the proper swap format.
You might need a swap device because the amount of memory available in the kdump
kernel during a stand-alone dump is limited to the size of the HSA memory.
.
.SS "fuse_debug"
Enable (1) or disable (0) fuse debugging.
.
.SH EXAMPLES
A complete configuration file could look like this:
.nf
------------------------------ config file start ------------------------------
# Example configuration for hsavmcore
# 0 - ERROR
# 1 - WARN
# 2 - INFO
# 3 - DEBUG
# 4 - TRACE
verbose = 3
workdir = /var/crash
mount_debugfs = 1
use_hsa_mem = 1
hsa_size = -1
release_hsa = 1
bind_mount_vmcore = 1
swap = /dev/disk/by-uuid/3cf6630b-4c4d-49ac-a0ae-0f5484cb5721
#swap = /swap.img
fuse_debug = 0
------------------------------ config file end ------------------------------
.fi
.
.SH SEE ALSO
.BR hsavmcore (8)

63
hsavmcore/mount.c Normal file
View File

@@ -0,0 +1,63 @@
/*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <sys/mount.h>
#include "lib/util_log.h"
#include "mount.h"
int mount_debugfs(const char *target)
{
int ret;
util_log_print(UTIL_LOG_INFO, "Mount debugfs on %s\n", target);
ret = mount("none", target, "debugfs", 0, NULL);
if (ret) {
util_log_print(UTIL_LOG_ERROR, "mount syscall failed (%s)\n",
strerror(errno));
return -1;
}
return 0;
}
int bind_mount(const char *src, const char *target)
{
int ret;
util_log_print(UTIL_LOG_INFO, "Bind mount %s on %s\n", src, target);
ret = mount(src, target, "", MS_BIND, NULL);
if (ret) {
util_log_print(UTIL_LOG_ERROR, "mount syscall failed (%s)\n",
strerror(errno));
return -1;
}
return 0;
}
int unmount_detach(const char *target)
{
int ret;
util_log_print(UTIL_LOG_INFO, "Unmount detach %s\n", target);
ret = umount2(target, MNT_DETACH);
if (ret) {
util_log_print(UTIL_LOG_ERROR, "umount2 syscall failed (%s)\n",
strerror(errno));
return -1;
}
return 0;
}

17
hsavmcore/mount.h Normal file
View File

@@ -0,0 +1,17 @@
/*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef _HSAVMCORE_MOUNT_H
#define _HSAVMCORE_MOUNT_H
int mount_debugfs(const char *target);
int bind_mount(const char *src, const char *target);
int unmount_detach(const char *target);
#endif

209
hsavmcore/overlay.c Normal file
View File

@@ -0,0 +1,209 @@
/*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define FUSE_USE_VERSION 26
#include <fuse.h>
#include "lib/util_log.h"
#include "common.h"
#include "overlay.h"
#define ROOT_DIR "/"
struct vmcore_overlay {
struct vmcore_proxy *vmcore_proxy;
char mount_point[PATH_MAX];
bool fuse_debug;
};
static int vmcore_fuse_getattr(const char *path, struct stat *stbuf)
{
struct vmcore_overlay *overlay = fuse_get_context()->private_data;
int ret = 0;
memset(stbuf, 0, sizeof(struct stat));
if (strcmp(path, ROOT_DIR) == 0) {
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 2;
} else if (strcmp(path + 1, VMCORE_FILE) == 0) {
stbuf->st_mode = S_IFREG | 0444;
stbuf->st_nlink = 1;
stbuf->st_size = vmcore_proxy_size(overlay->vmcore_proxy);
} else {
ret = -ENOENT;
}
return ret;
}
static int vmcore_fuse_readdir(const char *path, void *buf,
fuse_fill_dir_t filler, off_t offset,
struct fuse_file_info *fi)
{
(void)offset;
(void)fi;
if (strcmp(path, ROOT_DIR) != 0)
return -ENOENT;
/* We have only one file */
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, VMCORE_FILE, NULL, 0);
return 0;
}
static int vmcore_fuse_open(const char *path, struct fuse_file_info *fi)
{
if (strcmp(path + 1, VMCORE_FILE) != 0)
return -ENOENT;
if ((fi->flags & O_ACCMODE) != O_RDONLY)
return -EACCES;
return 0;
}
static int vmcore_fuse_read(const char *path, char *buf, size_t size,
off_t offset, struct fuse_file_info *fi)
{
(void)fi;
if (strcmp(path + 1, VMCORE_FILE) != 0)
return -ENOENT;
struct vmcore_overlay *overlay = fuse_get_context()->private_data;
return read_vmcore_proxy_at(overlay->vmcore_proxy, offset, buf, size);
}
static int setup_fuse_args(struct fuse_args *args, const char *mount_point,
bool debug)
{
int ret;
ret = fuse_opt_add_arg(args, NAME);
if (ret)
goto done;
/* Single-threaded */
ret = fuse_opt_add_arg(args, "-s");
if (ret)
goto done;
/* Foreground */
ret = fuse_opt_add_arg(args, "-f");
if (ret)
goto done;
/* Debugging */
if (debug) {
ret = fuse_opt_add_arg(args, "-d");
if (ret)
goto done;
}
ret = fuse_opt_add_arg(args, mount_point);
if (ret)
goto done;
done:
if (ret)
return -1;
else
return 0;
}
struct vmcore_overlay *make_vmcore_overlay(struct vmcore_proxy *vmcore_proxy,
const char *mount_point,
bool fuse_debug)
{
struct vmcore_overlay *overlay;
util_log_print(UTIL_LOG_INFO, "vmcore overlay: mountpoint=%s\n",
mount_point);
overlay = malloc(sizeof(struct vmcore_overlay));
if (!overlay) {
util_log_print(UTIL_LOG_ERROR, "malloc failed\n");
return NULL;
}
overlay->vmcore_proxy = vmcore_proxy;
strncpy(overlay->mount_point, mount_point,
sizeof(overlay->mount_point) - 1);
/* Ensure null termination */
overlay->mount_point[sizeof(overlay->mount_point) - 1] = '\0';
overlay->fuse_debug = fuse_debug;
return overlay;
}
void destroy_vmcore_overlay(struct vmcore_overlay *overlay)
{
free(overlay);
}
/*
* FUSE file system operations
*/
static struct fuse_operations vmcore_fuse_ops = {
.getattr = vmcore_fuse_getattr,
.readdir = vmcore_fuse_readdir,
.open = vmcore_fuse_open,
.read = vmcore_fuse_read,
};
int serve_vmcore_overlay(struct vmcore_overlay *overlay)
{
struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
int ret;
util_log_print(UTIL_LOG_DEBUG, "vmcore overlay: FUSE main\n");
ret = setup_fuse_args(&args, overlay->mount_point, overlay->fuse_debug);
if (ret < 0)
goto free_args;
/* Create mount point */
ret = mkdir(overlay->mount_point, 0755);
if (ret < 0) {
util_log_print(UTIL_LOG_ERROR, "mkdir syscall failed (%s)\n",
strerror(errno));
goto free_args;
}
/*
* Run file system, blocks until a signal has been received or an error
* occurred.
*/
fuse_main(args.argc, args.argv, &vmcore_fuse_ops, overlay);
/* Remove mount point */
rmdir(overlay->mount_point);
ret = 0;
free_args:
fuse_opt_free_args(&args);
return ret;
}

33
hsavmcore/overlay.h Normal file
View File

@@ -0,0 +1,33 @@
/*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef _HSAVMCORE_OVERLAY_H
#define _HSAVMCORE_OVERLAY_H
#include <stdbool.h>
#include "proxy.h"
/*
* A vmcore Overlay exports a vmcore Proxy as a normal read-only file
* that could be used, for instance, by *makedumpfile*.
*/
struct vmcore_overlay;
struct vmcore_overlay *make_vmcore_overlay(struct vmcore_proxy *vmcore_proxy,
const char *mount_point,
bool fuse_debug);
void destroy_vmcore_overlay(struct vmcore_overlay *overlay);
/*
* This method handles all file system calls and blocks until a signal arrives.
*/
int serve_vmcore_overlay(struct vmcore_overlay *overlay);
#endif

198
hsavmcore/proxy.c Normal file
View File

@@ -0,0 +1,198 @@
/*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "lib/zt_common.h"
#include "lib/util_log.h"
#include "proxy.h"
struct vmcore_proxy {
int vmcore_fd;
long vmcore_size;
struct hsa_reader *hsa_reader;
};
static int read_file_at(int fd, long offset, void *buf, int size)
{
long n, nread = 0;
util_log_print(UTIL_LOG_DEBUG,
"vmcore proxy vmcore read: offset=%lx size=%x\n", offset,
size);
n = lseek(fd, offset, SEEK_SET);
if (n < 0) {
util_log_print(UTIL_LOG_ERROR, "lseek syscall failed (%s)\n",
strerror(errno));
return -1;
}
while (size) {
n = read(fd, buf + nread, size);
if (n < 0) {
util_log_print(UTIL_LOG_ERROR,
"read syscall failed (%s)\n",
strerror(errno));
return -1;
} else if (n == 0) {
break;
}
nread += n;
size -= n;
}
return nread;
}
static long get_vmcore_size(int fd)
{
long n, size;
/* Get vmcore file size */
n = lseek(fd, 0, SEEK_END);
if (n < 0) {
util_log_print(UTIL_LOG_ERROR, "lseek syscall failed (%s)\n",
strerror(errno));
return 0;
}
size = n;
/* Reset vmcore file position */
n = lseek(fd, 0, SEEK_SET);
if (n < 0) {
util_log_print(UTIL_LOG_ERROR, "lseek syscall failed (%s)\n",
strerror(errno));
return 0;
}
return size;
}
struct vmcore_proxy *make_vmcore_proxy(const char *vmcore_path,
struct hsa_reader *hsa_reader)
{
struct vmcore_proxy *proxy;
int vmcore_fd;
long vmcore_size;
util_log_print(UTIL_LOG_INFO, "vmcore proxy: vmcore path=%s\n",
vmcore_path);
/* Open vmcore file */
vmcore_fd = open(vmcore_path, O_RDONLY);
if (vmcore_fd < 0) {
util_log_print(UTIL_LOG_ERROR, "open syscall failed (%s)\n",
strerror(errno));
return NULL;
}
vmcore_size = get_vmcore_size(vmcore_fd);
if (!vmcore_size) {
close(vmcore_fd);
return NULL;
}
util_log_print(UTIL_LOG_INFO, "vmcore proxy: vmcore size=%lx\n",
vmcore_size);
proxy = malloc(sizeof(struct vmcore_proxy));
if (!proxy) {
util_log_print(UTIL_LOG_ERROR, "malloc failed\n");
close(vmcore_fd);
return NULL;
}
proxy->vmcore_fd = vmcore_fd;
proxy->vmcore_size = vmcore_size;
proxy->hsa_reader = hsa_reader;
return proxy;
}
void destroy_vmcore_proxy(struct vmcore_proxy *proxy)
{
close(proxy->vmcore_fd);
free(proxy);
}
long vmcore_proxy_size(struct vmcore_proxy *proxy)
{
return proxy->vmcore_size;
}
int read_vmcore_proxy_at(struct vmcore_proxy *proxy, long offset, void *buf,
int size)
{
const long hsa_size = hsa_get_size(proxy->hsa_reader);
const long hsa_vmcore_offset = hsa_get_vmcore_offset(proxy->hsa_reader);
long nread = 0;
util_log_print(UTIL_LOG_DEBUG,
"vmcore proxy read: offset=%lx size=%x\n", offset, size);
/*
* The caller might try to read beyond the maximum length of vmcore.
* This guarantees the termination of the loop below in that case.
*/
size = MIN(proxy->vmcore_size - offset, size);
/*
* 0 HSA offset HSA offset + vmcore size
* HSA size
*
* +---------------------+---------------------+-----------------------+
* | | | |
* | vmcore 1st part | HSA memory region | vmcore 2nd part |
* | | | |
* +---------------------+---------------------+-----------------------+
*/
while (size) {
long n, nbyte;
if (offset < hsa_vmcore_offset) {
/* vmcore 1st part */
nbyte = MIN(hsa_vmcore_offset - offset, size);
n = read_file_at(proxy->vmcore_fd, offset, buf + nread,
nbyte);
} else if (offset >= hsa_vmcore_offset &&
offset < (hsa_vmcore_offset + hsa_size)) {
/* HSA memory region */
nbyte = MIN(hsa_vmcore_offset + hsa_size - offset,
size);
n = read_hsa_at(proxy->hsa_reader,
offset - hsa_vmcore_offset,
buf + nread, nbyte);
} else {
/* vmcore 2nd part */
nbyte = MIN(proxy->vmcore_size - offset, size);
n = read_file_at(proxy->vmcore_fd, offset, buf + nread,
nbyte);
}
if (n != nbyte)
return -1;
nread += n;
size -= n;
offset += n;
}
return nread;
}

35
hsavmcore/proxy.h Normal file
View File

@@ -0,0 +1,35 @@
/*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef _HSAVMCORE_PROXY_H
#define _HSAVMCORE_PROXY_H
#include "hsa.h"
/*
* A vmcore Proxy combines the original /proc/vmcore file with a HSA memory
* reader into a new interface which can be used to read vmcore data w/o being
* aware that the HSA memory region is NOT contained in the file /proc/vmcore.
*
* After releasing the HSA memory, the original /proc/vmcore will contain
* a *hole* where the HSA memory was located. The vmcore proxy hides this
* inconvenience from the user of this interface.
*/
struct vmcore_proxy;
struct vmcore_proxy *make_vmcore_proxy(const char *vmcore_path,
struct hsa_reader *hsa_reader);
void destroy_vmcore_proxy(struct vmcore_proxy *proxy);
long vmcore_proxy_size(struct vmcore_proxy *proxy);
int read_vmcore_proxy_at(struct vmcore_proxy *proxy, long offset, void *buf,
int size);
#endif

51
hsavmcore/swap.c Normal file
View File

@@ -0,0 +1,51 @@
/*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/swap.h>
#include "lib/util_log.h"
#include "common.h"
#include "swap.h"
int swap_on(const char *path)
{
int ret;
util_log_print(UTIL_LOG_INFO, "Swap on %s\n", path);
ret = swapon(path, 0);
if (ret) {
util_log_print(UTIL_LOG_ERROR, "swapon syscall failed (%s)\n",
strerror(errno));
return ret;
}
return 0;
}
int swap_off(const char *path)
{
int ret;
util_log_print(UTIL_LOG_INFO, "Swap off %s\n", path);
ret = swapoff(path);
if (ret) {
util_log_print(UTIL_LOG_ERROR, "swapoff syscall failed (%s)\n",
strerror(errno));
return ret;
}
return 0;
}

15
hsavmcore/swap.h Normal file
View File

@@ -0,0 +1,15 @@
/*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef _HSAVMCORE_SWAP_H
#define _HSAVMCORE_SWAP_H
int swap_on(const char *path);
int swap_off(const char *path);
#endif

430
hsci/hsci
View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -115,7 +115,7 @@
#include "lib/util_base.h"
#include "lib/util_list.h"
#include "vtoc.h"
#include <iconv.h>
/**
@@ -834,6 +834,11 @@ void lzds_dshandle_get_errorlog(struct dshandle *dsh, struct errorlog **log);
int lzds_dshandle_set_seekbuffer(struct dshandle *dsh,
unsigned long long seek_buffer_size);
/**
* @brief Set iconv handle for codepage conversion.
*/
int lzds_dshandle_set_iconv(struct dshandle *dsh, iconv_t *iconv);
/**
* @brief Get the size of the data set in number of tracks (sum of all extents).
*/

39
include/lib/util_arch.h Normal file
View File

@@ -0,0 +1,39 @@
/**
* @defgroup util_arch_h util_arch: General architecture helpers
* @{
* @brief General architecture helpers
*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef LIB_UTIL_ARCH_H
#define LIB_UTIL_ARCH_H
enum util_arch_machine_type {
UTIL_ARCH_MACHINE_TYPE_UNKNOWN = 0,
UTIL_ARCH_MACHINE_TYPE_Z10_EC = 2097,
UTIL_ARCH_MACHINE_TYPE_Z10_BC = 2098,
UTIL_ARCH_MACHINE_TYPE_ZE_196 = 2817,
UTIL_ARCH_MACHINE_TYPE_ZE_114 = 2818,
UTIL_ARCH_MACHINE_TYPE_ZE_EC12 = 2827,
UTIL_ARCH_MACHINE_TYPE_ZE_BC12 = 2828,
UTIL_ARCH_MACHINE_TYPE_Z13 = 2964,
UTIL_ARCH_MACHINE_TYPE_Z13_S = 2965,
UTIL_ARCH_MACHINE_TYPE_Z14 = 3906,
UTIL_ARCH_MACHINE_TYPE_Z14_ZR1 = 3907,
UTIL_ARCH_MACHINE_TYPE_Z15 = 8561,
UTIL_ARCH_MACHINE_TYPE_Z15_T02 = 8562,
};
int util_arch_machine_type(void);
const char *util_arch_machine_type_str(void);
const char *util_arch_machine_type_to_str(int type);
unsigned long util_arch_hsa_maxsize(void);
#endif /** LIB_UTIL_ARCH_H @} */

View File

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

28
include/lib/util_log.h Normal file
View File

@@ -0,0 +1,28 @@
/**
* @defgroup util_log_h util_log: Multi-level message logging interface
* @{
* @brief Multi-level message logging
*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef LIB_UTIL_LOG_H
#define LIB_UTIL_LOG_H
enum util_log_level {
UTIL_LOG_ERROR,
UTIL_LOG_WARN,
UTIL_LOG_INFO,
UTIL_LOG_DEBUG,
UTIL_LOG_TRACE,
UTIL_LOG_NUM_LEVELS /* Must be the last one. */
};
void util_log_set_level(int log_level);
void util_log_print(int log_level, const char *fmt, ...);
#endif /** LIB_UTIL_LOG_H @} */

View File

@@ -27,25 +27,10 @@ struct util_proc_dev_entry {
char *name;
};
/**
* Container for the fields of the output of /proc/mounts (man fstab)
*/
struct util_proc_mnt_entry {
char *spec;
char *file;
char *vfstype;
char *mntOpts;
char *dump;
char *passno;
};
int util_proc_part_get_entry(dev_t device, struct util_proc_part_entry *entry);
void util_proc_part_free_entry(struct util_proc_part_entry *entry);
int util_proc_dev_get_entry(dev_t dev, int blockdev,
struct util_proc_dev_entry *entry);
void util_proc_dev_free_entry(struct util_proc_dev_entry *entry);
int util_proc_mnt_get_entry(const char *file_name, const char *spec,
struct util_proc_mnt_entry *entry);
void util_proc_mnt_free_entry(struct util_proc_mnt_entry *entry);
#endif /* LIB_UTIL_PROC_H */

View File

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

View File

@@ -0,0 +1,48 @@
/*
* libseckey - Secure key library
*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef SK_CCA_H
#define SK_CCA_H
#include <stddef.h>
#include <stdbool.h>
#include <openssl/evp.h>
#include "libseckey/sk_openssl.h"
#define CCA_MAX_PKA_KEY_TOKEN_SIZE 3500
int SK_CCA_generate_ec_key_pair(const struct sk_ext_cca_lib *cca_lib,
int curve_nid, unsigned char *key_token,
size_t *key_token_length, bool debug);
int SK_CCA_generate_rsa_key_pair(const struct sk_ext_cca_lib *cca_lib,
size_t modulus_bits, unsigned int pub_exp,
unsigned char *key_token,
size_t *key_token_length, bool debug);
int SK_CCA_get_key_type(const unsigned char *key_token, size_t key_token_length,
int *pkey_type);
int SK_CCA_get_secure_key_as_pkey(const struct sk_ext_cca_lib *cca_lib,
const unsigned char *key_token,
size_t key_token_length,
bool rsa_pss, EVP_PKEY **pkey, bool debug);
int SK_CCA_get_public_from_secure_key(const unsigned char *key_token,
size_t key_token_length,
sk_pub_key_func_t pub_key_cb,
void *private,
bool debug);
int SK_CCA_reencipher_key(const struct sk_ext_cca_lib *cca_lib,
unsigned char *key_token, size_t key_token_length,
bool to_new, bool debug);
#endif

177
include/libseckey/sk_ep11.h Normal file
View File

@@ -0,0 +1,177 @@
/*
* libseckey - Secure key library
*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef SK_EP11_H
#define SK_EP11_H
#include <stddef.h>
#include <stdbool.h>
#include <openssl/evp.h>
#include "libseckey/sk_openssl.h"
#define EP11_MAX_KEY_TOKEN_SIZE 8192
int SK_EP11_generate_ec_key_pair(const struct sk_ext_ep11_lib *ep11_lib,
int curve_nid, unsigned char *key_token,
size_t *key_token_length, bool debug);
int SK_EP11_generate_rsa_key_pair(const struct sk_ext_ep11_lib *ep11_lib,
size_t modulus_bits, unsigned int pub_exp,
bool x9_31, unsigned char *key_token,
size_t *key_token_length, bool debug);
int SK_EP11_get_key_type(const unsigned char *key_token,
size_t key_token_length,
int *pkey_type);
const unsigned char *SK_EP11_get_key_blob(const unsigned char *key_token,
size_t key_token_length);
size_t SK_EP11_get_key_blob_size(const unsigned char *key_token,
size_t key_token_length);
int SK_EP11_get_secure_key_as_pkey(const struct sk_ext_ep11_lib *ep11_lib,
const unsigned char *key_token,
size_t key_token_length,
bool rsa_pss, EVP_PKEY **pkey, bool debug);
int SK_EP11_get_public_from_secure_key(const unsigned char *key_token,
size_t key_token_length,
sk_pub_key_func_t pub_key_cb,
void *private,
bool debug);
int SK_EP11_reencipher_key(const struct sk_ext_ep11_lib *ep11_lib,
unsigned char *key_token, size_t key_token_length,
bool debug);
/* PKCS#11 definitions */
#define CK_PTR *
typedef unsigned char CK_BYTE;
typedef CK_BYTE CK_CHAR;
typedef CK_BYTE CK_UTF8CHAR;
typedef CK_BYTE CK_BBOOL;
typedef unsigned long CK_ULONG;
typedef long CK_LONG;
typedef CK_ULONG CK_FLAGS;
typedef CK_ULONG CK_RV;
typedef CK_ULONG CK_SLOT_ID;
typedef CK_ULONG CK_MECHANISM_TYPE;
typedef CK_ULONG CK_ATTRIBUTE_TYPE;
typedef CK_ULONG CK_OBJECT_CLASS;
typedef CK_ULONG CK_KEY_TYPE;
typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE;
typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE;
typedef CK_BYTE CK_PTR CK_BYTE_PTR;
typedef CK_CHAR CK_PTR CK_CHAR_PTR;
typedef CK_UTF8CHAR CK_PTR CK_UTF8CHAR_PTR;
typedef CK_ULONG CK_PTR CK_ULONG_PTR;
typedef void CK_PTR CK_VOID_PTR;
typedef CK_SLOT_ID CK_PTR CK_SLOT_ID_PTR;
typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR;
typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR;
typedef struct CK_MECHANISM {
CK_MECHANISM_TYPE mechanism;
CK_VOID_PTR pParameter;
CK_ULONG ulParameterLen;
} CK_MECHANISM;
typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR;
typedef struct CK_ATTRIBUTE {
CK_ATTRIBUTE_TYPE type;
CK_VOID_PTR pValue;
CK_ULONG ulValueLen;
} CK_ATTRIBUTE;
typedef CK_ATTRIBUTE CK_PTR CK_ATTRIBUTE_PTR;
typedef struct CK_RSA_PKCS_PSS_PARAMS {
CK_MECHANISM_TYPE hashAlg;
CK_RSA_PKCS_MGF_TYPE mgf;
CK_ULONG sLen;
} CK_RSA_PKCS_PSS_PARAMS;
typedef CK_RSA_PKCS_PSS_PARAMS CK_PTR CK_RSA_PKCS_PSS_PARAMS_PTR;
typedef struct CK_RSA_PKCS_OAEP_PARAMS {
CK_MECHANISM_TYPE hashAlg;
CK_RSA_PKCS_MGF_TYPE mgf;
CK_RSA_PKCS_OAEP_SOURCE_TYPE source;
CK_VOID_PTR pSourceData;
CK_ULONG ulSourceDataLen;
} CK_RSA_PKCS_OAEP_PARAMS;
typedef CK_RSA_PKCS_OAEP_PARAMS CK_PTR CK_RSA_PKCS_OAEP_PARAMS_PTR;
#define CKZ_DATA_SPECIFIED 0x00000001
#define CKG_MGF1_SHA1 0x00000001
#define CKG_MGF1_SHA224 0x00000005
#define CKG_MGF1_SHA256 0x00000002
#define CKG_MGF1_SHA384 0x00000003
#define CKG_MGF1_SHA512 0x00000004
#define CKG_VENDOR_DEFINED 0x80000000UL
#define CKG_IBM_MGF1_SHA3_224 (CKG_VENDOR_DEFINED + 1)
#define CKG_IBM_MGF1_SHA3_256 (CKG_VENDOR_DEFINED + 2)
#define CKG_IBM_MGF1_SHA3_384 (CKG_VENDOR_DEFINED + 3)
#define CKG_IBM_MGF1_SHA3_512 (CKG_VENDOR_DEFINED + 4)
#define CKR_OK 0x00000000
#define CKR_VENDOR_DEFINED 0x80000000
#define CKO_PUBLIC_KEY 0x00000002
#define CKO_PRIVATE_KEY 0x00000003
#define CKK_EC 0x00000003
#define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000
#define CKM_RSA_PKCS 0x00000001
#define CKM_RSA_PKCS_OAEP 0x00000009
#define CKM_RSA_X9_31_KEY_PAIR_GEN 0x0000000A
#define CKM_RSA_X9_31 0x0000000B
#define CKM_RSA_PKCS_PSS 0x0000000D
#define CKM_SHA_1 0x00000220
#define CKM_SHA256 0x00000250
#define CKM_SHA224 0x00000255
#define CKM_SHA384 0x00000260
#define CKM_SHA512 0x00000270
#define CKM_SHA512_224 0x00000048
#define CKM_SHA512_256 0x0000004C
#define CKM_EC_KEY_PAIR_GEN 0x00001040
#define CKM_ECDSA 0x00001041
#define CKM_VENDOR_DEFINED 0x80000000
#define CKM_IBM_SHA3_224 (CKM_VENDOR_DEFINED + 0x00010001)
#define CKM_IBM_SHA3_256 (CKM_VENDOR_DEFINED + 0x00010002)
#define CKM_IBM_SHA3_384 (CKM_VENDOR_DEFINED + 0x00010003)
#define CKM_IBM_SHA3_512 (CKM_VENDOR_DEFINED + 0x00010004)
#define CKA_CLASS 0x00000000
#define CKA_KEY_TYPE 0x00000100
#define CKA_SENSITIVE 0x00000103
#define CKA_ENCRYPT 0x00000104
#define CKA_DECRYPT 0x00000105
#define CKA_SIGN 0x00000108
#define CKA_VERIFY 0x0000010A
#define CKA_DERIVE 0x0000010C
#define CKA_DECRYPT 0x00000105
#define CKA_WRAP 0x00000106
#define CKA_UNWRAP 0x00000107
#define CKA_MODULUS_BITS 0x00000121
#define CKA_PUBLIC_EXPONENT 0x00000122
#define CKA_EC_PARAMS 0x00000180
#endif

View File

@@ -0,0 +1,234 @@
/*
* libseckey - Secure key library
*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef SK_OPENSSL_H
#define SK_OPENSSL_H
#include <stddef.h>
#include <stdbool.h>
#include <openssl/evp.h>
#include <openssl/opensslv.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#ifndef OPENSSL_VERSION_PREREQ
#if defined(OPENSSL_VERSION_MAJOR) && defined(OPENSSL_VERSION_MINOR)
#define OPENSSL_VERSION_PREREQ(maj, min) \
((OPENSSL_VERSION_MAJOR << 16) + \
OPENSSL_VERSION_MINOR >= ((maj) << 16) + (min))
#else
#define OPENSSL_VERSION_PREREQ(maj, min) \
(OPENSSL_VERSION_NUMBER >= (((maj) << 28) | \
((min) << 20)))
#endif
#endif
/**
* External crypto library definitions
*/
struct sk_ext_cca_lib {
void *cca_lib; /* Handle of CCA host library loaded via dlopen */
};
typedef uint64_t target_t;
struct sk_ext_ep11_lib {
void *ep11_lib; /* Handle of EP11 host library loaded via dlopen */
target_t target; /* single or group target handle */
};
enum sk_ext_lib_type {
SK_EXT_LIB_CCA = 1,
SK_EXT_LIB_EP11 = 2,
};
struct sk_ext_lib {
enum sk_ext_lib_type type;
union {
struct sk_ext_cca_lib *cca; /* Used if type = EXT_LIB_CCA */
struct sk_ext_ep11_lib *ep11; /* Used if type = EXT_LIB_EP11 */
};
};
/*
* Secure key library initialization and termination functions
*/
int SK_OPENSSL_init(bool debug);
void SK_OPENSSL_term(void);
/*
* Secure key generation and reenciphering definitions and functions
*/
enum sk_key_type {
SK_KEY_TYPE_EC = 1,
SK_KEY_TYPE_RSA = 2,
};
struct sk_key_gen_info {
enum sk_key_type type;
union {
struct {
int curve_nid;
} ec;
struct {
size_t modulus_bits;
unsigned int pub_exp;
bool x9_31;
} rsa;
};
};
int SK_OPENSSL_generate_secure_key(unsigned char *secure_key,
size_t *secure_key_size,
const struct sk_key_gen_info *info,
const struct sk_ext_lib *ext_lib,
bool debug);
int SK_OPENSSL_reencipher_secure_key(unsigned char *secure_key,
size_t secure_key_size, bool to_new,
const struct sk_ext_lib *ext_lib,
bool debug);
/*
* Get an OpenSSL PKEY from a secure key to be used with OpenSSL.
*/
int SK_OPENSSL_get_secure_key_as_pkey(const unsigned char *secure_key,
size_t secure_key_size, bool rsa_pss,
EVP_PKEY **pkey,
const struct sk_ext_lib *ext_lib,
bool debug);
/*
* Get the public key parts from a secure key.
*/
struct sk_pub_key_info {
enum sk_key_type type;
union {
struct {
int curve_nid;
size_t prime_len;
const unsigned char *x;
const unsigned char *y;
} ec;
struct {
size_t modulus_len;
const unsigned char *modulus;
size_t pub_exp_len;
const unsigned char *pub_exp;
} rsa;
};
};
typedef int (*sk_pub_key_func_t)(const struct sk_pub_key_info *pub_key,
void *private);
int SK_OPENSSL_get_public_from_secure_key(const unsigned char *secure_key,
size_t secure_key_size,
sk_pub_key_func_t pub_key_cb,
void *private,
const struct sk_ext_lib *ext_lib,
bool debug);
/*
* Helper functions to setup a secure key sign context and to generate
* certificate signing requests or self signed certificates with the secure key
*/
struct sk_rsa_pss_params {
/*
* salt length in bytes, or OpenSSL constants
* RSA_PSS_SALTLEN_DIGEST (-1), RSA_PSS_SALTLEN_AUTO (-2), or
* RSA_PSS_SALTLEN_MAX(-3)
*/
int salt_len;
/*
* OpenSSl digest nid, or NID_undef to use the same digest algorithm
* as the signature algorithm
*/
int mgf_digest_nid;
};
int SK_OPENSSL_setup_sign_context(EVP_PKEY *pkey, bool verify, int digest_nid,
struct sk_rsa_pss_params *rsa_pss_params,
EVP_MD_CTX **md_ctx, EVP_PKEY_CTX **pkey_ctx,
bool debug);
int SK_OPENSSL_generate_csr(const unsigned char *secure_key,
size_t secure_key_size,
const char *subject_rdns[], size_t num_subject_rdns,
bool subject_utf8, const X509 *renew_cert,
const char *extensions[], size_t num_extensions,
int digest_nid,
struct sk_rsa_pss_params *rsa_pss_params,
X509_REQ **csr,
const struct sk_ext_lib *ext_lib, bool debug);
int SK_OPENSSL_generate_ss_cert(const unsigned char *secure_key,
size_t secure_key_size,
const char *subject_rdns[],
size_t num_subject_rdns, bool subject_utf8,
const X509 *renew_cert,
const char *extensions[], size_t num_extensions,
int validity_days, int digest_nid,
struct sk_rsa_pss_params *rsa_pss_params,
X509 **ss_cert,
const struct sk_ext_lib *ext_lib, bool debug);
/*
* Import secure keys as PKEY, or import clear public keys as PKEY
*/
typedef int (*sk_rsa_sign_t)(const unsigned char *key_blob,
size_t key_blob_length,
unsigned char *sig, size_t *siglen,
const unsigned char *tbs, size_t tbslen,
int padding_type, int md_nid,
void *private, bool debug);
typedef int (*sk_rsa_pss_sign_t)(const unsigned char *key_blob,
size_t key_blob_length, unsigned char *sig,
size_t *siglen, const unsigned char *tbs,
size_t tbslen, int md_nid, int mfgmd_nid,
int saltlen, void *private, bool debug);
typedef int (*sk_ecdsa_sign_t)(const unsigned char *key_blob,
size_t key_blob_length, unsigned char *sig,
size_t *siglen, const unsigned char *tbs,
size_t tbslen, int md_nid, void *private,
bool debug);
typedef int (*sk_rsa_decrypt_t)(const unsigned char *key_blob,
size_t key_blob_length,
unsigned char *to, size_t *tolen,
const unsigned char *from, size_t fromlen,
int padding_type, void *private, bool debug);
typedef int (*sk_rsa_decrypt_oaep_t)(const unsigned char *key_blob,
size_t key_blob_length,
unsigned char *to, size_t *tolen,
const unsigned char *from, size_t fromlen,
int oaep_md_nid, int mgfmd_nid,
unsigned char *label, int label_len,
void *private, bool debug);
struct sk_funcs {
sk_rsa_sign_t rsa_sign;
sk_rsa_pss_sign_t rsa_pss_sign;
sk_ecdsa_sign_t ecdsa_sign;
sk_rsa_decrypt_t rsa_decrypt;
sk_rsa_decrypt_oaep_t rsa_decrypt_oaep;
};
int SK_OPENSSL_get_pkey(const unsigned char *secure_key, size_t secure_key_size,
const struct sk_pub_key_info *pub_key, bool rsa_pss,
const struct sk_funcs *sk_funcs, const void *private,
EVP_PKEY **pkey, bool debug);
int SK_OPENSSL_get_curve_from_ec_pkey(EVP_PKEY *pkey);
#endif

View File

@@ -0,0 +1,89 @@
/*
* libseckey - Secure key library
*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef SK_UTILITIES_H
#define SK_UTILITIES_H
#include <stddef.h>
#include <stdbool.h>
#include <openssl/x509.h>
#include <openssl/obj_mac.h>
#include <openssl/evp.h>
#include "libseckey/sk_openssl.h"
void SK_UTIL_warnx(const char *func, const char *fmt, ...);
#define sk_debug(debug, fmt...) \
do { \
if (debug) \
SK_UTIL_warnx(__func__, fmt); \
} while (0)
/* EC curve information definitions and functions */
struct sk_ec_curve_info {
int curve_nid;
enum {
SK_EC_TYPE_PRIME = 0,
SK_EC_TYPE_BRAINPOOL = 1,
} type;
size_t prime_bits;
size_t prime_len;
const unsigned char *der; /* DER encoded OID */
size_t der_size;
};
const struct sk_ec_curve_info *SK_UTIL_ec_get_curve_info(int curve_nid);
int SK_UTIL_ec_get_prime_curve_by_prime_bits(size_t prime_bits);
int SK_UTIL_ec_get_brainpool_curve_by_prime_bits(size_t prime_bits);
int SK_UTIL_ec_calculate_y_coordinate(int nid, size_t prime_len,
const unsigned char *x, int y_bit,
unsigned char *y);
/* Digest information definitions and functions */
struct sk_digest_info {
int digest_nid;
size_t digest_size;
const char *cca_keyword;
const unsigned char *der; /* DER encoded SEQ of OID and OCT-STRING */
size_t der_size;
unsigned long pkcs11_mech;
unsigned long pkcs11_mgf;
unsigned char x9_31_md; /* X9.31 digest identifier */
};
const struct sk_digest_info *SK_UTIL_get_digest_info(int digest_nid);
/* Helper functions for certificate and CSR handling */
int SK_UTIL_build_subject_name(X509_NAME **name, const char *rdns[],
size_t num_rdns, bool utf8);
int SK_UTIL_build_certificate_extensions(X509 *cert, X509_REQ *req,
const char *exts[], size_t num_exts,
const STACK_OF(X509_EXTENSION)
*addl_exts);
int SK_UTIL_generate_x509_serial_number(X509 *cert, size_t sn_bit_size);
int SK_UTIL_build_ecdsa_signature(const unsigned char *raw_sig,
size_t raw_sig_len,
unsigned char *sig, size_t *sig_len);
/* Functions to read and write keys, certificates, requests, etc. */
int SK_UTIL_read_x509_certificate(const char *pem_filename, X509 **cert);
int SK_UTIL_write_x509_certificate(const char *pem_filename, X509 *cert);
int SK_UTIL_write_x509_request(const char *pem_filename, X509_REQ *req,
bool new_hdr);
int SK_UTIL_read_key_blob(const char *filename, unsigned char *key_blob,
size_t *key_blob_len);
int SK_UTIL_write_key_blob(const char *filename, unsigned char *key_blob,
size_t key_blob_len);
int SK_UTIL_read_public_key(const char *pem_filename, EVP_PKEY **pkey);
int SK_UTIL_write_public_key(const char *pem_filename, EVP_PKEY *pkey);
#endif

View File

@@ -91,6 +91,7 @@ int dasd_sys_ese(char *devnode)
rc = fgetc(fp) - '0';
fclose(fp);
free(path);
return (rc == 1) ? 1 : 0;
}
@@ -218,7 +219,8 @@ int dasd_get_host_access_count(char *device)
return 0;
path = util_path_sysfs("bus/ccw/devices/%s/host_access_count", busid);
util_file_read_l(&value, 10, path);
if (util_file_read_l(&value, 10, path))
value = 0;
free(path);
return value;

View File

@@ -21,17 +21,33 @@ else
INSTALL_TARGETS += skip-libekmfweb-openssl
endif
libs = $(rootdir)/libutil/libutil.a
libs = $(rootdir)/libseckey/libseckey.a
TMPFILE := $(shell mktemp)
detect-openssl-version.dep:
echo "#include <openssl/opensslv.h>" > detect-openssl-version.dep
echo "#include <openssl/evp.h>" >> detect-openssl-version.dep
echo "#if OPENSSL_VERSION_NUMBER < 0x10101000L" >> detect-openssl-version.dep
echo " #error openssl version 1.1.1 is required" >> detect-openssl-version.dep
echo "#endif" >> detect-openssl-version.dep
echo "static void __attribute__((unused)) test(void) {" >> detect-openssl-version.dep
echo " EVP_PKEY_meth_remove(NULL);" >> detect-openssl-version.dep
echo "}" >> detect-openssl-version.dep
echo "#include <openssl/opensslv.h>" > $(TMPFILE)
echo "#include <openssl/evp.h>" >> $(TMPFILE)
echo "#ifndef OPENSSL_VERSION_PREREQ" >> $(TMPFILE)
echo " #if defined(OPENSSL_VERSION_MAJOR) && defined(OPENSSL_VERSION_MINOR)" >> $(TMPFILE)
echo " #define OPENSSL_VERSION_PREREQ(maj, min) \\" >> $(TMPFILE)
echo " ((OPENSSL_VERSION_MAJOR << 16) + \\" >> $(TMPFILE)
echo " OPENSSL_VERSION_MINOR >= ((maj) << 16) + (min))" >> $(TMPFILE)
echo " #else" >> $(TMPFILE)
echo " #define OPENSSL_VERSION_PREREQ(maj, min) \\" >> $(TMPFILE)
echo " (OPENSSL_VERSION_NUMBER >= (((maj) << 28) | \\" >> $(TMPFILE)
echo " ((min) << 20)))" >> $(TMPFILE)
echo " #endif" >> $(TMPFILE)
echo "#endif" >> $(TMPFILE)
echo "#if !OPENSSL_VERSION_PREREQ(1, 1)" >> $(TMPFILE)
echo " #error openssl version 1.1 is required" >> $(TMPFILE)
echo "#endif" >> $(TMPFILE)
echo "static void __attribute__((unused)) test(void) {" >> $(TMPFILE)
echo " EVP_PKEY_meth_remove(NULL);" >> $(TMPFILE)
echo "}" >> $(TMPFILE)
mv $(TMPFILE) $@
CURL_CONFIG ?= curl-config
check-dep-libekmfweb: detect-openssl-version.dep
$(call check_dep, \
@@ -39,7 +55,7 @@ check-dep-libekmfweb: detect-openssl-version.dep
"detect-openssl-version.dep", \
"openssl-devel version >= 1.1.1", \
"HAVE_OPENSSL=0", \
-I. -lcrypto)
-I. -lcrypto -DOPENSSL_SUPPRESS_DEPRECATED)
$(call check_dep, \
"libekmfweb", \
"json-c/json.h", \
@@ -49,7 +65,9 @@ check-dep-libekmfweb: detect-openssl-version.dep
"libekmfweb", \
"curl/curl.h", \
"libcurl-devel", \
"HAVE_LIBCURL=0")
"HAVE_LIBCURL=0" \
`$(CURL_CONFIG) --cflags` `$(CURL_CONFIG) --libs`)
$(CURL_CONFIG) --ssl-backends | grep OpenSSL >/dev/null 2>&1 || { echo "Error: libcurl is not built with the OpenSSL backend"; exit 1; }
touch check-dep-libekmfweb
skip-libekmfweb-openssl:
@@ -67,11 +85,11 @@ ekmfweb.o: check-dep-libekmfweb ekmfweb.c utilities.h cca.h $(rootdir)include/ek
utilities.o: check-dep-libekmfweb utilities.c utilities.h $(rootdir)include/ekmfweb/ekmfweb.h
cca.o: check-dep-libekmfweb cca.c cca.h utilities.h $(rootdir)include/ekmfweb/ekmfweb.h
libekmfweb.so.$(VERSION): ALL_CFLAGS += -fPIC
libekmfweb.so.$(VERSION): LDLIBS = -ljson-c -lcrypto -lssl -lcurl -ldl
libekmfweb.so.$(VERSION): ALL_CFLAGS += -fPIC `$(CURL_CONFIG) --cflags`
libekmfweb.so.$(VERSION): LDLIBS = -ljson-c -lcrypto -lssl `$(CURL_CONFIG) --libs` -ldl
libekmfweb.so.$(VERSION): ALL_LDFLAGS += -shared -Wl,--version-script=libekmfweb.map \
-Wl,-z,defs,-Bsymbolic -Wl,-soname,libekmfweb.so.$(VERM)
libekmfweb.so.$(VERSION): ekmfweb.o utilities.o cca.o
libekmfweb.so.$(VERSION): ekmfweb.o utilities.o cca.o $(libs)
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
ln -srf libekmfweb.so.$(VERSION) libekmfweb.so.$(VERM)
ln -srf libekmfweb.so.$(VERSION) libekmfweb.so

File diff suppressed because it is too large Load Diff

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