mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Compare commits
163 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 18efac6306 | |||
| 18f8db2225 | |||
| f1a13749df | |||
| b5da337d1e | |||
| a67888f36a | |||
| e1f174ae22 | |||
| 7503d88b3b | |||
| 43039943cd | |||
| b2e02d202a | |||
| 1faa5d2957 | |||
| d62e075450 | |||
| 983233730c | |||
| ad024c06e1 | |||
| e2843232d5 | |||
| b79d17d233 | |||
| 11b401b599 | |||
| 69c5ee2e52 | |||
| 3ee625d74f | |||
| 832268ecb0 | |||
| 5fb6434548 | |||
| 5894e3f700 | |||
| e384f06014 | |||
| 1627c6a39f | |||
| bb8f17a7da | |||
| 8b3d3dd4bd | |||
| a5c04e5746 | |||
| c5ae1a41da | |||
| 970c697983 | |||
| cff4b0384f | |||
| 724f800dc5 | |||
| 4cdfe91ca9 | |||
| a44db0f367 | |||
| 03ddcd6267 | |||
| 5c468a220e | |||
| 4ba65eaa74 | |||
| 58cae4fecd | |||
| 9b84de4b0a | |||
| e679a88d88 | |||
| 6acf6ed76d | |||
| e7abf256f6 | |||
| 0d407904dd | |||
| 2238eb820f | |||
| 81013f0c70 | |||
| 697c5dc405 | |||
| e9deec4c62 | |||
| d60b7770fd | |||
| 70925f9aff | |||
| ef88fac874 | |||
| 4bd16ba8ea | |||
| f6a7da141c | |||
| 1bbd34e500 | |||
| c2f8988444 | |||
| d2990db15f | |||
| fd3d79335a | |||
| 07b3837e68 | |||
| 13a1227a02 | |||
| 52118a8d02 | |||
| ee89b850fe | |||
| 5160f41079 | |||
| 5b0115fdb4 | |||
| ae305b5158 | |||
| 04407d24fc | |||
| bcb8ea09d1 | |||
| 88619b6dba | |||
| e127b89624 | |||
| 3591b94c42 | |||
| 2a29a28f78 | |||
| cb831aea44 | |||
| 04be704083 | |||
| 1bcfcd3253 | |||
| 2dbaf9f991 | |||
| 2ea20094d0 | |||
| a80c14d72c | |||
| 10518da618 | |||
| e9d1e168b2 | |||
| 7567506cca | |||
| 524017ac06 | |||
| 15774dbe32 | |||
| f247850ff0 | |||
| 800ef7cb13 | |||
| 48cf3b3809 | |||
| 99c8c27302 | |||
| a5c3af1361 | |||
| 353c23a157 | |||
| d371ba0db8 | |||
| 8308143008 | |||
| d8871197ea | |||
| df338a3bac | |||
| 1005e7be7e | |||
| afb14cba7a | |||
| 1e450e6f7b | |||
| 696a007b62 | |||
| ea5f3f4a1c | |||
| 6afd5e97d1 | |||
| b1da8bbbe9 | |||
| 6ece595532 | |||
| 40d4aa38e9 | |||
| c58cfd1ec1 | |||
| 02086f26d2 | |||
| 7a2666d727 | |||
| 2df532c1fa | |||
| 969a439aaa | |||
| f8331a4b8e | |||
| 895dc80580 | |||
| d93645d690 | |||
| c3bb6307b8 | |||
| 6208c0626a | |||
| 3949c62f6f | |||
| 8c6c2ef30e | |||
| 12c84469fd | |||
| 0a8e726d05 | |||
| 533df585fd | |||
| c4eb2d5fba | |||
| 35029ad010 | |||
| 296079f70a | |||
| 4f1c73d592 | |||
| 1fb859729e | |||
| bbeb0f8445 | |||
| 2ae44cb794 | |||
| a0b8033088 | |||
| 9cc74839b0 | |||
| b7b7002855 | |||
| 55e428a4d7 | |||
| cb09223a56 | |||
| 28db3523d0 | |||
| f15e32cdb1 | |||
| 094057e265 | |||
| 025a2198a4 | |||
| 2b938b78aa | |||
| de36fc5259 | |||
| e3e5b6422a | |||
| 38343be0fa | |||
| 957e612720 | |||
| 1d2316caef | |||
| 64539853ca | |||
| 686c331b69 | |||
| 01551f98d5 | |||
| 0e2c5907e0 | |||
| 68ff79e4c3 | |||
| 5b96d86538 | |||
| 4043137cd7 | |||
| 735d8f5493 | |||
| 28efa7d120 | |||
| ebde75eeda | |||
| a645ec0fc0 | |||
| 761a185938 | |||
| 890b15d158 | |||
| 07677668a3 | |||
| fde914fd1c | |||
| 35c97a07aa | |||
| 45e3f016f4 | |||
| 38b520ab4c | |||
| 3b6920271e | |||
| a3146409da | |||
| 76aa8e4a52 | |||
| f5e6f4a8cb | |||
| 80cb1553a3 | |||
| 706f59b9d9 | |||
| 02cc902b90 | |||
| ff2fb42868 | |||
| 451bf7fbc6 | |||
| d2a4a8b0f3 | |||
| fe5753d34d |
@@ -0,0 +1,13 @@
|
|||||||
|
# Check https://editorconfig.org for details
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = tab
|
||||||
|
tab_width = 8
|
||||||
|
|
||||||
|
[*.sh]
|
||||||
|
shell_variant = bash # used by `shfmt`
|
||||||
@@ -9,6 +9,10 @@
|
|||||||
tags
|
tags
|
||||||
TAGS
|
TAGS
|
||||||
|
|
||||||
|
# Ignore coverage data
|
||||||
|
*.gcda
|
||||||
|
*.gcno
|
||||||
|
|
||||||
#
|
#
|
||||||
# Ignore generated executables and other generated files
|
# Ignore generated executables and other generated files
|
||||||
#
|
#
|
||||||
@@ -25,6 +29,7 @@ dasdview/dasdview
|
|||||||
dump2tar/src/dump2tar
|
dump2tar/src/dump2tar
|
||||||
fdasd/fdasd
|
fdasd/fdasd
|
||||||
hmcdrvfs/hmcdrvfs
|
hmcdrvfs/hmcdrvfs
|
||||||
|
hsavmcore/check-dep-fuse
|
||||||
hsavmcore/hsavmcore
|
hsavmcore/hsavmcore
|
||||||
hyptop/hyptop
|
hyptop/hyptop
|
||||||
ip_watcher/xcec-bridge
|
ip_watcher/xcec-bridge
|
||||||
@@ -98,7 +103,9 @@ zipl/boot/*.bin
|
|||||||
zipl/boot/*.exec
|
zipl/boot/*.exec
|
||||||
zipl/boot/data.h
|
zipl/boot/data.h
|
||||||
zipl/src/chreipl_helper.device-mapper
|
zipl/src/chreipl_helper.device-mapper
|
||||||
|
zdev/src/zdev_id
|
||||||
zipl/src/zipl
|
zipl/src/zipl
|
||||||
|
zipl/src/zipl-editenv
|
||||||
zipl/src/zipl_helper.device-mapper
|
zipl/src/zipl_helper.device-mapper
|
||||||
zkey/check-dep-zkey
|
zkey/check-dep-zkey
|
||||||
zkey/check-dep-zkey-cryptsetup
|
zkey/check-dep-zkey-cryptsetup
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ List of all individuals having contributed content to s390-tools
|
|||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
||||||
- Alexander Egorenkov
|
- Alexander Egorenkov
|
||||||
|
- Alexandra Winter
|
||||||
- Alexey Ishchuk
|
- Alexey Ishchuk
|
||||||
- Andreas Herrmann
|
- Andreas Herrmann
|
||||||
- Andre Wild
|
- Andre Wild
|
||||||
@@ -37,6 +38,7 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Fritz Elfert
|
- Fritz Elfert
|
||||||
- Gerald Schaefer
|
- Gerald Schaefer
|
||||||
- Gerhard Tonn
|
- Gerhard Tonn
|
||||||
|
- Graham Inggs
|
||||||
- Guevenc Guelce
|
- Guevenc Guelce
|
||||||
- Hannes Reinecke
|
- Hannes Reinecke
|
||||||
- Hans-Joachim Picht
|
- Hans-Joachim Picht
|
||||||
@@ -73,6 +75,7 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Martin Peschke
|
- Martin Peschke
|
||||||
- Martin Petermann
|
- Martin Petermann
|
||||||
- Martin Schwidefsky
|
- Martin Schwidefsky
|
||||||
|
- Matthew Rosato
|
||||||
- Maxim Shchetynin
|
- Maxim Shchetynin
|
||||||
- Melissa Howland
|
- Melissa Howland
|
||||||
- Michael Ernst
|
- Michael Ernst
|
||||||
@@ -102,6 +105,7 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Stefan Raspl
|
- Stefan Raspl
|
||||||
- Stefan Reimbold
|
- Stefan Reimbold
|
||||||
- Stefan Weinhuber
|
- Stefan Weinhuber
|
||||||
|
- Steffen Eiden
|
||||||
- Steffen Maier
|
- Steffen Maier
|
||||||
- Steffen Thoss
|
- Steffen Thoss
|
||||||
- Susanne Wintenberger
|
- Susanne Wintenberger
|
||||||
@@ -110,6 +114,7 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Swen Schillig
|
- Swen Schillig
|
||||||
- Taraka R. Bodireddy
|
- Taraka R. Bodireddy
|
||||||
- Thomas Heidrich
|
- Thomas Heidrich
|
||||||
|
- Thomas Huth
|
||||||
- Thomas Richter
|
- Thomas Richter
|
||||||
- Thomas Spatzier
|
- Thomas Spatzier
|
||||||
- Thomas Weber
|
- Thomas Weber
|
||||||
|
|||||||
@@ -1,5 +1,76 @@
|
|||||||
Release history for s390-tools (MIT version)
|
Release history for s390-tools (MIT version)
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
|
* __v2.20.0 (2021-02-04)__
|
||||||
|
|
||||||
|
For Linux kernel version: 5.16
|
||||||
|
|
||||||
|
Add new tools / libraries:
|
||||||
|
- Add EditorConfig configuration
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- s390-tools switches to Fuse 3 as Fuse 2 is deprecated.
|
||||||
|
Affected tools: cmsfs, hmcdrvfs, hsavmcore, zdsfs, zdump
|
||||||
|
- chreipl-fcp-mpath: don't compress the manpage before installing it
|
||||||
|
- cpictl: Report extended version information
|
||||||
|
- genprotimg: Add extended kernel command line support
|
||||||
|
- zdev: modify the lsblk output parser in lszdev
|
||||||
|
- zipl: Add support for longer kernel command lines (now supports up to 64k length)
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- cpictl: Suppress messages for unwritable sysfs files
|
||||||
|
- dbginfo.sh: Fix missing syslog for step create_package
|
||||||
|
- lshwc: Fix CPU list parameter setup for device driver
|
||||||
|
- zdev: Check for errors when removing a devtype setting
|
||||||
|
- zdev: Fix path resolution for multi-mount point file systems
|
||||||
|
|
||||||
|
* __v2.19.0 (2021-11-10)__
|
||||||
|
|
||||||
|
For Linux kernel version: 5.15
|
||||||
|
|
||||||
|
Add new tools / libraries:
|
||||||
|
- chreipl-fcp-mpath: New toolset that uses multipath information to change
|
||||||
|
the configured FCP re-IPL path on detecting issues with the current path
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- dbginfo.sh: Add retry timeout and remove possible blocking "blockdev --report"
|
||||||
|
- dbginfo.sh: Collect config- and debug-data for chreipl-fcp-mpath
|
||||||
|
- hsci: Add support for multiple MAC addresses
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- lshwc: Fix compile error for gcc <8.1
|
||||||
|
- zdump: Various clean-ups and fixes
|
||||||
|
- ziomon: Correct throughput calculation in ziorep_printers
|
||||||
|
- zipl: Fix segmentation fault when setting stage3_parms
|
||||||
|
|
||||||
|
* __v2.18.0 (2021-10-01)__
|
||||||
|
|
||||||
|
For Linux kernel version: 5.14
|
||||||
|
|
||||||
|
Add new tools:
|
||||||
|
- scripts: Add tool for parsing sclp s390dbf logs
|
||||||
|
- zdev: Add udev rule helper tool
|
||||||
|
- zipl-editenv: Add tool to operate with zIPL environment installed in the boot record
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- Makefile: Fix order of build of libraries for parallel builds
|
||||||
|
- dbginfo.sh: Add collection in area of timedate, coredump and --check option
|
||||||
|
- dbginfo.sh: Add exception on dump2tar for /sys/kernel/mm/page_idle/bitmap
|
||||||
|
- dbginfo.sh: Cleanup of outdated sections and general code rework
|
||||||
|
- dbginfo.sh: Collect zipl boot menu entries from boot loader specification
|
||||||
|
- lszcrypt: Add support for vfio-ap status field
|
||||||
|
- lszcrypt: Improved output for deconfig cards and queues
|
||||||
|
- lszfcp: Add linkdown case to host marker of extended output
|
||||||
|
- zdev: Add auto-config for PCI and crypto devices
|
||||||
|
- zdump: Introduce multi-level message logging
|
||||||
|
- zipl: Add support for environment block interpretation
|
||||||
|
- zkey-cryptsetup: Support LUKS2 volumes with integrity support enabled
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- hsavmcore: Avoid recompilation of overlay during install step
|
||||||
|
- libkmipclient: Fix parsing of hex values for XML and JSON encoding
|
||||||
|
- vmur/vmur.cpp: Fix error handling on transfer failure
|
||||||
|
- zdump: Lots of smaller fixes across the board
|
||||||
|
|
||||||
* __v2.17.0 (2021-07-07)__
|
* __v2.17.0 (2021-07-07)__
|
||||||
|
|
||||||
For Linux kernel version: 5.12 / 5.13
|
For Linux kernel version: 5.12 / 5.13
|
||||||
|
|||||||
@@ -3,16 +3,22 @@ ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/ar
|
|||||||
# Include common definitions
|
# Include common definitions
|
||||||
include common.mak
|
include common.mak
|
||||||
|
|
||||||
LIB_DIRS = libvtoc libutil libzds libdasd libvmdump libccw libvmcp libekmfweb \
|
#
|
||||||
libseckey libkmipclient
|
# BASELIBS: Libraries that have no dependency to other libraries in s390-tools
|
||||||
|
# LIBS: Libraries that can have a dependency to base libraries
|
||||||
|
# TOOLS: Tools that can have a dependency to base libraries or libraries
|
||||||
|
#
|
||||||
|
BASELIB_DIRS = libutil libseckey
|
||||||
|
LIB_DIRS = libvtoc libzds libdasd libvmdump libccw libvmcp libekmfweb \
|
||||||
|
libkmipclient
|
||||||
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
|
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
|
||||||
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
|
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
|
||||||
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
|
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
|
||||||
ziomon iucvterm hyptop cmsfs-fuse qethqoat zfcpdump zdsfs cpumf \
|
ziomon iucvterm hyptop cmsfs-fuse qethqoat zfcpdump zdsfs cpumf \
|
||||||
systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc zpcictl \
|
systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc zpcictl \
|
||||||
genprotimg lsstp hsci hsavmcore
|
genprotimg lsstp hsci hsavmcore chreipl-fcp-mpath
|
||||||
|
|
||||||
SUB_DIRS = $(LIB_DIRS) $(TOOL_DIRS)
|
SUB_DIRS = $(BASELIB_DIRS) $(LIB_DIRS) $(TOOL_DIRS)
|
||||||
|
|
||||||
all: $(TOOL_DIRS)
|
all: $(TOOL_DIRS)
|
||||||
clean: $(TOOL_DIRS)
|
clean: $(TOOL_DIRS)
|
||||||
@@ -26,9 +32,10 @@ MAKECMDGOALS = all
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
#
|
#
|
||||||
# We have to build the libraries before the tools are built. Otherwise
|
# We have to build the base libraries before the other libraries are built,
|
||||||
# the tools would trigger parallel "make -C" builds for libraries in
|
# and then build the other libraries before the tools are built. Otherwise the
|
||||||
# case of "make -j".
|
# 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
|
# MAKECMDGOALS contains the list of goals, e.g. "clean all". We use
|
||||||
# "foreach" to generate a ";" separated list of "make -C <target>".
|
# "foreach" to generate a ";" separated list of "make -C <target>".
|
||||||
@@ -45,7 +52,12 @@ $(TOOL_DIRS): $(LIB_DIRS)
|
|||||||
$(MAKE) -C $@ TOPDIR=$(TOPDIR) ARCH=$(ARCH) $(goal) ;)
|
$(MAKE) -C $@ TOPDIR=$(TOPDIR) ARCH=$(ARCH) $(goal) ;)
|
||||||
.PHONY: $(TOOL_DIRS)
|
.PHONY: $(TOOL_DIRS)
|
||||||
|
|
||||||
$(LIB_DIRS):
|
$(LIB_DIRS): $(BASELIB_DIRS)
|
||||||
$(foreach goal,$(MAKECMDGOALS), \
|
$(foreach goal,$(MAKECMDGOALS), \
|
||||||
$(MAKE) -C $@ TOPDIR=$(TOPDIR) ARCH=$(ARCH) $(goal) ;)
|
$(MAKE) -C $@ TOPDIR=$(TOPDIR) ARCH=$(ARCH) $(goal) ;)
|
||||||
.PHONY: $(LIB_DIRS)
|
.PHONY: $(LIB_DIRS)
|
||||||
|
|
||||||
|
$(BASELIB_DIRS):
|
||||||
|
$(foreach goal,$(MAKECMDGOALS), \
|
||||||
|
$(MAKE) -C $@ TOPDIR=$(TOPDIR) ARCH=$(ARCH) $(goal) ;)
|
||||||
|
.PHONY: $(BASELIB_DIRS)
|
||||||
|
|||||||
@@ -109,6 +109,9 @@ Package contents
|
|||||||
feature. Those traces are filtered with the zfcpdbf script, i.e. merge
|
feature. Those traces are filtered with the zfcpdbf script, i.e. merge
|
||||||
several traces, make it more readable etc.
|
several traces, make it more readable etc.
|
||||||
|
|
||||||
|
* sclpdbf:
|
||||||
|
Display debug data for the sclp kernel component.
|
||||||
|
|
||||||
* scsi_logging_level:
|
* scsi_logging_level:
|
||||||
Create, get or set the logging level for the SCSI logging facility.
|
Create, get or set the logging level for the SCSI logging facility.
|
||||||
|
|
||||||
@@ -267,6 +270,10 @@ Package contents
|
|||||||
can be time consuming and prevent the HSA memory from being reused
|
can be time consuming and prevent the HSA memory from being reused
|
||||||
by other LPARs.
|
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:
|
For more information refer to the following publications:
|
||||||
|
|
||||||
* "Device Drivers, Features, and Commands" chapter "Useful Linux commands"
|
* "Device Drivers, Features, and Commands" chapter "Useful Linux commands"
|
||||||
@@ -285,7 +292,7 @@ build options:
|
|||||||
|
|
||||||
| __LIBRARY__ | __BUILD OPTION__ | __TOOLS__ |
|
| __LIBRARY__ | __BUILD OPTION__ | __TOOLS__ |
|
||||||
|----------------|:------------------:|:-------------------------------------:|
|
|----------------|:------------------:|:-------------------------------------:|
|
||||||
| fuse | `HAVE_FUSE` | cmsfs-fuse, zdsfs, hmcdrvfs, zgetdump,|
|
| fuse3 | `HAVE_FUSE` | cmsfs-fuse, zdsfs, hmcdrvfs, zgetdump,|
|
||||||
| | | hsavmcore |
|
| | | hsavmcore |
|
||||||
| zlib | `HAVE_ZLIB` | zgetdump, dump2tar |
|
| zlib | `HAVE_ZLIB` | zgetdump, dump2tar |
|
||||||
| ncurses | `HAVE_NCURSES` | hyptop |
|
| ncurses | `HAVE_NCURSES` | hyptop |
|
||||||
@@ -304,11 +311,11 @@ build options:
|
|||||||
|
|
||||||
This table lists additional build or install options:
|
This table lists additional build or install options:
|
||||||
|
|
||||||
| __COMPONENT__ | __OPTION__ | __TOOLS__ |
|
| __COMPONENT__ | __OPTION__ | __TOOLS__ |
|
||||||
|------------------|:----------------------------:|:--------------:|
|
|------------------|:----------------------------:|:-----------------------:|
|
||||||
| dracut | `HAVE_DRACUT` | zdev |
|
| dracut | `HAVE_DRACUT` | zdev, chreipl-fcp-mpath |
|
||||||
| initramfs-tools | `HAVE_INITRAMFS` | zdev |
|
| initramfs-tools | `HAVE_INITRAMFS` | zdev |
|
||||||
| | `ZDEV_ALWAYS_UPDATE_INITRD` | zdev |
|
| | `ZDEV_ALWAYS_UPDATE_INITRD` | zdev |
|
||||||
|
|
||||||
The s390-tools build process uses "pkg-config" if available and hard-coded
|
The s390-tools build process uses "pkg-config" if available and hard-coded
|
||||||
compiler and linker options otherwise.
|
compiler and linker options otherwise.
|
||||||
@@ -348,12 +355,12 @@ the different tools are provided:
|
|||||||
|
|
||||||
* cmsfs-fuse/zdsfs/hmcdrvfs/zgetdump:
|
* cmsfs-fuse/zdsfs/hmcdrvfs/zgetdump:
|
||||||
The tools cmsfs-fuse, zdsfs, hmcdrvfs, and zgetdump depend on FUSE.
|
The tools cmsfs-fuse, zdsfs, hmcdrvfs, and zgetdump depend on FUSE.
|
||||||
FUSE is provided by installing the fuse and libfuse packages and by a
|
FUSE is provided by installing the fuse3 and libfuse3 packages and by a
|
||||||
kernel compiled with `CONFIG_FUSE_FS`. For compiling the s390-tools package
|
kernel compiled with `CONFIG_FUSE_FS`. For compiling the s390-tools package
|
||||||
the fuse-devel package is required.
|
the fuse3-devel package is required.
|
||||||
The cmsfs-fuse tool requires FUSE version 2.8.1 or newer for full
|
The cmsfs-fuse tool requires FUSE version 3.0 or newer for full
|
||||||
functionality.
|
functionality.
|
||||||
For further information about FUSE see: http://fuse.sourceforge.net
|
For further information about FUSE see: https://github.com/libfuse/libfuse
|
||||||
|
|
||||||
* hyptop:
|
* hyptop:
|
||||||
The ncurses-devel package is required to build hyptop.
|
The ncurses-devel package is required to build hyptop.
|
||||||
@@ -449,7 +456,7 @@ the different tools are provided:
|
|||||||
`HAVE_JSONC=0`, or `HAVE_LIBCURL=0` to the make invocation.
|
`HAVE_JSONC=0`, or `HAVE_LIBCURL=0` to the make invocation.
|
||||||
|
|
||||||
* hsavmcore:
|
* hsavmcore:
|
||||||
For building the hsavmcore tool you need fuse version 2.6 and optionally
|
For building the hsavmcore tool you need fuse version 3.0 and optionally
|
||||||
systemd which is enabled by default, to disable systemd support,
|
systemd which is enabled by default, to disable systemd support,
|
||||||
add `HAVE_SYSTEMD=0` to the make invocation.
|
add `HAVE_SYSTEMD=0` to the make invocation.
|
||||||
Tip: you may skip the hsavmcore build by adding `HAVE_FUSE=0`
|
Tip: you may skip the hsavmcore build by adding `HAVE_FUSE=0`
|
||||||
@@ -462,3 +469,14 @@ the different tools are provided:
|
|||||||
(libxml2-devel.rpm), and libcurl version 7.59 or newer (libcurl-devel.rpm).
|
(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`,
|
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.
|
`HAVE_JSONC=0`, `HAVE_LIBXML2=0`, or `HAVE_LIBCURL=0` to the make invocation.
|
||||||
|
|
||||||
|
* chreipl-fcp-mpath:
|
||||||
|
For a complete list and documentation of the requirements, installation and
|
||||||
|
uninstallation, please see
|
||||||
|
[chreipl-fcp-mpath/README.md](chreipl-fcp-mpath/README.md).
|
||||||
|
|
||||||
|
Summarized: chreipl-fcp-mpath requires GNU Bash, GNU Core Utilities,
|
||||||
|
util-linux, udev, and multipath-tools. When using `HAVE_DRACUT=1` with the
|
||||||
|
make invocation, it also requires dracut. When using `ENABLE_DOC=1` with the
|
||||||
|
make invocation to build a man page and render the README.md as HTML, make
|
||||||
|
further requires pandoc and GNU awk for the build process.
|
||||||
|
|||||||
+2
-2
@@ -32,7 +32,7 @@ Usage: $cmd [-t LAST_GIT_TAG]
|
|||||||
Add all new authors since last release to the $authors_file file. Without
|
Add all new authors since last release to the $authors_file file. Without
|
||||||
the -t option the tool uses the last available git tag as last release.
|
the -t option the tool uses the last available git tag as last release.
|
||||||
|
|
||||||
The tool should be called form the s390-tools master branch.
|
The tool runs on the s390-tools master branch.
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-t, --tag LAST_GIT_TAG Use git tag LAST_GIT_TAG as starting point
|
-t, --tag LAST_GIT_TAG Use git tag LAST_GIT_TAG as starting point
|
||||||
@@ -116,7 +116,7 @@ echo "$cmd: Adding new authors since tag: $release_tag_last"
|
|||||||
# Print authors list without header
|
# Print authors list without header
|
||||||
tail -n +4 $authors_file_path
|
tail -n +4 $authors_file_path
|
||||||
# Add the new authors
|
# Add the new authors
|
||||||
git log --format="- %an" $release_tag_last..
|
git log --format="- %an" $release_tag_last..master
|
||||||
# Then sort everything and remove duplicates
|
# Then sort everything and remove duplicates
|
||||||
} | sort | uniq > $authors_file_tmp
|
} | sort | uniq > $authors_file_tmp
|
||||||
# Create new AUTHORS file with header ...
|
# Create new AUTHORS file with header ...
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# build artifacts
|
||||||
|
/chreipl-fcp-mpath-common.sh
|
||||||
|
/chreipl-fcp-mpath-is-ipl-tgt
|
||||||
|
/chreipl-fcp-mpath-is-ipl-vol
|
||||||
|
/chreipl-fcp-mpath-is-reipl-zfcp
|
||||||
|
/chreipl-fcp-mpath-record-volume-identifier
|
||||||
|
/chreipl-fcp-mpath-try-change-ipl-path
|
||||||
|
/dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf
|
||||||
|
/README.html
|
||||||
|
/README.pdf
|
||||||
|
/chreipl-fcp-mpath.md
|
||||||
|
/chreipl-fcp-mpath.7
|
||||||
@@ -0,0 +1,255 @@
|
|||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
#
|
||||||
|
# chreipl-fcp-mpath: use multipath information to change FCP IPL target
|
||||||
|
# (C) Copyright IBM Corp. 2021
|
||||||
|
#
|
||||||
|
# Uses the following system-utilities (and shell-builtins):
|
||||||
|
# Utilities list in GNU Make Conventions:
|
||||||
|
# https://www.gnu.org/software/make/manual/make.html#Utilities-in-Makefiles
|
||||||
|
# Those necessary for sourced Makefiles:
|
||||||
|
# - ../common.mak
|
||||||
|
# - chreipl-fcp-mpath.mak
|
||||||
|
# bash:
|
||||||
|
# - bash
|
||||||
|
# If $(ENABLE_DOC) is `1`:
|
||||||
|
# GNU awk:
|
||||||
|
# - gawk
|
||||||
|
|
||||||
|
override SHELL := /bin/bash
|
||||||
|
override .SHELLFLAGS := -O globstar -O nullglob -O extglob -c
|
||||||
|
|
||||||
|
# Include common s390-tools definitions
|
||||||
|
include ../common.mak
|
||||||
|
|
||||||
|
# Include common chreipl-fcp-mpath definitions
|
||||||
|
include chreipl-fcp-mpath.mak
|
||||||
|
|
||||||
|
# Local setting: .make.config
|
||||||
|
# You may create a file named like this in the same directory as this
|
||||||
|
# Makefile, and customize the build this way (e.g. re-define variables
|
||||||
|
# set in `chreipl-fcp-mpath.mak`, or define a `CHREIPLZFCPMP_POST_INSTALL`
|
||||||
|
# that is automatically called after each installation)
|
||||||
|
ifneq ($(wildcard .make.config),)
|
||||||
|
include $(wildcard .make.config)
|
||||||
|
endif
|
||||||
|
|
||||||
|
#
|
||||||
|
## Build
|
||||||
|
#
|
||||||
|
|
||||||
|
.PHONY: chreipl-fcp-mpath chreipl-fcp-mpath-clean
|
||||||
|
chreipl-fcp-mpath:
|
||||||
|
chreipl-fcp-mpath-clean:
|
||||||
|
all: chreipl-fcp-mpath
|
||||||
|
clean: chreipl-fcp-mpath-clean
|
||||||
|
|
||||||
|
# common function used in the helper scripts
|
||||||
|
CHREIPL_FCP_MPATH_COMMON := \
|
||||||
|
chreipl-fcp-mpath-common.sh
|
||||||
|
CHREIPL_FCP_MPATH_UDEV_HELPER := \
|
||||||
|
chreipl-fcp-mpath-is-ipl-tgt \
|
||||||
|
chreipl-fcp-mpath-is-ipl-vol \
|
||||||
|
chreipl-fcp-mpath-is-reipl-zfcp \
|
||||||
|
chreipl-fcp-mpath-record-volume-identifier \
|
||||||
|
chreipl-fcp-mpath-try-change-ipl-path
|
||||||
|
|
||||||
|
$(CHREIPL_FCP_MPATH_UDEV_HELPER) $(CHREIPL_FCP_MPATH_COMMON): $(MAKEFILE_LIST)
|
||||||
|
$(CHREIPL_FCP_MPATH_UDEV_HELPER) $(CHREIPL_FCP_MPATH_COMMON): % : %.in
|
||||||
|
$(call chreiplzfcpmp-sed-buildvar-replace,$(<),$(@))
|
||||||
|
chmod a+x $(@)
|
||||||
|
|
||||||
|
$(CHREIPL_FCP_MPATH_UDEV_HELPER): $(CHREIPL_FCP_MPATH_COMMON)
|
||||||
|
|
||||||
|
.PHONY: chreipl-fcp-mpath-udev-helper-clean
|
||||||
|
chreipl-fcp-mpath-udev-helper-clean:
|
||||||
|
rm -f $(CHREIPL_FCP_MPATH_UDEV_HELPER) $(CHREIPL_FCP_MPATH_COMMON)
|
||||||
|
|
||||||
|
udev/rules.d/70-chreipl-fcp-mpath.rules: $(CHREIPL_FCP_MPATH_UDEV_HELPER)
|
||||||
|
|
||||||
|
chreipl-fcp-mpath: udev/rules.d/70-chreipl-fcp-mpath.rules
|
||||||
|
chreipl-fcp-mpath-clean: chreipl-fcp-mpath-udev-helper-clean
|
||||||
|
|
||||||
|
dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf: $(MAKEFILE_LIST)
|
||||||
|
dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf: % : %.in
|
||||||
|
$(call chreiplzfcpmp-sed-buildvar-replace,$(<),$(@))
|
||||||
|
|
||||||
|
.PHONY: chreipl-fcp-mpath-dracut-clean
|
||||||
|
chreipl-fcp-mpath-dracut-clean:
|
||||||
|
rm -f dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf
|
||||||
|
|
||||||
|
chreipl-fcp-mpath: dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf
|
||||||
|
chreipl-fcp-mpath-clean: chreipl-fcp-mpath-dracut-clean
|
||||||
|
|
||||||
|
ifeq ($(ENABLE_DOC),1)
|
||||||
|
|
||||||
|
.PHONY: chreipl-fcp-mpath-doc
|
||||||
|
chreipl-fcp-mpath-doc: README.html chreipl-fcp-mpath.7
|
||||||
|
|
||||||
|
ifeq ($(ENABLE_DOC_PDF),1)
|
||||||
|
chreipl-fcp-mpath-doc: README.pdf
|
||||||
|
|
||||||
|
README.pdf: PANDOCFLAGS += -M title="chreipl-fcp-mpath" -M subtitle="README"
|
||||||
|
endif
|
||||||
|
|
||||||
|
README.html: PANDOCFLAGS += -M title="chreipl-fcp-mpath" -M subtitle="README"
|
||||||
|
|
||||||
|
chreiplzfcpmp-doc-man-meta = \
|
||||||
|
-M title="CHREIPL-FCP-MPATH" \
|
||||||
|
-V header="Administrator Manual" \
|
||||||
|
-V section="7" \
|
||||||
|
-V footer="s390-tools $(S390_TOOLS_RELEASE)"
|
||||||
|
|
||||||
|
chreipl-fcp-mpath.7: PANDOCFLAGS += $(chreiplzfcpmp-doc-man-meta)
|
||||||
|
|
||||||
|
.INTERMEDIATE: chreipl-fcp-mpath.md
|
||||||
|
chreipl-fcp-mpath.md: README.md
|
||||||
|
gawk -- '/NOT-IN-MAN \{/,/NOT-IN-MAN \}/ { next } { print }' $(<) > $(@)
|
||||||
|
|
||||||
|
.PHONY: chreipl-fcp-mpath-doc-clean
|
||||||
|
chreipl-fcp-mpath-doc-clean:
|
||||||
|
rm -f README.html README.pdf chreipl-fcp-mpath.md chreipl-fcp-mpath.7
|
||||||
|
|
||||||
|
chreipl-fcp-mpath: chreipl-fcp-mpath-doc
|
||||||
|
chreipl-fcp-mpath-clean: chreipl-fcp-mpath-doc-clean
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
#
|
||||||
|
## Install
|
||||||
|
#
|
||||||
|
|
||||||
|
.PHONY: chreipl-fcp-mpath-install
|
||||||
|
# The content of `CHREIPLZFCPMP_POST_INSTALL` (bash script) is automatically
|
||||||
|
# called *after* installing chreipl-fcp-mpath during `make install`. If not
|
||||||
|
# defined (the default), nothing happens. You may define this on the make
|
||||||
|
# command line, or by creating a `.make.config` and defining the variable in
|
||||||
|
# there.
|
||||||
|
chreipl-fcp-mpath-install:
|
||||||
|
$(CHREIPLZFCPMP_POST_INSTALL)
|
||||||
|
|
||||||
|
install: chreipl-fcp-mpath-install
|
||||||
|
|
||||||
|
# install udev rules
|
||||||
|
INSTDIRS += $(UDEVRULESDIR)
|
||||||
|
$(DESTDIR)$(UDEVRULESDIR): install_dirs
|
||||||
|
|
||||||
|
.PHONY: chreipl-fcp-mpath-install-udev-rules
|
||||||
|
chreipl-fcp-mpath-install-udev-rules: | $(DESTDIR)$(UDEVRULESDIR)
|
||||||
|
chreipl-fcp-mpath-install-udev-rules: udev/rules.d/70-chreipl-fcp-mpath.rules
|
||||||
|
$(INSTALL_DATA) -t $(DESTDIR)$(UDEVRULESDIR) \
|
||||||
|
udev/rules.d/70-chreipl-fcp-mpath.rules
|
||||||
|
|
||||||
|
chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-udev-rules
|
||||||
|
|
||||||
|
# install udev helper programs
|
||||||
|
INSTDIRS += $(UDEVDIR)
|
||||||
|
$(DESTDIR)$(UDEVDIR): install_dirs
|
||||||
|
|
||||||
|
.PHONY: chreipl-fcp-mpath-install-udev-helper
|
||||||
|
chreipl-fcp-mpath-install-udev-helper: | $(DESTDIR)$(UDEVDIR)
|
||||||
|
chreipl-fcp-mpath-install-udev-helper: $(CHREIPL_FCP_MPATH_UDEV_HELPER)
|
||||||
|
$(INSTALL_EXEC) -t $(DESTDIR)$(UDEVDIR) $(CHREIPL_FCP_MPATH_UDEV_HELPER)
|
||||||
|
|
||||||
|
chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-udev-helper
|
||||||
|
|
||||||
|
# install common library files
|
||||||
|
INSTDIRS += $(CHREIPLZFCPMPDIR)
|
||||||
|
$(DESTDIR)$(CHREIPLZFCPMPDIR): install_dirs
|
||||||
|
|
||||||
|
.PHONY: chreipl-fcp-mpath-install-libfiles
|
||||||
|
chreipl-fcp-mpath-install-libfiles: | $(DESTDIR)$(CHREIPLZFCPMPDIR)
|
||||||
|
chreipl-fcp-mpath-install-libfiles: $(CHREIPL_FCP_MPATH_COMMON)
|
||||||
|
$(INSTALL_DATA) -t $(DESTDIR)$(CHREIPLZFCPMPDIR) \
|
||||||
|
$(CHREIPL_FCP_MPATH_COMMON)
|
||||||
|
|
||||||
|
chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-libfiles
|
||||||
|
|
||||||
|
ifeq ($(HAVE_DRACUT),1)
|
||||||
|
|
||||||
|
# install dracut config files
|
||||||
|
INSTDIRS += $(DRACUTCONFDIR)
|
||||||
|
$(DESTDIR)$(DRACUTCONFDIR): install_dirs
|
||||||
|
|
||||||
|
.PHONY: chreipl-fcp-mpath-install-dracut-config
|
||||||
|
chreipl-fcp-mpath-install-dracut-config: | $(DESTDIR)$(DRACUTCONFDIR)
|
||||||
|
chreipl-fcp-mpath-install-dracut-config: dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf
|
||||||
|
$(INSTALL_DATA) -t $(DESTDIR)$(DRACUTCONFDIR) \
|
||||||
|
dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf
|
||||||
|
|
||||||
|
chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-dracut-config
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(ENABLE_DOC),1)
|
||||||
|
|
||||||
|
# chreipl-fcp-mpath: install man page
|
||||||
|
INSTDIRS += $(MANDIR)
|
||||||
|
$(DESTDIR)$(MANDIR)/man7: install_dirs
|
||||||
|
|
||||||
|
.PHONY: chreipl-fcp-mpath-install-man-page
|
||||||
|
chreipl-fcp-mpath-install-man-page: | $(DESTDIR)$(MANDIR)/man7
|
||||||
|
chreipl-fcp-mpath-install-man-page: chreipl-fcp-mpath.7
|
||||||
|
$(INSTALL_DATA) -t $(DESTDIR)$(MANDIR)/man7 \
|
||||||
|
chreipl-fcp-mpath.7
|
||||||
|
|
||||||
|
chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-man-page
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
#
|
||||||
|
## Utility
|
||||||
|
#
|
||||||
|
|
||||||
|
# Utilities for the debug feature of chreipl-fcp-mpath-common.sh.
|
||||||
|
#
|
||||||
|
# When `chreipl-fcp-mpath` is built with D=1 (default is D=0), each run
|
||||||
|
# of one of the helper scripts will create a debug log in $(DEBUGOUTDIR)
|
||||||
|
# (default: /run/udev) which among other things contains the complete shell
|
||||||
|
# trace of that script run, with some added information that would not be
|
||||||
|
# inspectable otherwise with just the trace.
|
||||||
|
#
|
||||||
|
# There is currently no way of enabling/disabling this at runtime.
|
||||||
|
#
|
||||||
|
# chreipl-fcp-mpath-common.sh defines debug log file name as
|
||||||
|
# "chreiplzfcpmp-${debug_trace_tag}-${SEQNUM:-0}.XXXXXXXXXX" where SEQNUM is a
|
||||||
|
# udev rule environment variable and each X is replaced with some [[:alnum:]]
|
||||||
|
# by mktemp. For a definition of `debug_trace_tag`, please see the comments
|
||||||
|
# in the source.
|
||||||
|
#
|
||||||
|
# The following targets can be used for some simple access and filtering of the
|
||||||
|
# logs during development.
|
||||||
|
|
||||||
|
DEBUG_LOG_GLOB = $(DEBUGOUTDIR)/chreiplzfcpmp-[[:digit:]][[:digit:]][[:alpha:]][[:alpha:]][[:alpha:]][[:alpha:]]-+([[:digit:]]).[[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]]
|
||||||
|
|
||||||
|
# display all debug log files on the system
|
||||||
|
.PHONY: chreipl-fcp-mpath-debug-logs
|
||||||
|
chreipl-fcp-mpath-debug-logs:
|
||||||
|
@ls -1d $(DEBUG_LOG_GLOB)
|
||||||
|
|
||||||
|
# display only debug log files of script runs that exited with status 0 (= good)
|
||||||
|
#
|
||||||
|
# XXX: `sed -n -e '$p'` is used instead of `tail -n1` to prevent an other
|
||||||
|
# dependency just for that (both invocations do the same thing).
|
||||||
|
.PHONY: chreipl-fcp-mpath-debug-logs-filter-good
|
||||||
|
chreipl-fcp-mpath-debug-logs-filter-good:
|
||||||
|
@for lg in $(DEBUG_LOG_GLOB); do \
|
||||||
|
sed -e '/^+ trap_exit$$/,/^+ trap - EXIT$$/d' "$${lg}" \
|
||||||
|
| sed -n -e '$$p' \
|
||||||
|
| grep -q -e '^+ exit 0$$' || continue; \
|
||||||
|
ls -d "$${lg}"; \
|
||||||
|
done
|
||||||
|
|
||||||
|
# display only debug log files of script runs that didn't exit with status 0
|
||||||
|
# (= bad)
|
||||||
|
.PHONY: chreipl-fcp-mpath-debug-logs-filter-bad
|
||||||
|
chreipl-fcp-mpath-debug-logs-filter-bad:
|
||||||
|
@for lg in $(DEBUG_LOG_GLOB); do \
|
||||||
|
sed -e '/^+ trap_exit$$/,/^+ trap - EXIT$$/d' "$${lg}" \
|
||||||
|
| sed -n -e '$$p' \
|
||||||
|
| grep -q -e '^+ exit 0$$' && continue; \
|
||||||
|
ls -d "$${lg}"; \
|
||||||
|
done
|
||||||
|
|
||||||
|
.PHONY: chreipl-fcp-mpath-debug-logs-clean
|
||||||
|
chreipl-fcp-mpath-debug-logs-clean:
|
||||||
|
rm -f $(DEBUG_LOG_GLOB)
|
||||||
@@ -0,0 +1,268 @@
|
|||||||
|
<!-- markdown documentation: https://github.github.com/gfm/ -->
|
||||||
|
|
||||||
|
NAME
|
||||||
|
====
|
||||||
|
|
||||||
|
chreipl-fcp-mpath - use multipath information for re-IPL path failover on a
|
||||||
|
running Linux instance
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
===========
|
||||||
|
|
||||||
|
The IPL process of Linux on Z or LinuxONE from an FCP-attached SCSI volume uses
|
||||||
|
exactly one path to the volume. If this path is unavailable, the IPL fails.
|
||||||
|
|
||||||
|
The **chreipl-fcp-mpath** toolset monitors **udev** events about paths to the
|
||||||
|
re-IPL volume. If the currently configured re-IPL path becomes unavailable, the
|
||||||
|
toolset checks for operational paths to the same volume. If available, it
|
||||||
|
reconfigures the re-IPL settings to use an operational path.
|
||||||
|
|
||||||
|
Thus, re-IPL from an FCP-attached SCSI volume can be successful despite path
|
||||||
|
failures on a running Linux instance if at least one path to the re-IPL volume
|
||||||
|
remains operational.
|
||||||
|
|
||||||
|
**Chreipl-fcp-mpath** requires **udev**, **multipathd** and **dm-multipath**.
|
||||||
|
Once installed, the toolset runs automatically and autonomously. No user
|
||||||
|
intervention is possible or required.
|
||||||
|
|
||||||
|
Other than installing the toolset, there is no user interface for
|
||||||
|
**chreipl-fcp-mpath**.
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
|
||||||
|
The **chreipl-fcp-mpath** tool has the following requirements on the
|
||||||
|
Linux instance that is being monitored:
|
||||||
|
|
||||||
|
- The Linux instance must have started successfully, during IPL.
|
||||||
|
|
||||||
|
- The running Linux instance must use **dm-multipath** and **multipathd** for
|
||||||
|
the configured re-IPL volume - a volume that contains a zipl boot record
|
||||||
|
and has one of its paths used in the re-IPL configuration.
|
||||||
|
|
||||||
|
- **udev** must run.
|
||||||
|
|
||||||
|
- The toolset must observe at least one event about the configured re-IPL
|
||||||
|
path. Examples for such events are: the SCSI disk comes online, or a path
|
||||||
|
of the corresponding multipath device goes down or comes back online.
|
||||||
|
|
||||||
|
- The WWID of the re-IPL volume must not change while the Linux instance is
|
||||||
|
running.
|
||||||
|
|
||||||
|
- When the configured re-IPL path becomes unavailable while the Linux
|
||||||
|
instance is running, at least one operational path to the re-IPL volume
|
||||||
|
must be available, or must become available. If no such path is available
|
||||||
|
when the Linux instance is rebooted, the re-IPL path is not changed.
|
||||||
|
|
||||||
|
- The tool assumes that any manually reconfigured re-IPL device is valid and
|
||||||
|
operational.
|
||||||
|
|
||||||
|
The tool treats a newly configured re-IPL device like the initially
|
||||||
|
configured re-IPL device. In particular, if the newly configured re-IPL
|
||||||
|
device fulfills the requirements of the tool, re-IPL path failover takes
|
||||||
|
place if the configured re-IPL path becomes unavailable.
|
||||||
|
|
||||||
|
Caution with Manual Changes to the Configured re-IPL Target
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
**chreipl-fcp-mpath** is designed to accept operator-inititated changes of the
|
||||||
|
re-IPL device. However, concurrent changes by the operator and tool driven
|
||||||
|
changes can result in the operator change being overwritten.
|
||||||
|
|
||||||
|
To avoid this problem, change the re-IPL device only during steady-state
|
||||||
|
operations, when no path events happen. Alternatively, make sure that no events
|
||||||
|
are processed while you change the device. See [EXAMPLES](#examples) for one
|
||||||
|
way to suspend event processing.
|
||||||
|
|
||||||
|
MESSAGES
|
||||||
|
========
|
||||||
|
|
||||||
|
During monitoring and event processing, **chreipl-fcp-mpath** writes messages
|
||||||
|
to the syslog.
|
||||||
|
|
||||||
|
When the configured re-IPL path is changed to a different path to the same
|
||||||
|
volume (priority *daemon.notice*):
|
||||||
|
|
||||||
|
> Changed re-IPL path to: \<device-bus-id\>:\<wwpn\>:\<lun\>.
|
||||||
|
|
||||||
|
When a path event indicates that the last available path has become
|
||||||
|
non-operational (priority *daemon.alert*):
|
||||||
|
|
||||||
|
> The re-IPL device cannot be changed because no operational path to the
|
||||||
|
> re-IPL volume remains. The next re-IPL might fail unless you re-attach or
|
||||||
|
> enable at least one valid path to the re-IPL volume.
|
||||||
|
|
||||||
|
When changing the configured re-IPL device failed because of an error with the
|
||||||
|
used Linux kernel interface (priority *daemon.crit*):
|
||||||
|
|
||||||
|
> Changing the re-IPL device failed. The current re-IPL settings might be
|
||||||
|
> inconsistent. Check and correct the settings (see the README.md of
|
||||||
|
> chreipl-fcp-mpath) to make sure that the current re-IPL device is valid.
|
||||||
|
|
||||||
|
A failure to change the re-IPL device can indicate an inconsistent setting that
|
||||||
|
cannot be corrected automatically by **chreipl-fcp-mpath**. As a result, the
|
||||||
|
next re-IPL might fail or might not use the intended re-IPL device.
|
||||||
|
|
||||||
|
You can use the following tools to check and correct the current settings:
|
||||||
|
|
||||||
|
- **lsreipl** to confirm that the intended re-IPL device is configured;
|
||||||
|
- **chreipl** to change the re-IPL device;
|
||||||
|
- **lszfcp** to inspect the state of available paths to the re-IPL device.
|
||||||
|
|
||||||
|
<!-- NOT-IN-MAN { -->
|
||||||
|
|
||||||
|
SOFTWARE REQUIREMENTS
|
||||||
|
=====================
|
||||||
|
|
||||||
|
**chreipl-fcp-mpath** integrates into s390-tools's build and install
|
||||||
|
infrastructure. Use **make** to build it. No explicit dependency management is
|
||||||
|
in place, but the toolset has some software dependencies besides the
|
||||||
|
requirements in section [Requirements](#requirements):
|
||||||
|
|
||||||
|
- GNU Bash;
|
||||||
|
- GNU Core Utilities (mktemp, readlink, sync, truncate);
|
||||||
|
- util-linux (flock, hexdump, logger);
|
||||||
|
- udev / systemd-udev;
|
||||||
|
- multipath-tools.
|
||||||
|
|
||||||
|
To make use of the optional dracut configuration you need: dracut.
|
||||||
|
|
||||||
|
To build and install the documentation (man page) you need:
|
||||||
|
|
||||||
|
- pandoc;
|
||||||
|
- GNU Core Utilities (date);
|
||||||
|
- GNU awk.
|
||||||
|
|
||||||
|
INSTALLATION
|
||||||
|
============
|
||||||
|
|
||||||
|
If your distribution includes a packaged version of **chreipl-fcp-mpath**,
|
||||||
|
either as a separate package or as part of a **s390-tools** package, install
|
||||||
|
that package. Otherwise, you can either install it from source as part of
|
||||||
|
**s390-tools** or separately.
|
||||||
|
|
||||||
|
To install **chreipl-fcp-mpath** as part of **s390-tools**, use **make** on the
|
||||||
|
top-level directory of your **s390-tools** distribution. Installing the entire
|
||||||
|
distribution might overwrite other already installed tools.
|
||||||
|
|
||||||
|
To install the tool separately, change into the **chreipl-fcp-mpath**
|
||||||
|
directory, and use **make** there.
|
||||||
|
|
||||||
|
You need *root* privileges to install the tool into the root file system.
|
||||||
|
|
||||||
|
Calling **make** runs the build steps. Calling **make install** runs the build
|
||||||
|
steps and copies the resulting components to their final destination.
|
||||||
|
**s390-tools** offers more options and targets to customize the build (see
|
||||||
|
**make help**).
|
||||||
|
|
||||||
|
**chreipl-fcp-mpath** has the following optional build options:
|
||||||
|
|
||||||
|
| Option | Values | Default | Effect
|
||||||
|
| :----- | :----: | :-----: | :-----
|
||||||
|
| HAVE_DRACUT | 0, 1 | 0 | Install a dracut configuration file that includes **chreipl-fcp-mpath** in the initial ramdisks built with **dracut**.
|
||||||
|
| ENABLE_DOC | 0, 1 | 0 | Build and install a man page for **chreipl-fcp-mpath**.
|
||||||
|
|
||||||
|
Specify any options as arguments for both the **make** and **make install**
|
||||||
|
command as shown in the following example:
|
||||||
|
|
||||||
|
~ # cd chreipl-fcp-mpath/
|
||||||
|
~ # make HAVE_DRACUT=1 ENABLE_DOC=1
|
||||||
|
~ # make HAVE_DRACUT=1 ENABLE_DOC=1 install
|
||||||
|
|
||||||
|
After the installation, reload the udev rules database:
|
||||||
|
|
||||||
|
~ # udevadm control --reload
|
||||||
|
|
||||||
|
*The toolset is now active on your running Linux instance.*
|
||||||
|
|
||||||
|
If you use the *HAVE_DRACUT=1* option, also rebuild your
|
||||||
|
initial ramdisk, to immediately include the toolset instead of
|
||||||
|
waiting for the next kernel update.
|
||||||
|
|
||||||
|
How to rebuild the initial ramdisk and the naming scheme for the
|
||||||
|
resulting file or files depends on your distribution.
|
||||||
|
The following example applies to Fedora and to Red Hat Enterprise Linux:
|
||||||
|
|
||||||
|
~ # dracut --force /boot/initramfs-"$(uname -r)".img "$(uname -r)"
|
||||||
|
|
||||||
|
For SUSE Linux Enterprise Server run for example:
|
||||||
|
|
||||||
|
~ # dracut --hostonly --force /boot/initrd-"$(uname -r)" "$(uname -r)"
|
||||||
|
|
||||||
|
These commands replace the initial ramdisk for the currently running kernel.
|
||||||
|
If your distribution uses **zipl** as its boot loader, run **zipl** to refresh
|
||||||
|
the boot record to find the new initial ramdisk.
|
||||||
|
|
||||||
|
~ # zipl
|
||||||
|
|
||||||
|
With dracut and documentation enabled, **make install** deploys the following
|
||||||
|
files to these default locations:
|
||||||
|
|
||||||
|
/usr/lib/chreipl-fcp-mpath/chreipl-fcp-mpath-common.sh
|
||||||
|
/usr/lib/dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf
|
||||||
|
/usr/lib/udev/chreipl-fcp-mpath-is-ipl-tgt
|
||||||
|
/usr/lib/udev/chreipl-fcp-mpath-is-ipl-vol
|
||||||
|
/usr/lib/udev/chreipl-fcp-mpath-is-reipl-zfcp
|
||||||
|
/usr/lib/udev/chreipl-fcp-mpath-record-volume-identifier
|
||||||
|
/usr/lib/udev/chreipl-fcp-mpath-try-change-ipl-path
|
||||||
|
/usr/lib/udev/rules.d/70-chreipl-fcp-mpath.rules
|
||||||
|
/usr/share/man/man7/chreipl-fcp-mpath.7
|
||||||
|
|
||||||
|
UNINSTALL
|
||||||
|
=========
|
||||||
|
|
||||||
|
If your distribution includes a separately from **s390-tools** packaged version
|
||||||
|
of **chreipl-fcp-mpath**, uninstall that package.
|
||||||
|
|
||||||
|
For installations without distribution packaging, you cannot uninstall
|
||||||
|
**chreipl-fcp-mpath** with **make**.
|
||||||
|
|
||||||
|
Instead, remove the toolset by deleting the installed files as listed in
|
||||||
|
[INSTALLATION](#installation)), reload the udev rules database, and rebuild all
|
||||||
|
modified initial ramdisks as described in [INSTALLATION](#installation)).
|
||||||
|
|
||||||
|
<!-- NOT-IN-MAN } -->
|
||||||
|
|
||||||
|
EXAMPLES
|
||||||
|
========
|
||||||
|
|
||||||
|
Manual Changes to the Configured re-IPL Device
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
As outlined in [DESCRIPTION](#description), be cautious when manually changing
|
||||||
|
the configured re-IPL device. Assure that your reconfiguration actions do not
|
||||||
|
collide with concurrent automatic event processing by **chreipl-fcp-mpath**.
|
||||||
|
You can avoid such collisions, by stopping event processing, making your
|
||||||
|
changes, and then re-enabling event processing. You need *root* privileges for
|
||||||
|
running the commands in the following example:
|
||||||
|
|
||||||
|
~ # udevadm settle
|
||||||
|
~ # udevadm control --stop-exec-queue
|
||||||
|
~ # chreipl ...
|
||||||
|
~ # udevadm control --start-exec-queue
|
||||||
|
|
||||||
|
Listing messages with journalctl
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
If your Linux instance includes **journalctl**, use the following command to
|
||||||
|
list all messages that are issued by **chreipl-fcp-mpath**:
|
||||||
|
|
||||||
|
~ # journalctl -t chreipl-fcp-mpath
|
||||||
|
|
||||||
|
To list only messages that were issued since the last IPL, use this command:
|
||||||
|
|
||||||
|
~ # journalctl -t chreipl-fcp-mpath -b
|
||||||
|
|
||||||
|
REPORTING BUGS
|
||||||
|
==============
|
||||||
|
|
||||||
|
Use the **Issues** functionality on GitHub to report any bugs in
|
||||||
|
**chreipl-fcp-mpath**:
|
||||||
|
[s390-tools Issues](<https://github.com/ibm-s390-linux/s390-tools/issues> "Link to the s390-tools Issues page").
|
||||||
|
|
||||||
|
SEE ALSO
|
||||||
|
========
|
||||||
|
|
||||||
|
**chreipl**(8), **dracut**(8), **journalctl**(1), **lsreipl(8)**,
|
||||||
|
**lszfcp**(8), **multipath**(8), **multipathd**(8), **udev**(7),
|
||||||
|
**udevadm**(8), **zipl**(8)
|
||||||
@@ -0,0 +1,446 @@
|
|||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
#
|
||||||
|
# chreipl-fcp-mpath: use multipath information to change FCP IPL target
|
||||||
|
# (C) Copyright IBM Corp. 2021
|
||||||
|
#
|
||||||
|
# Uses the following system-utilities (and shell-builtins):
|
||||||
|
# GNU coreutils:
|
||||||
|
# - mktemp
|
||||||
|
# - readlink
|
||||||
|
# - sync
|
||||||
|
# util-linux:
|
||||||
|
# - flock
|
||||||
|
# - logger
|
||||||
|
|
||||||
|
# Makes use of udev event environment variables:
|
||||||
|
# SEQNUM
|
||||||
|
|
||||||
|
# (1) expand failed globs to an empty string
|
||||||
|
# (2) extended pattern matching to strip leading/trailing whitespaces
|
||||||
|
shopt -s nullglob extglob
|
||||||
|
# (1) don't overwrite existing files using redirects (e.g.: `>`)
|
||||||
|
set -o noclobber
|
||||||
|
|
||||||
|
# make sure any state files created are only writeable by the owning user
|
||||||
|
umask 027
|
||||||
|
|
||||||
|
# create log if DEBUG is enabled (with Make: D=1)
|
||||||
|
#
|
||||||
|
# Each script importing this library and expecting a debug log to be created
|
||||||
|
# must declare a *trace tag* in a variable `debug_trace_tag`. This is used as
|
||||||
|
# identifier in the log file name. The format is:
|
||||||
|
#
|
||||||
|
# [[:digit:]][[:digit:]][[:alpha:]][[:alpha:]][[:alpha:]][[:alpha:]]
|
||||||
|
# \ /\ /
|
||||||
|
# --------\ /-------- -------------------\ /-------------------
|
||||||
|
# \/ \/
|
||||||
|
# relative position of some unique abbreviation for the script
|
||||||
|
# execution in the name, excluding any common prefix
|
||||||
|
# udev rules
|
||||||
|
if '@DEBUG@' && [ -v debug_trace_tag ] && tlg="$(
|
||||||
|
mktemp -p '@debugoutdir@' \
|
||||||
|
"chreiplzfcpmp-${debug_trace_tag}-${SEQNUM:-0}.XXXXXXXXXX" \
|
||||||
|
2>/dev/null)"
|
||||||
|
then
|
||||||
|
readonly tlg
|
||||||
|
exec >|"${tlg}" 2>&1
|
||||||
|
set -x
|
||||||
|
set
|
||||||
|
else
|
||||||
|
unset tlg
|
||||||
|
fi
|
||||||
|
|
||||||
|
declare -gr ID_FILE='@chreiplzfcpmp-id-file@'
|
||||||
|
declare -gr FW_LOCK_FILE='@chreiplzfcpmp-fwlock-file@'
|
||||||
|
|
||||||
|
declare -gA TRAP_EXIT_FN=()
|
||||||
|
declare -gf trap_exit 1>/dev/null
|
||||||
|
function trap_exit() {
|
||||||
|
local fn
|
||||||
|
|
||||||
|
for fn in "${TRAP_EXIT_FN[@]}"; do
|
||||||
|
"${fn}"
|
||||||
|
done
|
||||||
|
|
||||||
|
trap - EXIT
|
||||||
|
}
|
||||||
|
trap trap_exit EXIT
|
||||||
|
|
||||||
|
# Output variables:
|
||||||
|
# id_file_unlock_exclusive_create() - call to unlock when finished with
|
||||||
|
# critical section
|
||||||
|
#
|
||||||
|
# XXX: `id_file_lock_*` can't be taken recursively
|
||||||
|
function id_file_lock_exclusive_create() {
|
||||||
|
declare -g ID_FILE_LOCK=""
|
||||||
|
|
||||||
|
# prevent concurrent file creation
|
||||||
|
#
|
||||||
|
# First, open the file defined in ${ID_FILE} for writing; this will
|
||||||
|
# succeed and create the file only if it doesn't exist already. If the
|
||||||
|
# file already exist, the first open attempt will fail and we fall
|
||||||
|
# back to opening it only for reading; this will always succeed if the
|
||||||
|
# file already exists (the reason why the first attempty failed). In
|
||||||
|
# both cases store the corresponding file descriptor in
|
||||||
|
# ${ID_FILE_LOCK}.
|
||||||
|
#
|
||||||
|
# XXX: This should be race free.
|
||||||
|
# open() with O_EXCL... is atomic (we set `noclobber` as shell
|
||||||
|
# option); at least as long as we talk about a local FS.
|
||||||
|
if ! { exec {ID_FILE_LOCK}>"${ID_FILE}"; } 2>/dev/null; then
|
||||||
|
{ exec {ID_FILE_LOCK}<"${ID_FILE}"; } 2>/dev/null \
|
||||||
|
|| return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
declare -gf id_file_unlock_exclusive_create 1>/dev/null
|
||||||
|
function id_file_unlock_exclusive_create() {
|
||||||
|
if [ -v ID_FILE_LOCK ]; then
|
||||||
|
sync "${ID_FILE}" 2>/dev/null
|
||||||
|
# release file and implicitly the lock, if taken
|
||||||
|
exec {ID_FILE_LOCK}>&-
|
||||||
|
unset ID_FILE_LOCK
|
||||||
|
fi
|
||||||
|
|
||||||
|
unset "TRAP_EXIT_FN[id_file_unlock_exclusive_create]"
|
||||||
|
}
|
||||||
|
TRAP_EXIT_FN+=(
|
||||||
|
[id_file_unlock_exclusive_create]=id_file_unlock_exclusive_create
|
||||||
|
)
|
||||||
|
|
||||||
|
flock --exclusive --timeout 5 "${ID_FILE_LOCK}" || return 2
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Output variables:
|
||||||
|
# id_file_unlock_exclusive_no_create() - call to unlock when finished with
|
||||||
|
# critical section
|
||||||
|
#
|
||||||
|
# XXX: `id_file_lock_*` can't be taken recursively
|
||||||
|
function id_file_lock_exclusive_no_create() {
|
||||||
|
declare -g ID_FILE_LOCK=""
|
||||||
|
|
||||||
|
# Open the file defined in ${ID_FILE} for reading, and store the
|
||||||
|
# corresponding file descriptor in ${ID_FILE_LOCK}.
|
||||||
|
#
|
||||||
|
# XXX: return code is used in `chreipl-fcp-mpath-try-change-ipl-path`
|
||||||
|
{ exec {ID_FILE_LOCK}<"${ID_FILE}"; } 2>/dev/null || return 1
|
||||||
|
|
||||||
|
declare -gf id_file_unlock_exclusive_no_create 1>/dev/null
|
||||||
|
function id_file_unlock_exclusive_no_create() {
|
||||||
|
if [ -v ID_FILE_LOCK ]; then
|
||||||
|
sync "${ID_FILE}" 2>/dev/null
|
||||||
|
# release file and implicitly the lock, if taken
|
||||||
|
exec {ID_FILE_LOCK}<&-
|
||||||
|
unset ID_FILE_LOCK
|
||||||
|
fi
|
||||||
|
|
||||||
|
unset "TRAP_EXIT_FN[id_file_unlock_exclusive_no_create]"
|
||||||
|
}
|
||||||
|
TRAP_EXIT_FN+=(
|
||||||
|
[id_file_unlock_exclusive_no_create]=id_file_unlock_exclusive_no_create
|
||||||
|
)
|
||||||
|
|
||||||
|
flock --exclusive --timeout 5 "${ID_FILE_LOCK}" || return 2
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Output variables:
|
||||||
|
# id_file_unlock_shared_no_create() - call to unlock when finished with
|
||||||
|
# critical section
|
||||||
|
#
|
||||||
|
# XXX: `id_file_lock_*` can't be taken recursively
|
||||||
|
function id_file_lock_shared_no_create() {
|
||||||
|
declare -g ID_FILE_LOCK=""
|
||||||
|
|
||||||
|
# Open the file defined in ${ID_FILE} for reading, and store the
|
||||||
|
# corresponding file descriptor in ${ID_FILE_LOCK}.
|
||||||
|
{ exec {ID_FILE_LOCK}<"${ID_FILE}"; } 2>/dev/null || return 1
|
||||||
|
|
||||||
|
declare -gf id_file_unlock_shared_no_create 1>/dev/null
|
||||||
|
function id_file_unlock_shared_no_create() {
|
||||||
|
if [ -v ID_FILE_LOCK ]; then
|
||||||
|
# release file and implicitly the lock, if taken
|
||||||
|
exec {ID_FILE_LOCK}<&-
|
||||||
|
unset ID_FILE_LOCK
|
||||||
|
fi
|
||||||
|
|
||||||
|
unset "TRAP_EXIT_FN[id_file_unlock_shared_no_create]"
|
||||||
|
}
|
||||||
|
TRAP_EXIT_FN+=(
|
||||||
|
[id_file_unlock_shared_no_create]=id_file_unlock_shared_no_create
|
||||||
|
)
|
||||||
|
|
||||||
|
flock --shared --timeout 5 "${ID_FILE_LOCK}" || return 2
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Output variables:
|
||||||
|
# firmware_unlock_exclusive() - call to unlock when finished with critical section
|
||||||
|
#
|
||||||
|
# XXX: `firmware_lock_*` can't be taken recursively
|
||||||
|
function firmware_lock_exclusive() {
|
||||||
|
declare -g FIRMWARE_LOCK=""
|
||||||
|
|
||||||
|
# Open the file defined in ${FW_LOCK_FILE} for reading, and store the
|
||||||
|
# corresponding file descriptor in ${FIRMWARE_LOCK} (it doesn't matter
|
||||||
|
# whether this is a normal file or directory). This file descriptor
|
||||||
|
# will only be used for locking - not for actual I/O.
|
||||||
|
{ exec {FIRMWARE_LOCK}<"${FW_LOCK_FILE}"; } 2>/dev/null || return 1
|
||||||
|
|
||||||
|
declare -gf firmware_unlock_exclusive 1>/dev/null
|
||||||
|
function firmware_unlock_exclusive() {
|
||||||
|
if [ -v FIRMWARE_LOCK ]; then
|
||||||
|
# release file and implicitly the lock, if taken
|
||||||
|
exec {FIRMWARE_LOCK}<&-
|
||||||
|
unset FIRMWARE_LOCK
|
||||||
|
fi
|
||||||
|
|
||||||
|
unset "TRAP_EXIT_FN[firmware_unlock_exclusive]"
|
||||||
|
}
|
||||||
|
TRAP_EXIT_FN+=([firmware_unlock_exclusive]=firmware_unlock_exclusive)
|
||||||
|
|
||||||
|
flock --exclusive --timeout 5 "${FIRMWARE_LOCK}" || return 2
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Output variables:
|
||||||
|
# firmware_unlock_shared() - call to unlock when finished with critical section
|
||||||
|
#
|
||||||
|
# XXX: `firmware_lock_*` can't be taken recursively
|
||||||
|
function firmware_lock_shared() {
|
||||||
|
declare -g FIRMWARE_LOCK=""
|
||||||
|
|
||||||
|
# Open the file defined in ${FW_LOCK_FILE} for reading, and store the
|
||||||
|
# corresponding file descriptor in ${FIRMWARE_LOCK} (it doesn't matter
|
||||||
|
# whether this is a normal file or directory). This file descriptor
|
||||||
|
# will only be used for locking - not for actual I/O.
|
||||||
|
{ exec {FIRMWARE_LOCK}<"${FW_LOCK_FILE}"; } 2>/dev/null || return 1
|
||||||
|
|
||||||
|
declare -gf firmware_unlock_shared 1>/dev/null
|
||||||
|
function firmware_unlock_shared() {
|
||||||
|
if [ -v FIRMWARE_LOCK ]; then
|
||||||
|
# release file and implicitly the lock, if taken
|
||||||
|
exec {FIRMWARE_LOCK}<&-
|
||||||
|
unset FIRMWARE_LOCK
|
||||||
|
fi
|
||||||
|
|
||||||
|
unset "TRAP_EXIT_FN[firmware_unlock_shared]"
|
||||||
|
}
|
||||||
|
TRAP_EXIT_FN+=([firmware_unlock_shared]=firmware_unlock_shared)
|
||||||
|
|
||||||
|
flock --shared --timeout 5 "${FIRMWARE_LOCK}" || return 2
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Output variables:
|
||||||
|
# IPL_TYPE
|
||||||
|
# IPL_BUSID
|
||||||
|
# IPL_WWPN
|
||||||
|
# IPL_LUN
|
||||||
|
function firmware_get_ipl_information() {
|
||||||
|
declare -g IPL_TYPE="" IPL_BUSID="" IPL_WWPN="" IPL_LUN=""
|
||||||
|
|
||||||
|
# Take lock so we don't see any intermediate state from other helpers
|
||||||
|
# running in parallel
|
||||||
|
firmware_lock_shared || return 5
|
||||||
|
|
||||||
|
{ read -r IPL_TYPE _ < /sys/firmware/reipl/reipl_type; } 2>/dev/null \
|
||||||
|
|| return 1
|
||||||
|
{ read -r IPL_BUSID _ < /sys/firmware/reipl/fcp/device; } 2>/dev/null \
|
||||||
|
|| return 2
|
||||||
|
{ read -r IPL_WWPN _ < /sys/firmware/reipl/fcp/wwpn; } 2>/dev/null \
|
||||||
|
|| return 3
|
||||||
|
{ read -r IPL_LUN _ < /sys/firmware/reipl/fcp/lun; } 2>/dev/null \
|
||||||
|
|| return 4
|
||||||
|
|
||||||
|
firmware_unlock_shared
|
||||||
|
|
||||||
|
# show read values in debug log if enabled
|
||||||
|
if '@DEBUG@'; then
|
||||||
|
declare -p IPL_TYPE IPL_BUSID IPL_WWPN IPL_LUN 1>&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Input:
|
||||||
|
# 1: absolute canonical path to the scsi device in sysfs, e.g.:
|
||||||
|
# /sys/devices/css0/0.0.0014/0.0.1700/host1/rport-1:0-0/target1:0:0/1:0:0:1075789848
|
||||||
|
# Output variables:
|
||||||
|
# SDEV_LUN
|
||||||
|
function sdev_get_lun() {
|
||||||
|
local sdev="${1}" sdev_lun_str
|
||||||
|
# bash uses `intmax_t` as width for integer variables, and glibc
|
||||||
|
# defines this either as `long int` on 64 bit systems, or
|
||||||
|
# `long long int` on other.
|
||||||
|
local -i sdev_lun=0 fcp_lun=0
|
||||||
|
|
||||||
|
sdev_lun_str="${sdev##*:}"
|
||||||
|
# e.g.: 1075789848
|
||||||
|
[[ "${sdev_lun_str}" == +([[:digit:]]) ]] || return 1
|
||||||
|
# "cast" to integer
|
||||||
|
sdev_lun="${sdev_lun_str}"
|
||||||
|
|
||||||
|
# convert the Linux integer LUN format to the hexadecimal 64 bit T10
|
||||||
|
# LUN representation format used by many s390x interfaces
|
||||||
|
(( fcp_lun = (((sdev_lun >> 0) & 0xffff) << 48)
|
||||||
|
| (((sdev_lun >> 16) & 0xffff) << 32)
|
||||||
|
| (((sdev_lun >> 32) & 0xffff) << 16)
|
||||||
|
| (((sdev_lun >> 48) & 0xffff) << 0) ))
|
||||||
|
# the '0x' prefix is part of the length
|
||||||
|
printf -v SDEV_LUN "%#018llx" "${fcp_lun}"
|
||||||
|
|
||||||
|
# show read values in debug log if enabled
|
||||||
|
if '@DEBUG@'; then
|
||||||
|
declare -p SDEV_LUN 1>&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Input:
|
||||||
|
# 1: path to the scsi device in sysfs, e.g.:
|
||||||
|
# /sys/devices/css0/0.0.0014/0.0.1700/host1/rport-1:0-0/target1:0:0/1:0:0:1075789848
|
||||||
|
# , or a symlink pointing to the scsi device, e.g.:
|
||||||
|
# /sys/class/block/sds/device
|
||||||
|
# Output variables:
|
||||||
|
# SDEV_BUSID
|
||||||
|
# SDEV_WWPN
|
||||||
|
# SDEV_LUN
|
||||||
|
function sdev_get_fcp_addressing() {
|
||||||
|
local sdev="${1}" fcp_lun rport rport_wwpn zfcp_dev
|
||||||
|
|
||||||
|
declare -g SDEV_BUSID="" SDEV_WWPN="" SDEV_LUN=""
|
||||||
|
|
||||||
|
sdev="$(readlink -se "${sdev}")" || return 1
|
||||||
|
|
||||||
|
# get the LUN for this SDEV
|
||||||
|
#
|
||||||
|
# sets ${SDEV_LUN}
|
||||||
|
sdev_get_lun "${sdev}" || return 2
|
||||||
|
|
||||||
|
# get the WWPN of the remote port this SDEV is attached to
|
||||||
|
printf -v rport "%s" "${sdev}"/../../fc_remote_ports/rport-*:*-*
|
||||||
|
# e.g.: /sys/devices/css0/0.0.0016/0.0.1740/host0/rport-0:0-1/fc_remote_ports/rport-0:0-1
|
||||||
|
[ "${rport}" != "" ] || return 3
|
||||||
|
|
||||||
|
# XXX: This works even if the rport is currently in a bad
|
||||||
|
# state, so e.g. when it has just gone down because of a
|
||||||
|
# cable pull.
|
||||||
|
{ read -r rport_wwpn _ < "${rport}"/port_name; } 2>/dev/null \
|
||||||
|
|| return 4
|
||||||
|
|
||||||
|
# The Linux kernel doesn't guarantee the same format as in
|
||||||
|
# /sys/firmware/..., so make sure it is the one we expect.
|
||||||
|
[[ "${rport_wwpn}" =~ ^0x[[:xdigit:]]{1,16}$ ]] || return 5
|
||||||
|
# the '0x' prefix is part of the length
|
||||||
|
printf -v rport_wwpn "%#018llx" "${rport_wwpn}"
|
||||||
|
|
||||||
|
# get the Device Bus-ID of the device via which this SDEV is attached
|
||||||
|
zfcp_dev="$(readlink -se "${sdev}"/../../../..)" || return 6
|
||||||
|
# e.g.: /sys/devices/css0/0.0.0016/0.0.1740
|
||||||
|
zfcp_dev="${zfcp_dev##*/}"
|
||||||
|
|
||||||
|
# shellcheck disable=2034
|
||||||
|
SDEV_BUSID="${zfcp_dev}"
|
||||||
|
# shellcheck disable=2034
|
||||||
|
SDEV_WWPN="${rport_wwpn}"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Input:
|
||||||
|
# 1: path to the scsi device in sysfs
|
||||||
|
# Output variables:
|
||||||
|
# SDEV_WWID
|
||||||
|
function sdev_get_wwid() {
|
||||||
|
local sdev="${1}"
|
||||||
|
local -a wwid
|
||||||
|
|
||||||
|
declare -g SDEV_WWID=""
|
||||||
|
|
||||||
|
# read the volume identifier without stripping any content
|
||||||
|
#
|
||||||
|
# XXX: we can read the WWID file, even if the SDEV is currently not
|
||||||
|
# operational (e.g.: due to the path has gone away), as long as
|
||||||
|
# the VPD PG 83 is still cached in the kernel; and the page gets
|
||||||
|
# only released on SDEV device release.
|
||||||
|
{ readarray -d "" -t wwid < "${sdev}"/wwid; } 2>/dev/null \
|
||||||
|
|| return 1
|
||||||
|
if '@DEBUG@'; then declare -p wwid 1>&2; fi
|
||||||
|
|
||||||
|
# test whether we read something
|
||||||
|
#
|
||||||
|
# This strips all leading spaces from the beginning of the read WWID
|
||||||
|
# (until the first non-space or NUL character), and checks whether the
|
||||||
|
# result is empty.
|
||||||
|
# Hence, we return early if the WWID consists of only whitespace.
|
||||||
|
#
|
||||||
|
# XXX: there could be unexpected characters in the returned ID.
|
||||||
|
# `scsi_id` from the udev helpers sanitizes the strings it reads
|
||||||
|
# from the devices, so they can be used in environment variables
|
||||||
|
# without much danger.
|
||||||
|
# But we don't export anything here, so it should be fine.
|
||||||
|
[ "${wwid[0]/#*([[:space:]])}" != "" ] || return 2
|
||||||
|
|
||||||
|
# shellcheck disable=2034
|
||||||
|
SDEV_WWID="${wwid[0]}"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Input:
|
||||||
|
# 1: path to the scsi device in sysfs
|
||||||
|
# Return Value:
|
||||||
|
# == 0: SDEV referenced by `1` in good state
|
||||||
|
# != 0: otherwise
|
||||||
|
function sdev_test_path_state() {
|
||||||
|
local sdev="${1}" state zfcp_failed zfcp_in_recovery rport port_state
|
||||||
|
|
||||||
|
sdev="$(readlink -se "${sdev}")" || return 1
|
||||||
|
|
||||||
|
{ read -r state _ < "${sdev}"/state; } 2>/dev/null || return 2
|
||||||
|
{ read -r zfcp_failed _ < "${sdev}"/zfcp_failed; } 2>/dev/null \
|
||||||
|
|| return 3
|
||||||
|
{ read -r zfcp_in_recovery _ < "${sdev}"/zfcp_in_recovery; } 2>/dev/null \
|
||||||
|
|| return 4
|
||||||
|
|
||||||
|
printf -v rport "%s" "${sdev}"/../../fc_remote_ports/rport-*:*-*
|
||||||
|
# e.g.: /sys/devices/css0/0.0.0016/0.0.1740/host0/rport-0:0-1/fc_remote_ports/rport-0:0-1
|
||||||
|
[ "${rport}" != "" ] || return 5
|
||||||
|
{ read -r port_state _ < "${rport}"/port_state; } 2>/dev/null \
|
||||||
|
|| return 6
|
||||||
|
|
||||||
|
if '@DEBUG@'; then
|
||||||
|
declare -p state zfcp_failed zfcp_in_recovery port_state 1>&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ "${state}" = "running" ] || return 7
|
||||||
|
[ "${zfcp_failed}" = "0" ] || return 8
|
||||||
|
[ "${zfcp_in_recovery}" = "0" ] || return 9
|
||||||
|
{ [ "${port_state}" = "Online" ] \
|
||||||
|
|| [ "${port_state}" = "Marginal" ]; } || return 10
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Input:
|
||||||
|
# *: all input parameters are used as quoted message
|
||||||
|
function log_note() {
|
||||||
|
logger -p 'daemon.notice' -t 'chreipl-fcp-mpath' "${*}" &>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Input:
|
||||||
|
# *: all input parameters are used as quoted message
|
||||||
|
function log_crit() {
|
||||||
|
logger -p 'daemon.crit' -t 'chreipl-fcp-mpath' "${*}" &>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Input:
|
||||||
|
# *: all input parameters are used as quoted message
|
||||||
|
function log_alert() {
|
||||||
|
logger -p 'daemon.alert' -t 'chreipl-fcp-mpath' "${*}" &>/dev/null
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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 $(@) $(<)
|
||||||
@@ -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 "
|
||||||
@@ -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"
|
||||||
+7
-6
@@ -16,17 +16,18 @@ check_dep:
|
|||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
"cmsfs-fuse", \
|
"cmsfs-fuse", \
|
||||||
"fuse.h", \
|
"fuse.h", \
|
||||||
"fuse-devel or libfuse-dev", \
|
"fuse3-devel or libfuse3-dev", \
|
||||||
"HAVE_FUSE=0")
|
"HAVE_FUSE=0", \
|
||||||
|
"-DFUSE_USE_VERSION=30")
|
||||||
|
|
||||||
all: check_dep cmsfs-fuse
|
all: check_dep cmsfs-fuse
|
||||||
|
|
||||||
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
||||||
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse)
|
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse3)
|
||||||
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse)
|
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse3)
|
||||||
else
|
else
|
||||||
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse
|
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse3
|
||||||
FUSE_LDLIBS = -lfuse
|
FUSE_LDLIBS = -lfuse3
|
||||||
endif
|
endif
|
||||||
ALL_CFLAGS += -DHAVE_SETXATTR $(FUSE_CFLAGS)
|
ALL_CFLAGS += -DHAVE_SETXATTR $(FUSE_CFLAGS)
|
||||||
LDLIBS += $(FUSE_LDLIBS) -lm
|
LDLIBS += $(FUSE_LDLIBS) -lm
|
||||||
|
|||||||
@@ -80,9 +80,6 @@ Allow access by other users
|
|||||||
\fB\-o\fR allow_root
|
\fB\-o\fR allow_root
|
||||||
Allow access by root
|
Allow access by root
|
||||||
.TP
|
.TP
|
||||||
\fB\-o\fR nonempty
|
|
||||||
Allow mounts over non\-empty file/dir
|
|
||||||
.TP
|
|
||||||
\fB\-o\fR default_permissions
|
\fB\-o\fR default_permissions
|
||||||
Enable permission checking by kernel
|
Enable permission checking by kernel
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
+23
-9
@@ -9,7 +9,7 @@
|
|||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define FUSE_USE_VERSION 26
|
#define FUSE_USE_VERSION 30
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -1516,7 +1516,7 @@ static void walk_dir_block(struct fst_entry *fst, struct walk_file *walk,
|
|||||||
decode_edf_name(file, fst->name, fst->type);
|
decode_edf_name(file, fst->name, fst->type);
|
||||||
if (!file_unlinked(file)) {
|
if (!file_unlinked(file)) {
|
||||||
cache_fst_addr(walk->addr, file);
|
cache_fst_addr(walk->addr, file);
|
||||||
walk->filler(walk->buf, file, NULL, 0);
|
walk->filler(walk->buf, file, NULL, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1728,8 +1728,11 @@ static off_t get_file_size_logical(struct fst_entry *fst)
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmsfs_getattr(const char *path, struct stat *stbuf)
|
static int cmsfs_getattr(const char *path, struct stat *stbuf,
|
||||||
|
struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
|
(void) fi;
|
||||||
|
|
||||||
int mask = (cmsfs.allow_other) ? 0444 : 0440;
|
int mask = (cmsfs.allow_other) ? 0444 : 0440;
|
||||||
struct fst_entry fst;
|
struct fst_entry fst;
|
||||||
|
|
||||||
@@ -1783,13 +1786,15 @@ static int cmsfs_getattr(const char *path, struct stat *stbuf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int cmsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
static int cmsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
||||||
off_t offset, struct fuse_file_info *fi)
|
off_t offset, struct fuse_file_info *fi,
|
||||||
|
enum fuse_readdir_flags flags)
|
||||||
{
|
{
|
||||||
struct walk_file walk;
|
struct walk_file walk;
|
||||||
struct fst_entry fst;
|
struct fst_entry fst;
|
||||||
|
|
||||||
(void) offset;
|
(void) offset;
|
||||||
(void) fi;
|
(void) fi;
|
||||||
|
(void) flags;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Offset is ignored and 0 passed to the filler fn so the whole
|
* Offset is ignored and 0 passed to the filler fn so the whole
|
||||||
@@ -1800,8 +1805,8 @@ static int cmsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
|||||||
if (strcmp(path, "/") != 0)
|
if (strcmp(path, "/") != 0)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
filler(buf, ".", NULL, 0);
|
filler(buf, ".", NULL, 0, 0);
|
||||||
filler(buf, "..", NULL, 0);
|
filler(buf, "..", NULL, 0, 0);
|
||||||
|
|
||||||
memset(&walk, 0, sizeof(walk));
|
memset(&walk, 0, sizeof(walk));
|
||||||
/* readdir is possible without open so fi->fh is not set */
|
/* readdir is possible without open so fi->fh is not set */
|
||||||
@@ -2683,13 +2688,16 @@ static int cmsfs_statfs(const char *path, struct statvfs *buf)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmsfs_utimens(const char *path, const struct timespec ts[2])
|
static int cmsfs_utimens(const char *path, const struct timespec ts[2],
|
||||||
|
struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
struct fst_entry fst;
|
struct fst_entry fst;
|
||||||
off_t fst_addr;
|
off_t fst_addr;
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
(void) fi;
|
||||||
|
|
||||||
if (cmsfs.readonly)
|
if (cmsfs.readonly)
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
@@ -2825,7 +2833,8 @@ error:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmsfs_rename(const char *path, const char *new_path)
|
static int cmsfs_rename(const char *path, const char *new_path,
|
||||||
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
struct fst_entry fst, fst_new;
|
struct fst_entry fst, fst_new;
|
||||||
off_t fst_addr, fst_addr_new;
|
off_t fst_addr, fst_addr_new;
|
||||||
@@ -2835,6 +2844,8 @@ static int cmsfs_rename(const char *path, const char *new_path)
|
|||||||
struct file *f;
|
struct file *f;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
(void) flags;
|
||||||
|
|
||||||
if (cmsfs.readonly)
|
if (cmsfs.readonly)
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
@@ -3232,13 +3243,16 @@ static void update_fst(struct file *f, off_t addr)
|
|||||||
unhide_null_blocks(f);
|
unhide_null_blocks(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmsfs_truncate(const char *path, off_t size)
|
static int cmsfs_truncate(const char *path, off_t size,
|
||||||
|
struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
struct fst_entry fst;
|
struct fst_entry fst;
|
||||||
off_t fst_addr, len;
|
off_t fst_addr, len;
|
||||||
struct file *f;
|
struct file *f;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
|
(void) fi;
|
||||||
|
|
||||||
if (cmsfs.readonly)
|
if (cmsfs.readonly)
|
||||||
return -EROFS;
|
return -EROFS;
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -5,7 +5,7 @@ COMMON_INCLUDED = true
|
|||||||
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
|
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
|
||||||
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
|
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
|
||||||
VERSION = 2
|
VERSION = 2
|
||||||
RELEASE = 17
|
RELEASE = 20
|
||||||
PATCHLEVEL = 0
|
PATCHLEVEL = 0
|
||||||
DISTRELEASE = build-$(shell date +%Y%m%d)
|
DISTRELEASE = build-$(shell date +%Y%m%d)
|
||||||
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
|
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
|
||||||
@@ -182,6 +182,7 @@ USRSBINDIR = $(INSTALLDIR)/usr/sbin
|
|||||||
USRBINDIR = $(INSTALLDIR)/usr/bin
|
USRBINDIR = $(INSTALLDIR)/usr/bin
|
||||||
BINDIR = $(INSTALLDIR)/sbin
|
BINDIR = $(INSTALLDIR)/sbin
|
||||||
LIBDIR = $(INSTALLDIR)/lib
|
LIBDIR = $(INSTALLDIR)/lib
|
||||||
|
USRLIBDIR = $(INSTALLDIR)/usr/lib
|
||||||
USRLIB64DIR = $(INSTALLDIR)/usr/lib64
|
USRLIB64DIR = $(INSTALLDIR)/usr/lib64
|
||||||
SYSCONFDIR = $(INSTALLDIR)/etc
|
SYSCONFDIR = $(INSTALLDIR)/etc
|
||||||
MANDIR = $(INSTALLDIR)/usr/share/man
|
MANDIR = $(INSTALLDIR)/usr/share/man
|
||||||
@@ -206,10 +207,10 @@ INSTDIRS = $(USRSBINDIR) $(USRBINDIR) $(BINDIR) $(LIBDIR) $(MANDIR) \
|
|||||||
$(TOOLS_LIBDIR) $(TOOLS_DATADIR) \
|
$(TOOLS_LIBDIR) $(TOOLS_DATADIR) \
|
||||||
$(ZFCPDUMP_DIR) $(SYSTEMDSYSTEMUNITDIR) \
|
$(ZFCPDUMP_DIR) $(SYSTEMDSYSTEMUNITDIR) \
|
||||||
$(USRLIB64DIR) $(USRINCLUDEDIR) $(ZKEYKMSPLUGINDIR) \
|
$(USRLIB64DIR) $(USRINCLUDEDIR) $(ZKEYKMSPLUGINDIR) \
|
||||||
$(SOINSTALLDIR)
|
$(SOINSTALLDIR) $(USRLIBDIR)
|
||||||
OWNER = $(shell id -un)
|
OWNER = $(shell id -un)
|
||||||
GROUP = $(shell id -gn)
|
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
|
# Special defines for zfcpdump
|
||||||
ZFCPDUMP_IMAGE = zfcpdump-image
|
ZFCPDUMP_IMAGE = zfcpdump-image
|
||||||
|
|||||||
+15
-20
@@ -17,6 +17,7 @@
|
|||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <linux/limits.h>
|
#include <linux/limits.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -45,15 +46,15 @@
|
|||||||
#define CPUS_POSSIBLE "/sys/devices/system/cpu/possible"
|
#define CPUS_POSSIBLE "/sys/devices/system/cpu/possible"
|
||||||
#define CPUS_KERNELMAX "/sys/devices/system/cpu/kernel_max"
|
#define CPUS_KERNELMAX "/sys/devices/system/cpu/kernel_max"
|
||||||
#define MAXCTRS 512
|
#define MAXCTRS 512
|
||||||
|
#define IOCTLSLEEP 60U
|
||||||
|
|
||||||
static const unsigned int ioctlsleep = 60;
|
static unsigned int read_interval = IOCTLSLEEP, cfvn, csvn, authorization;
|
||||||
static unsigned int read_interval = ioctlsleep, cfvn, csvn, authorization;
|
|
||||||
static unsigned long loop_count = 1;
|
static unsigned long loop_count = 1;
|
||||||
static unsigned char *ioctlbuffer;
|
static unsigned char *ioctlbuffer;
|
||||||
static bool allcpu;
|
static bool allcpu;
|
||||||
|
|
||||||
static unsigned int max_possible_cpus; /* No of possible CPUs */
|
static unsigned int max_possible_cpus; /* No of possible CPUs */
|
||||||
struct ctrname { /* List of defined counters */
|
static struct ctrname { /* List of defined counters */
|
||||||
char *name; /* Counter name */
|
char *name; /* Counter name */
|
||||||
bool hitcnt; /* Counter number read from ioctl() */
|
bool hitcnt; /* Counter number read from ioctl() */
|
||||||
unsigned long total; /* Total counter value */
|
unsigned long total; /* Total counter value */
|
||||||
@@ -240,7 +241,7 @@ static char *show_ctrset(unsigned long set)
|
|||||||
/* Parse CPU list and counter sets */
|
/* Parse CPU list and counter sets */
|
||||||
static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
|
static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
|
||||||
{
|
{
|
||||||
__u64 *words = start->cpumask;
|
uint64_t *words = start->cpumask;
|
||||||
unsigned long i, no_a, no_b;
|
unsigned long i, no_a, no_b;
|
||||||
char *cp, *tokens[16]; /* Used to parse command line params */
|
char *cp, *tokens[16]; /* Used to parse command line params */
|
||||||
char cpubuf[256];
|
char cpubuf[256];
|
||||||
@@ -275,8 +276,8 @@ static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
|
|||||||
show_ctrset(noton));
|
show_ctrset(noton));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(tokens) && (tokens[i] = strtok(parm, ",")) != 0;
|
for (i = 0; i < ARRAY_SIZE(tokens) && (tokens[i] = strtok(parm, ","));
|
||||||
++i, parm = 0) {
|
++i, parm = NULL) {
|
||||||
cp = strchr(tokens[i], '-'); /* Range character? */
|
cp = strchr(tokens[i], '-'); /* Range character? */
|
||||||
if (cp) {
|
if (cp) {
|
||||||
no_a = getnumber(tokens[i], *cp);
|
no_a = getnumber(tokens[i], *cp);
|
||||||
@@ -292,19 +293,13 @@ static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
|
|||||||
/* Convert the CPU list to a bitmask for kernel cpumask_t */
|
/* Convert the CPU list to a bitmask for kernel cpumask_t */
|
||||||
for (i = 0, no_b = 0; i < max_possible_cpus; ++i) {
|
for (i = 0, no_b = 0; i < max_possible_cpus; ++i) {
|
||||||
if (check[i].cpu_req) {
|
if (check[i].cpu_req) {
|
||||||
no_a = i % __BITS_PER_LONG;
|
no_a = i % LONG_BIT;
|
||||||
no_b = i / __BITS_PER_LONG;
|
no_b = i / LONG_BIT;
|
||||||
words[no_b] |= 1ULL << no_a;
|
words[no_b] |= 1ULL << no_a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* no_b is highest used index, swap array */
|
/* no_b is highest used index */
|
||||||
start->cpumask_len = (no_b + 1) * 8;
|
start->cpumask_len = (no_b + 1) * CHAR_BIT;
|
||||||
for (no_a = 0; no_a < no_b; ++no_a, --no_b) {
|
|
||||||
__u64 tmp = words[no_a];
|
|
||||||
|
|
||||||
words[no_a] = words[no_b];
|
|
||||||
words[no_b] = tmp;
|
|
||||||
}
|
|
||||||
start->version = S390_HWCTR_START_VERSION;
|
start->version = S390_HWCTR_START_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,7 +321,7 @@ static bool check_setpossible(void)
|
|||||||
}
|
}
|
||||||
parm = cpubuf;
|
parm = cpubuf;
|
||||||
for (i = 0; i < ARRAY_SIZE(tokens) && (tokens[i] = strtok(parm, ","));
|
for (i = 0; i < ARRAY_SIZE(tokens) && (tokens[i] = strtok(parm, ","));
|
||||||
++i, parm = 0) {
|
++i, parm = NULL) {
|
||||||
cp = strchr(tokens[i], '-');
|
cp = strchr(tokens[i], '-');
|
||||||
if (cp) { /* Range */
|
if (cp) { /* Range */
|
||||||
no_a = getnumber(tokens[i], *cp);
|
no_a = getnumber(tokens[i], *cp);
|
||||||
@@ -525,7 +520,7 @@ static int test_read(struct s390_hwctr_read *read)
|
|||||||
}
|
}
|
||||||
/* Iterate over all counters in each set */
|
/* Iterate over all counters in each set */
|
||||||
for (unsigned int k = 0; k < sp->no_cnts; ++k) {
|
for (unsigned int k = 0; k < sp->no_cnts; ++k) {
|
||||||
__u64 value;
|
uint64_t value;
|
||||||
void *addr = base + offset;
|
void *addr = base + offset;
|
||||||
size_t idx = ctrset_offset(sp->set) + k;
|
size_t idx = ctrset_offset(sp->set) + k;
|
||||||
|
|
||||||
@@ -608,8 +603,8 @@ static int do_it(char *s)
|
|||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
memset(&start, 0, sizeof(start));
|
memset(&start, 0, sizeof(start));
|
||||||
rc = max_possible_cpus / sizeof(__u64);
|
rc = max_possible_cpus / sizeof(uint64_t);
|
||||||
start.cpumask = alloca(max_possible_cpus / sizeof(__u64));
|
start.cpumask = alloca(max_possible_cpus / sizeof(uint64_t));
|
||||||
memset(start.cpumask, 0, rc);
|
memset(start.cpumask, 0, rc);
|
||||||
parse_cpulist(s, &start);
|
parse_cpulist(s, &start);
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
|||||||
+12
-11
@@ -13,6 +13,7 @@
|
|||||||
#ifndef LSHWC_H
|
#ifndef LSHWC_H
|
||||||
#define LSHWC_H
|
#define LSHWC_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@@ -58,27 +59,27 @@ enum {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct s390_hwctr_start { /* Set CPUs to operate on */
|
struct s390_hwctr_start { /* Set CPUs to operate on */
|
||||||
__u64 version; /* Version of interface */
|
uint64_t version; /* Version of interface */
|
||||||
__u64 data_bytes; /* # of bytes required */
|
uint64_t data_bytes; /* # of bytes required */
|
||||||
__u64 cpumask_len; /* Length of CPU mask in bytes */
|
uint64_t cpumask_len; /* Length of CPU mask in bytes */
|
||||||
__u64 *cpumask; /* Pointer to CPU mask */
|
uint64_t *cpumask; /* Pointer to CPU mask */
|
||||||
__u64 counter_sets; /* Bit mask of counter set to get */
|
uint64_t counter_sets; /* Bit mask of counter set to get */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct s390_hwctr_setdata { /* Counter set data */
|
struct s390_hwctr_setdata { /* Counter set data */
|
||||||
__u32 set; /* Counter set number */
|
uint32_t set; /* Counter set number */
|
||||||
__u32 no_cnts; /* # of counters stored in cv[] */
|
uint32_t no_cnts; /* # of counters stored in cv[] */
|
||||||
__u64 cv[0]; /* Counter values (variable length) */
|
uint64_t cv[0]; /* Counter values (variable length) */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct s390_hwctr_cpudata { /* Counter set data per CPU */
|
struct s390_hwctr_cpudata { /* Counter set data per CPU */
|
||||||
__u32 cpu_nr; /* Counter set number */
|
uint32_t cpu_nr; /* Counter set number */
|
||||||
__u32 no_sets; /* # of counters sets in data[] */
|
uint32_t no_sets; /* # of counters sets in data[] */
|
||||||
struct s390_hwctr_setdata data[0];
|
struct s390_hwctr_setdata data[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct s390_hwctr_read { /* Structure to get all ctr sets */
|
struct s390_hwctr_read { /* Structure to get all ctr sets */
|
||||||
__u64 no_cpus; /* Total # of CPUs data taken from */
|
uint64_t no_cpus; /* Total # of CPUs data taken from */
|
||||||
struct s390_hwctr_cpudata data[0];
|
struct s390_hwctr_cpudata data[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ static struct util_opt dump2tar_opts[] = {
|
|||||||
{
|
{
|
||||||
.option = { "file-timeout", required_argument, NULL, 'T' },
|
.option = { "file-timeout", required_argument, NULL, 'T' },
|
||||||
.desc = "Stop reading file after SEC seconds",
|
.desc = "Stop reading file after SEC seconds",
|
||||||
|
.argument = "SEC",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.option = { "file-max-size", required_argument, NULL, 'M' },
|
.option = { "file-max-size", required_argument, NULL, 'M' },
|
||||||
|
|||||||
@@ -28,13 +28,23 @@ static inline void __noreturn load_psw(struct psw_t psw)
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned long get_kernel_cmdline_size(void)
|
||||||
|
{
|
||||||
|
unsigned long size = *(volatile unsigned long *)MAX_COMMAND_LINE_SIZE;
|
||||||
|
|
||||||
|
if (size != 0)
|
||||||
|
return size;
|
||||||
|
|
||||||
|
return LEGACY_COMMAND_LINE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
void __noreturn start(void)
|
void __noreturn start(void)
|
||||||
{
|
{
|
||||||
volatile struct stage3b_args *args = &loader_parms;
|
volatile struct stage3b_args *args = &loader_parms;
|
||||||
volatile struct memblob *kernel = &args->kernel;
|
volatile struct memblob *kernel = &args->kernel;
|
||||||
volatile struct memblob *cmdline = &args->cmdline;
|
volatile struct memblob *cmdline = &args->cmdline;
|
||||||
volatile struct memblob *initrd = &args->initrd;
|
volatile struct memblob *initrd = &args->initrd;
|
||||||
volatile struct psw_t psw = args->psw;
|
struct psw_t psw = args->psw;
|
||||||
|
|
||||||
/* set up ASCII and line-mode */
|
/* set up ASCII and line-mode */
|
||||||
sclp_setup(SCLP_LINE_ASCII_INIT);
|
sclp_setup(SCLP_LINE_ASCII_INIT);
|
||||||
@@ -42,14 +52,14 @@ void __noreturn start(void)
|
|||||||
if (kernel->size < IMAGE_LOAD_ADDRESS)
|
if (kernel->size < IMAGE_LOAD_ADDRESS)
|
||||||
panic(EINTERNAL, "Invalid kernel\n");
|
panic(EINTERNAL, "Invalid kernel\n");
|
||||||
|
|
||||||
if (cmdline->size > COMMAND_LINE_SIZE)
|
|
||||||
panic(EINTERNAL, "Command line is too large\n");
|
|
||||||
|
|
||||||
/* move the kernel and cut the kernel header */
|
/* move the kernel and cut the kernel header */
|
||||||
memmove((void *)IMAGE_LOAD_ADDRESS,
|
memmove((void *)IMAGE_LOAD_ADDRESS,
|
||||||
(void *)(kernel->src + IMAGE_LOAD_ADDRESS),
|
(void *)(kernel->src + IMAGE_LOAD_ADDRESS),
|
||||||
kernel->size - IMAGE_LOAD_ADDRESS);
|
kernel->size - IMAGE_LOAD_ADDRESS);
|
||||||
|
|
||||||
|
if (cmdline->size > get_kernel_cmdline_size())
|
||||||
|
panic(EINTERNAL, "Command line is too large\n");
|
||||||
|
|
||||||
/* move the kernel cmdline */
|
/* move the kernel cmdline */
|
||||||
memmove((void *)COMMAND_LINE,
|
memmove((void *)COMMAND_LINE,
|
||||||
(void *)cmdline->src,
|
(void *)cmdline->src,
|
||||||
|
|||||||
@@ -248,19 +248,6 @@ gint pv_component_align(PvComponent *component, const gchar *tmp_path,
|
|||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert uint64_t address to byte array */
|
|
||||||
static void uint64_to_uint8_buf(uint8_t dst[8], uint64_t addr)
|
|
||||||
{
|
|
||||||
uint8_t *p = (uint8_t *)&addr;
|
|
||||||
|
|
||||||
g_assert(dst);
|
|
||||||
|
|
||||||
for (gint i = 0; i < 8; i++) {
|
|
||||||
/* cppcheck-suppress objectIndex */
|
|
||||||
dst[i] = p[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t pv_component_update_ald(const PvComponent *comp, EVP_MD_CTX *ctx,
|
int64_t pv_component_update_ald(const PvComponent *comp, EVP_MD_CTX *ctx,
|
||||||
GError **err)
|
GError **err)
|
||||||
{
|
{
|
||||||
@@ -273,11 +260,8 @@ int64_t pv_component_update_ald(const PvComponent *comp, EVP_MD_CTX *ctx,
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
uint64_t cur_be = GUINT64_TO_BE(cur);
|
uint64_t cur_be = GUINT64_TO_BE(cur);
|
||||||
uint8_t addr_buf[8];
|
|
||||||
|
|
||||||
uint64_to_uint8_buf(addr_buf, cur_be);
|
if (EVP_DigestUpdate(ctx, &cur_be, sizeof(cur_be)) != 1) {
|
||||||
|
|
||||||
if (EVP_DigestUpdate(ctx, addr_buf, sizeof(addr_buf)) != 1) {
|
|
||||||
g_set_error(err, PV_CRYPTO_ERROR,
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
PV_CRYPTO_ERROR_INTERNAL,
|
PV_CRYPTO_ERROR_INTERNAL,
|
||||||
_("EVP_DigestUpdate failed"));
|
_("EVP_DigestUpdate failed"));
|
||||||
|
|||||||
@@ -440,7 +440,7 @@ static int check_signature_algo_match(const EVP_PKEY *pkey, const X509 *subject,
|
|||||||
|
|
||||||
static X509_CRL *load_crl_from_bio(BIO *bio)
|
static X509_CRL *load_crl_from_bio(BIO *bio)
|
||||||
{
|
{
|
||||||
g_autoptr(X509_CRL) crl = PEM_read_bio_X509_CRL(bio, NULL, 0, NULL);
|
g_autoptr(X509_CRL) crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL);
|
||||||
gint rc;
|
gint rc;
|
||||||
|
|
||||||
if (crl)
|
if (crl)
|
||||||
|
|||||||
+6
-6
@@ -16,17 +16,17 @@ check_dep:
|
|||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
"hmcdrvfs", \
|
"hmcdrvfs", \
|
||||||
"fuse.h", \
|
"fuse.h", \
|
||||||
"fuse-devel or libfuse-dev", \
|
"fuse3-devel or libfuse3-dev", \
|
||||||
"HAVE_FUSE=0")
|
"HAVE_FUSE=0")
|
||||||
|
|
||||||
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
||||||
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse)
|
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse3)
|
||||||
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse)
|
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse3)
|
||||||
else
|
else
|
||||||
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse
|
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse3
|
||||||
FUSE_LDLIBS = -lfuse
|
FUSE_LDLIBS = -lfuse3
|
||||||
endif
|
endif
|
||||||
ALL_CFLAGS += -DFUSE_USE_VERSION=26 -D_LARGEFILE_SOURCE $(FUSE_CFLAGS)
|
ALL_CFLAGS += -DFUSE_USE_VERSION=30 -D_LARGEFILE_SOURCE $(FUSE_CFLAGS)
|
||||||
LDLIBS += $(FUSE_LDLIBS) -lpthread -lrt -ldl -lm
|
LDLIBS += $(FUSE_LDLIBS) -lpthread -lrt -ldl -lm
|
||||||
|
|
||||||
OBJECTS = hmcdrvfs.o
|
OBJECTS = hmcdrvfs.o
|
||||||
|
|||||||
@@ -111,9 +111,6 @@ allow access by other users
|
|||||||
.B -o allow_root
|
.B -o allow_root
|
||||||
allow access by root
|
allow access by root
|
||||||
.TP
|
.TP
|
||||||
.B -o nonempty
|
|
||||||
allow mounts over non-empty file/dir
|
|
||||||
.TP
|
|
||||||
.B -o default_permissions
|
.B -o default_permissions
|
||||||
enable permission checking by kernel
|
enable permission checking by kernel
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
+9
-6
@@ -990,7 +990,7 @@ static int hmcdrv_cache_dir(const char *dir, fuse_fill_dir_t filler, void *buf)
|
|||||||
hmcdrv_cache_refresh(path, &st, symlink);
|
hmcdrv_cache_refresh(path, &st, symlink);
|
||||||
|
|
||||||
if ((filler != NULL) &&
|
if ((filler != NULL) &&
|
||||||
(filler(buf, fname, &st, 0) != 0))
|
(filler(buf, fname, &st, 0, 0) != 0))
|
||||||
filler = NULL; /* stop filling */
|
filler = NULL; /* stop filling */
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
strftime(symlink, sizeof(symlink),
|
strftime(symlink, sizeof(symlink),
|
||||||
@@ -1109,7 +1109,8 @@ static struct hmcdrv_fuse_file *hmcdrv_file_get(const char *path)
|
|||||||
*
|
*
|
||||||
* Note: The most important function which FUSE calls (very often).
|
* Note: The most important function which FUSE calls (very often).
|
||||||
*/
|
*/
|
||||||
static int hmcdrv_fuse_getattr(const char *path, struct stat *stbuf)
|
static int hmcdrv_fuse_getattr(const char *path, struct stat *stbuf,
|
||||||
|
struct fuse_file_info *UNUSED(fi))
|
||||||
{
|
{
|
||||||
struct hmcdrv_fuse_file *fp;
|
struct hmcdrv_fuse_file *fp;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
@@ -1175,12 +1176,13 @@ static int hmcdrv_fuse_opendir(const char *UNUSED(path),
|
|||||||
*/
|
*/
|
||||||
static int hmcdrv_fuse_readdir(const char *path, void *buf,
|
static int hmcdrv_fuse_readdir(const char *path, void *buf,
|
||||||
fuse_fill_dir_t filler, off_t UNUSED(offset),
|
fuse_fill_dir_t filler, off_t UNUSED(offset),
|
||||||
struct fuse_file_info *UNUSED(fi))
|
struct fuse_file_info *UNUSED(fi),
|
||||||
|
enum fuse_readdir_flags UNUSED(flags))
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
filler(buf, ".", NULL, 0);
|
filler(buf, ".", NULL, 0, 0);
|
||||||
filler(buf, "..", NULL, 0);
|
filler(buf, "..", NULL, 0, 0);
|
||||||
|
|
||||||
pthread_mutex_lock(&hmcdrv_ctx.mutex);
|
pthread_mutex_lock(&hmcdrv_ctx.mutex);
|
||||||
ret = hmcdrv_cache_dir(path, filler, buf);
|
ret = hmcdrv_cache_dir(path, filler, buf);
|
||||||
@@ -1232,7 +1234,8 @@ static int hmcdrv_fuse_read(const char *path, char *buf, size_t size,
|
|||||||
* Return: value to be passed in the private_data field of fuse_context to
|
* Return: value to be passed in the private_data field of fuse_context to
|
||||||
* all file operations and as a parameter to the destroy() method
|
* all file operations and as a parameter to the destroy() method
|
||||||
*/
|
*/
|
||||||
static void *hmcdrv_fuse_init(struct fuse_conn_info *UNUSED(conn))
|
static void *hmcdrv_fuse_init(struct fuse_conn_info *UNUSED(conn),
|
||||||
|
struct fuse_config *UNUSED(cfg))
|
||||||
{
|
{
|
||||||
pthread_mutexattr_t attr;
|
pthread_mutexattr_t attr;
|
||||||
|
|
||||||
|
|||||||
+9
-7
@@ -23,11 +23,11 @@ else # HAVE_FUSE
|
|||||||
# FUSE
|
# FUSE
|
||||||
#
|
#
|
||||||
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
||||||
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse)
|
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse3)
|
||||||
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse)
|
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse3)
|
||||||
else
|
else
|
||||||
FUSE_CFLAGS = -I/usr/include/fuse
|
FUSE_CFLAGS = -I/usr/include/fuse3
|
||||||
FUSE_LDLIBS = -lfuse
|
FUSE_LDLIBS = -lfuse3
|
||||||
endif
|
endif
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -67,8 +67,10 @@ check-dep-fuse:
|
|||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
"hsavmcore", \
|
"hsavmcore", \
|
||||||
"fuse.h", \
|
"fuse.h", \
|
||||||
"fuse-devel or libfuse-dev", \
|
"fuse3-devel or libfuse3-dev", \
|
||||||
"HAVE_FUSE=0")
|
"HAVE_FUSE=0", \
|
||||||
|
"-DFUSE_USE_VERSION=30")
|
||||||
|
touch check-dep-fuse
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 hsavmcore \
|
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 hsavmcore \
|
||||||
@@ -81,6 +83,6 @@ install: all
|
|||||||
endif # HAVE_FUSE
|
endif # HAVE_FUSE
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f hsavmcore $(objects)
|
rm -f hsavmcore $(objects) check-dep-fuse
|
||||||
|
|
||||||
.PHONY: all install clean
|
.PHONY: all install clean
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ sudo reboot
|
|||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
sudo dnf install -y fuse fuse-devel systemd-devel
|
sudo dnf install -y fuse3 fuse3-devel systemd-devel
|
||||||
```
|
```
|
||||||
|
|
||||||
## Build hsavmcore
|
## Build hsavmcore
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ sudo reboot
|
|||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
sudo zypper install -y fuse fuse-devel systemd-devel
|
sudo zypper install -y fuse3 fuse3-devel systemd-devel
|
||||||
```
|
```
|
||||||
|
|
||||||
## Build hsavmcore
|
## Build hsavmcore
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
sudo apt-get install -y make gcc kdump-tools fuse libfuse-dev libsystemd-dev
|
sudo apt-get install -y make gcc kdump-tools fuse3 libfuse3-dev libsystemd-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
## Build hsavmcore
|
## Build hsavmcore
|
||||||
|
|||||||
+11
-6
@@ -15,7 +15,7 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define FUSE_USE_VERSION 26
|
#define FUSE_USE_VERSION 30
|
||||||
#include <fuse.h>
|
#include <fuse.h>
|
||||||
|
|
||||||
#include "lib/util_log.h"
|
#include "lib/util_log.h"
|
||||||
@@ -31,8 +31,11 @@ struct vmcore_overlay {
|
|||||||
bool fuse_debug;
|
bool fuse_debug;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int vmcore_fuse_getattr(const char *path, struct stat *stbuf)
|
static int vmcore_fuse_getattr(const char *path, struct stat *stbuf,
|
||||||
|
struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
|
(void)fi;
|
||||||
|
|
||||||
struct vmcore_overlay *overlay = fuse_get_context()->private_data;
|
struct vmcore_overlay *overlay = fuse_get_context()->private_data;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
@@ -54,18 +57,20 @@ static int vmcore_fuse_getattr(const char *path, struct stat *stbuf)
|
|||||||
|
|
||||||
static int vmcore_fuse_readdir(const char *path, void *buf,
|
static int vmcore_fuse_readdir(const char *path, void *buf,
|
||||||
fuse_fill_dir_t filler, off_t offset,
|
fuse_fill_dir_t filler, off_t offset,
|
||||||
struct fuse_file_info *fi)
|
struct fuse_file_info *fi,
|
||||||
|
enum fuse_readdir_flags flags)
|
||||||
{
|
{
|
||||||
(void)offset;
|
(void)offset;
|
||||||
(void)fi;
|
(void)fi;
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
if (strcmp(path, ROOT_DIR) != 0)
|
if (strcmp(path, ROOT_DIR) != 0)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
/* We have only one file */
|
/* We have only one file */
|
||||||
filler(buf, ".", NULL, 0);
|
filler(buf, ".", NULL, 0, 0);
|
||||||
filler(buf, "..", NULL, 0);
|
filler(buf, "..", NULL, 0, 0);
|
||||||
filler(buf, VMCORE_FILE, NULL, 0);
|
filler(buf, VMCORE_FILE, NULL, 0, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,11 +11,36 @@
|
|||||||
hsdev=""
|
hsdev=""
|
||||||
ndev=""
|
ndev=""
|
||||||
hsci=""
|
hsci=""
|
||||||
hsdev_mac=""
|
hscibr=""
|
||||||
|
hscibp=""
|
||||||
|
hsci_mac=""
|
||||||
hsif_pnetid=""
|
hsif_pnetid=""
|
||||||
netif_pnetid=""
|
netif_pnetid=""
|
||||||
hsci_pnetid=""
|
hsci_pnetid=""
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Concept:
|
||||||
|
# --------
|
||||||
|
# | hsci |
|
||||||
|
# --------
|
||||||
|
# / \
|
||||||
|
# -------- --------
|
||||||
|
# | ndev | | hsdev |
|
||||||
|
# -------- --------
|
||||||
|
#
|
||||||
|
# Detail (bridge w/ bridgeports):
|
||||||
|
# --------
|
||||||
|
# | hsci |
|
||||||
|
# --------
|
||||||
|
# |
|
||||||
|
# ----------------------
|
||||||
|
# | |hsci-bp| |
|
||||||
|
# | hsci-br --------- |
|
||||||
|
# | |
|
||||||
|
# -------- -------- |
|
||||||
|
# | ndev | | hsdev | |
|
||||||
|
# ----------------------
|
||||||
|
|
||||||
function usage {
|
function usage {
|
||||||
cat <<-EOD
|
cat <<-EOD
|
||||||
Usage: hsci COMMAND [OPTION]
|
Usage: hsci COMMAND [OPTION]
|
||||||
@@ -42,50 +67,53 @@ function prereqs_check {
|
|||||||
fi
|
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 {
|
function check_pnetids {
|
||||||
# get PNETID of the HS
|
if [ "$hsdev" != "" ]; then
|
||||||
local hsif_pnetids=""
|
hsif_pnetid="$(get_pnetid $hsdev)"
|
||||||
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)"
|
|
||||||
else
|
else
|
||||||
if [ -e /sys/class/net/$hsdev/device/chpid ]; then
|
hsif_pnetid=""
|
||||||
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
|
|
||||||
fi
|
fi
|
||||||
if [ "$hsif_pnetids" != "" ]; then
|
if [ "$ndev" != "" ]; then
|
||||||
port_hsif="$(cat /sys/class/net/$hsdev/dev_port)"
|
netif_pnetid="$(get_pnetid $ndev)"
|
||||||
(( 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)"
|
|
||||||
else
|
else
|
||||||
if [ -e /sys/class/net/$ndev/device/chpid ]; then
|
netif_pnetid=""
|
||||||
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 ' ')"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#Check PNETIDs
|
#Check PNETIDs
|
||||||
if [ "$hsif_pnetid" != "" ] && [ "$netif_pnetid" != "" ] && [ "$netif_pnetid" != "$hsif_pnetid" ]; then
|
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
|
echo "Error: $hsdev and $ndev have different PNETIDs! They are $hsif_pnetid and $netif_pnetid respectively" >&2
|
||||||
return 1
|
return 1
|
||||||
fi
|
else
|
||||||
|
if [ "$hsif_pnetid" != "" ]; then
|
||||||
if [ "$hsif_pnetid" != "" ] && [ "$netif_pnetid" != "" ] && [ "$netif_pnetid" == "$hsif_pnetid" ]; then
|
hsci_pnetid=$hsif_pnetid
|
||||||
hsci_pnetid=$hsif_pnetid
|
else
|
||||||
|
hsci_pnetid=$netif_pnetid
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,11 +124,11 @@ function verify_precon {
|
|||||||
echo "Error: $hsdev does not exist" >&2
|
echo "Error: $hsdev does not exist" >&2
|
||||||
return 1
|
return 1
|
||||||
fi
|
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
|
echo "Error: $hsdev is not a HiperSockets device" >&2
|
||||||
return 1
|
return 1
|
||||||
fi
|
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
|
echo "Error: $hsdev is not in layer 2 mode" >&2
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
@@ -108,7 +136,7 @@ function verify_precon {
|
|||||||
echo "Error: Missing vnic-characteristics support" >&2
|
echo "Error: Missing vnic-characteristics support" >&2
|
||||||
return 1
|
return 1
|
||||||
fi
|
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
|
echo "Error: $hsdev does not support vnicc" >&2
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
@@ -121,8 +149,10 @@ function verify_precon {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
if [ $(ip link show $hsdev | grep master | wc -l) -ne 0 ]; then
|
if [ $(ip link show $hsdev | grep master | wc -l) -ne 0 ]; then
|
||||||
echo "Error: $hsdev is already a bridge port" >&2
|
if [ $(ip link show $hsdev | grep "master $hsci" | wc -l) -eq 0 ]; then
|
||||||
return 1
|
echo "Error: $hsdev is already a subordinate to another master" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#Pre-verify net_dev
|
#Pre-verify net_dev
|
||||||
@@ -130,17 +160,15 @@ function verify_precon {
|
|||||||
echo "Error: $ndev does not exist" >&2
|
echo "Error: $ndev does not exist" >&2
|
||||||
return 1
|
return 1
|
||||||
fi
|
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
|
if [ $(ip link show $ndev | grep UP | wc -l) -eq 0 ]; then
|
||||||
echo "Error: $ndev is not in state UP" >&2
|
echo "Error: $ndev is not in state UP" >&2
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
if [ $(ip link show $ndev | grep master | wc -l) -ne 0 ]; then
|
if [ $(ip link show $ndev | grep master | wc -l) -ne 0 ]; then
|
||||||
echo "Error: $ndev is already a bridge port" >&2
|
if [ $(ip link show $ndev | grep "master $hsci" | wc -l) -eq 0 ]; then
|
||||||
return 1
|
echo "Error: $ndev is already a subordinate to another master" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#Check PNETIDs
|
#Check PNETIDs
|
||||||
@@ -153,10 +181,12 @@ function verify_precon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clean_up {
|
function clean_up {
|
||||||
|
ip link del $hsci >/dev/null 2>&1
|
||||||
bridge link set dev $hsdev learning_sync off self >/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
|
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
|
bridge fdb del $hsci_mac dev $hsdev self local >/dev/null 2>&1
|
||||||
ip link del $hsci >/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
|
hsdev=$1
|
||||||
ndev=$2
|
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 preconditions
|
||||||
verify_precon
|
verify_precon
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
return 1
|
return 1
|
||||||
fi
|
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"
|
echo "Adding $hsci with a HiperSockets dev $hsdev and an external dev $ndev"
|
||||||
|
|
||||||
#### Create bridge
|
#### Create bridge (idempotent)
|
||||||
ip link add name $hsci type bridge stp_state 0 >/dev/null 2>&1
|
if [ ! -e /sys/class/net/$hscibr ]; then
|
||||||
if [ $? -ne 0 ]; then
|
# ageing_time of $hscibr defaults to 30000 (300 secs)
|
||||||
echo "Error: Could not create a bridge" >&2
|
ip link add name $hscibr type bridge stp_state 0 >/dev/null 2>&1
|
||||||
return 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
|
fi
|
||||||
|
|
||||||
#### Prepare hsdev
|
#### Prepare hsdev
|
||||||
@@ -196,19 +237,24 @@ function add_hsci {
|
|||||||
echo 1 > /sys/class/net/$hsdev/device/vnicc/bridge_invisible
|
echo 1 > /sys/class/net/$hsdev/device/vnicc/bridge_invisible
|
||||||
|
|
||||||
#### Create bridge ports
|
#### 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
|
if [ $? -ne 0 ]; then
|
||||||
echo "Error: Could not set master for $ndev" >&2
|
echo "Error: Could not set master for $ndev" >&2
|
||||||
clean_up
|
clean_up
|
||||||
return 1
|
return 1
|
||||||
fi
|
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
|
if [ $? -ne 0 ]; then
|
||||||
echo "Error: Could not set master for $hsdev" >&2
|
echo "Error: Could not set master for $hsdev" >&2
|
||||||
clean_up
|
clean_up
|
||||||
return 1
|
return 1
|
||||||
fi
|
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
|
# no forwarding between ndev and hsdev -> isolated on
|
||||||
# ndev is default for outgoing unknown targets -> flood on
|
# ndev is default for outgoing unknown targets -> flood on
|
||||||
# no need to learn external LAN targets into fdb -> learning off
|
# no need to learn external LAN targets into fdb -> learning off
|
||||||
@@ -230,29 +276,102 @@ function add_hsci {
|
|||||||
clean_up
|
clean_up
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# NOTE: Although not required, BCs will be sent out on hsdev.
|
# 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.
|
# 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
|
ip link set dev $hscibr up >/dev/null 2>&1
|
||||||
bridge fdb add $hsdev_mac dev $ndev >/dev/null 2>&1
|
|
||||||
if [ $? -ne 0 ]; then
|
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
|
clean_up
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# set HS MAC (common MAC) on HSCI as primary MAC
|
#### Turn on device for bridge notification
|
||||||
ip link set address $hsdev_mac dev $hsci >/dev/null 2>&1
|
#### 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
|
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
|
clean_up
|
||||||
return 1
|
return 1
|
||||||
fi
|
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
|
ip link set dev $hsci up >/dev/null 2>&1
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "Error: Failed to set $hsci up" >&2
|
echo "Error: Failed to set $hsci up" >&2
|
||||||
@@ -260,14 +379,7 @@ function add_hsci {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Turn on device for bridge notification
|
echo "Added HSCI interface $hsci"
|
||||||
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"
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,51 +398,97 @@ function del_hsci {
|
|||||||
echo "Error: $hsci does not exit" >&2
|
echo "Error: $hsci does not exit" >&2
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
if [ $(ip link show | grep "master $hsci" | wc -l) -eq 0 ]; then
|
hsci_mac="$(cat /sys/class/net/$hsci/address)"
|
||||||
echo "Error: $hsci is not an active HSCI interface" >&2
|
|
||||||
return 1
|
#### 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
|
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
|
for bport in $bports; do
|
||||||
bport=${bport%:}
|
bport=${bport%:}
|
||||||
if [[ $bport == *@* ]]; then
|
bport=${bport%@*}
|
||||||
bport=${bport%@*}
|
if [ $(bridge -d link show dev $bport | grep "isolated on" | wc -l) -ne 0 ]; then
|
||||||
fi
|
if [ $(bridge -d link show dev $bport | grep "learning_sync on" | wc -l) -ne 0 ]; then
|
||||||
if [ $(bridge -d link show dev $bport | grep "learning_sync on" | wc -l) -ne 0 ]; then
|
hsdev=$bport
|
||||||
hsdev=$bport
|
else
|
||||||
else
|
ndev=$bport
|
||||||
ndev=$bport
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
if [ "$hsdev" == "" ]; then
|
if [ "$hsdev" == "" ]; then
|
||||||
echo "Error: $hsci has no active HiperSockets port" >&2
|
echo "Error: $hsci has no active HiperSockets port" >&2
|
||||||
return 1
|
|
||||||
fi
|
fi
|
||||||
echo "Deleting HSCI interface $hsci with the HiperSockets $hsdev and the external $ndev"
|
if [ "$ndev" == "" ]; then
|
||||||
|
echo "Error: $hsci has no active external port" >&2
|
||||||
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
|
|
||||||
fi
|
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
|
ip link del $hsci >/dev/null 2>&1
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "Error: Failed to delete $hsci" >&2
|
echo "Error: Failed to delete $hsci" >&2
|
||||||
return 1
|
|
||||||
fi
|
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
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,19 +496,63 @@ function del_hsci {
|
|||||||
## Show HSCI
|
## Show HSCI
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
function list_active {
|
function print_row {
|
||||||
hsdev=$1
|
if [ $mvp -eq 0 ]; then
|
||||||
local ext=""
|
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)}')"
|
function list_active {
|
||||||
ext="$(ip link show | grep "master $hsci" | grep --invert-match $hsdev | awk '{print $2}')"
|
hsci=""
|
||||||
# remove trailing ':'
|
hsdev=$1
|
||||||
ndev="${ext%:}"
|
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
|
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
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,13 +560,14 @@ function print_header {
|
|||||||
if [ $header -eq 0 ]; then
|
if [ $header -eq 0 ]; then
|
||||||
echo "HSCI PNET_ID HiperSockets External "
|
echo "HSCI PNET_ID HiperSockets External "
|
||||||
echo "------------------------------------------------------------"
|
echo "------------------------------------------------------------"
|
||||||
|
header=1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
function list_one {
|
function list_one {
|
||||||
local hsnetdev=$1
|
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
|
print_header
|
||||||
list_active $hsnetdev
|
list_active $hsnetdev
|
||||||
fi
|
fi
|
||||||
@@ -433,4 +636,3 @@ while true; do
|
|||||||
esac
|
esac
|
||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|||||||
@@ -23,10 +23,11 @@
|
|||||||
#define INITRD_SIZE _AC(0x10410, UL)
|
#define INITRD_SIZE _AC(0x10410, UL)
|
||||||
#define OLDMEM_BASE _AC(0x10418, UL)
|
#define OLDMEM_BASE _AC(0x10418, UL)
|
||||||
#define OLDMEM_SIZE _AC(0x10420, UL)
|
#define OLDMEM_SIZE _AC(0x10420, UL)
|
||||||
|
#define MAX_COMMAND_LINE_SIZE _AC(0x10430, UL)
|
||||||
#define COMMAND_LINE _AC(0x10480, UL)
|
#define COMMAND_LINE _AC(0x10480, UL)
|
||||||
|
|
||||||
/* Parameter sizes */
|
/* Parameter sizes */
|
||||||
#define COMMAND_LINE_SIZE 896
|
#define LEGACY_COMMAND_LINE_SIZE 896
|
||||||
|
|
||||||
|
|
||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
|
|||||||
@@ -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,
|
void util_hexdump_grp(FILE *fh, const char *tag, const void *data, int group,
|
||||||
int cnt, int indent);
|
int cnt, int indent);
|
||||||
void util_print_indented(const char *str, 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)
|
static inline void util_ptr_vec_free(void **ptr_vec, int count)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -52,6 +52,7 @@
|
|||||||
#define TOOLS_LIBDIR STRINGIFY (S390_TOOLS_LIBDIR)
|
#define TOOLS_LIBDIR STRINGIFY (S390_TOOLS_LIBDIR)
|
||||||
#define TOOLS_SYSCONFDIR STRINGIFY (S390_TOOLS_SYSCONFDIR)
|
#define TOOLS_SYSCONFDIR STRINGIFY (S390_TOOLS_SYSCONFDIR)
|
||||||
#define TOOLS_BINDIR STRINGIFY (S390_TOOLS_BINDIR)
|
#define TOOLS_BINDIR STRINGIFY (S390_TOOLS_BINDIR)
|
||||||
|
#define TOOLS_DATADIR STRINGIFY (S390_TOOLS_DATADIR)
|
||||||
|
|
||||||
#define __noreturn __attribute__((noreturn))
|
#define __noreturn __attribute__((noreturn))
|
||||||
#define __packed __attribute__((packed))
|
#define __packed __attribute__((packed))
|
||||||
|
|||||||
+1
-1
@@ -96,7 +96,7 @@ int dasd_sys_ese(char *devnode)
|
|||||||
return (rc == 1) ? 1 : 0;
|
return (rc == 1) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dasd_get_pm_from_chpid(char *busid, unsigned int chpid, int *mask)
|
static int dasd_get_pm_from_chpid(char *busid, unsigned int chpid, int *mask)
|
||||||
{
|
{
|
||||||
unsigned int val;
|
unsigned int val;
|
||||||
int count, i;
|
int count, i;
|
||||||
|
|||||||
+6
-4
@@ -47,6 +47,8 @@ detect-openssl-version.dep:
|
|||||||
echo "}" >> $(TMPFILE)
|
echo "}" >> $(TMPFILE)
|
||||||
mv $(TMPFILE) $@
|
mv $(TMPFILE) $@
|
||||||
|
|
||||||
|
CURL_CONFIG ?= curl-config
|
||||||
|
|
||||||
check-dep-libekmfweb: detect-openssl-version.dep
|
check-dep-libekmfweb: detect-openssl-version.dep
|
||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
"libekmfweb", \
|
"libekmfweb", \
|
||||||
@@ -64,8 +66,8 @@ check-dep-libekmfweb: detect-openssl-version.dep
|
|||||||
"curl/curl.h", \
|
"curl/curl.h", \
|
||||||
"libcurl-devel", \
|
"libcurl-devel", \
|
||||||
"HAVE_LIBCURL=0" \
|
"HAVE_LIBCURL=0" \
|
||||||
`curl-config --cflags` `curl-config --libs`)
|
`$(CURL_CONFIG) --cflags` `$(CURL_CONFIG) --libs`)
|
||||||
curl-config --ssl-backends | grep OpenSSL >/dev/null 2>&1 || { echo "Error: libcurl is not built with the OpenSSL backend"; exit 1; }
|
$(CURL_CONFIG) --ssl-backends | grep OpenSSL >/dev/null 2>&1 || { echo "Error: libcurl is not built with the OpenSSL backend"; exit 1; }
|
||||||
touch check-dep-libekmfweb
|
touch check-dep-libekmfweb
|
||||||
|
|
||||||
skip-libekmfweb-openssl:
|
skip-libekmfweb-openssl:
|
||||||
@@ -83,8 +85,8 @@ ekmfweb.o: check-dep-libekmfweb ekmfweb.c utilities.h cca.h $(rootdir)include/ek
|
|||||||
utilities.o: check-dep-libekmfweb utilities.c utilities.h $(rootdir)include/ekmfweb/ekmfweb.h
|
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
|
cca.o: check-dep-libekmfweb cca.c cca.h utilities.h $(rootdir)include/ekmfweb/ekmfweb.h
|
||||||
|
|
||||||
libekmfweb.so.$(VERSION): ALL_CFLAGS += -fPIC `curl-config --cflags`
|
libekmfweb.so.$(VERSION): ALL_CFLAGS += -fPIC `$(CURL_CONFIG) --cflags`
|
||||||
libekmfweb.so.$(VERSION): LDLIBS = -ljson-c -lcrypto -lssl `curl-config --libs` -ldl
|
libekmfweb.so.$(VERSION): LDLIBS = -ljson-c -lcrypto -lssl `$(CURL_CONFIG) --libs` -ldl
|
||||||
libekmfweb.so.$(VERSION): ALL_LDFLAGS += -shared -Wl,--version-script=libekmfweb.map \
|
libekmfweb.so.$(VERSION): ALL_LDFLAGS += -shared -Wl,--version-script=libekmfweb.map \
|
||||||
-Wl,-z,defs,-Bsymbolic -Wl,-soname,libekmfweb.so.$(VERM)
|
-Wl,-z,defs,-Bsymbolic -Wl,-soname,libekmfweb.so.$(VERM)
|
||||||
libekmfweb.so.$(VERSION): ekmfweb.o utilities.o cca.o $(libs)
|
libekmfweb.so.$(VERSION): ekmfweb.o utilities.o cca.o $(libs)
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ detect-openssl-version.dep:
|
|||||||
echo "}" >> $(TMPFILE)
|
echo "}" >> $(TMPFILE)
|
||||||
mv $(TMPFILE) $@
|
mv $(TMPFILE) $@
|
||||||
|
|
||||||
|
CURL_CONFIG ?= curl-config
|
||||||
|
XML2_CONFIG ?= xml2-config
|
||||||
|
|
||||||
check-dep-libkmipclient: detect-openssl-version.dep
|
check-dep-libkmipclient: detect-openssl-version.dep
|
||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
"libkmipclient", \
|
"libkmipclient", \
|
||||||
@@ -67,14 +70,14 @@ check-dep-libkmipclient: detect-openssl-version.dep
|
|||||||
"libxml/tree.h", \
|
"libxml/tree.h", \
|
||||||
"libxml2-devel", \
|
"libxml2-devel", \
|
||||||
"HAVE_LIBXML2=0", \
|
"HAVE_LIBXML2=0", \
|
||||||
`xml2-config --cflags` `xml2-config --libs`)
|
`$(XML2_CONFIG) --cflags` `$(XML2_CONFIG) --libs`)
|
||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
"libkmipclient", \
|
"libkmipclient", \
|
||||||
"curl/curl.h", \
|
"curl/curl.h", \
|
||||||
"libcurl-devel", \
|
"libcurl-devel", \
|
||||||
"HAVE_LIBCURL=0" \
|
"HAVE_LIBCURL=0" \
|
||||||
`curl-config --cflags` `curl-config --libs`)
|
`$(CURL_CONFIG) --cflags` `$(CURL_CONFIG) --libs`)
|
||||||
curl-config --ssl-backends | grep OpenSSL >/dev/null 2>&1 || { echo "Error: libcurl is not built with the OpenSSL backend"; exit 1; }
|
$(CURL_CONFIG) --ssl-backends | grep OpenSSL >/dev/null 2>&1 || { echo "Error: libcurl is not built with the OpenSSL backend"; exit 1; }
|
||||||
touch check-dep-libkmipclient
|
touch check-dep-libkmipclient
|
||||||
|
|
||||||
skip-libkmipclient-openssl:
|
skip-libkmipclient-openssl:
|
||||||
@@ -104,8 +107,8 @@ tls.o: check-dep-libkmipclient tls.c kmip.h utils.h $(rootdir)include/kmipclient
|
|||||||
names.o: check-dep-libkmipclient names.c names.h utils.h $(rootdir)include/kmipclient/kmipclient.h
|
names.o: check-dep-libkmipclient names.c names.h utils.h $(rootdir)include/kmipclient/kmipclient.h
|
||||||
utils.o: check-dep-libkmipclient utils.c names.h utils.h $(rootdir)include/kmipclient/kmipclient.h
|
utils.o: check-dep-libkmipclient utils.c names.h utils.h $(rootdir)include/kmipclient/kmipclient.h
|
||||||
|
|
||||||
libkmipclient.so.$(VERSION): ALL_CFLAGS += -fPIC `xml2-config --cflags` `curl-config --cflags`
|
libkmipclient.so.$(VERSION): ALL_CFLAGS += -fPIC `$(XML2_CONFIG) --cflags` `$(CURL_CONFIG) --cflags`
|
||||||
libkmipclient.so.$(VERSION): LDLIBS = -ljson-c -lcrypto -lssl `xml2-config --libs` `curl-config --libs`
|
libkmipclient.so.$(VERSION): LDLIBS = -ljson-c -lcrypto -lssl `$(XML2_CONFIG) --libs` `$(CURL_CONFIG) --libs`
|
||||||
libkmipclient.so.$(VERSION): ALL_LDFLAGS += -shared -Wl,--version-script=libkmipclient.map \
|
libkmipclient.so.$(VERSION): ALL_LDFLAGS += -shared -Wl,--version-script=libkmipclient.map \
|
||||||
-Wl,-z,defs,-Bsymbolic -Wl,-soname,libkmipclient.so.$(VERM)
|
-Wl,-z,defs,-Bsymbolic -Wl,-soname,libkmipclient.so.$(VERM)
|
||||||
libkmipclient.so.$(VERSION): kmip.o request.o response.o attribute.o key.o ttlv.o json.o \
|
libkmipclient.so.$(VERSION): kmip.o request.o response.o attribute.o key.o ttlv.o json.o \
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ int kmip_parse_hex(const char *str, bool has_prefix, unsigned char **val,
|
|||||||
{
|
{
|
||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
BIGNUM *b = NULL;
|
BIGNUM *b = NULL;
|
||||||
int len, rc;
|
int len;
|
||||||
|
|
||||||
if (str == NULL)
|
if (str == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -133,18 +133,20 @@ int kmip_parse_hex(const char *str, bool has_prefix, unsigned char **val,
|
|||||||
if (has_prefix && strncmp(str, "0x", 2) != 0)
|
if (has_prefix && strncmp(str, "0x", 2) != 0)
|
||||||
return -EBADMSG;
|
return -EBADMSG;
|
||||||
|
|
||||||
rc = BN_hex2bn(&b, str + (has_prefix ? 2 : 0));
|
len = BN_hex2bn(&b, str + (has_prefix ? 2 : 0));
|
||||||
if (rc <= 0)
|
if (len <= 0)
|
||||||
|
return -EBADMSG;
|
||||||
|
if (len < (int)strlen(str) - (has_prefix ? 2 : 0))
|
||||||
return -EBADMSG;
|
return -EBADMSG;
|
||||||
|
|
||||||
len = BN_num_bytes(b);
|
len = len / 2 + (len % 2 > 0 ? 1 : 0);
|
||||||
buf = calloc(1, len);
|
buf = calloc(1, len);
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
BN_free(b);
|
BN_free(b);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BN_bn2bin(b, buf) != len) {
|
if (BN_bn2binpad(b, buf, len) != len) {
|
||||||
BN_free(b);
|
BN_free(b);
|
||||||
free(buf);
|
free(buf);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "lib/util_base.h"
|
#include "lib/util_base.h"
|
||||||
@@ -91,3 +93,91 @@ void util_print_indented(const char *str, int indent)
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
free(desc_ptr);
|
free(desc_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the absolute name of an s390-tools system directory
|
||||||
|
* (it could be data, or library directory)
|
||||||
|
*/
|
||||||
|
static const char *util_sysdir(const char *env_var, const char *default_dir)
|
||||||
|
{
|
||||||
|
return secure_getenv(env_var) ?: default_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the absolute name of a file installed in the s390-tools
|
||||||
|
* system directory
|
||||||
|
*/
|
||||||
|
static const char *util_sysdir_path(const char *filename, const char *dirname)
|
||||||
|
{
|
||||||
|
static char libdir_pathname[PATH_MAX];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = snprintf(libdir_pathname, sizeof(libdir_pathname),
|
||||||
|
"%s/%s", dirname, filename);
|
||||||
|
|
||||||
|
if (ret < 0 || ret >= (int)sizeof(libdir_pathname))
|
||||||
|
errx(EXIT_FAILURE,
|
||||||
|
"Could not compose absolute pathname of %s and %s",
|
||||||
|
dirname, filename);
|
||||||
|
return libdir_pathname;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the absolute name of a s390-tools library directory
|
||||||
|
*
|
||||||
|
* Resources are handled by the library
|
||||||
|
*
|
||||||
|
* @returns Pointer to a buffer, which contains the null-terminated name
|
||||||
|
*/
|
||||||
|
const char *util_libdir(void)
|
||||||
|
{
|
||||||
|
return util_sysdir("S390TOOLS_LIBDIR", TOOLS_LIBDIR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the absolute name of a file installed in the s390-tools
|
||||||
|
* library directory by its relative name.
|
||||||
|
*
|
||||||
|
* Resources are handled by the library. A second call of this function
|
||||||
|
* overwrites previously returned data. Care must be taken when attempting
|
||||||
|
* to do a second call.
|
||||||
|
*
|
||||||
|
* @param[in] filename Null-terminated file name relative to the s390-tools
|
||||||
|
* library directory
|
||||||
|
* @returns Pointer to a buffer of PATH_MAX size, which contains the
|
||||||
|
* null-terminated absolute name
|
||||||
|
*/
|
||||||
|
const char *util_libdir_path(const char *filename)
|
||||||
|
{
|
||||||
|
return util_sysdir_path(filename, util_libdir());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the absolute name of a s390-tools data directory
|
||||||
|
*
|
||||||
|
* Resources are handled by the library
|
||||||
|
*
|
||||||
|
* @returns Pointer to a buffer which contains the null-terminated name
|
||||||
|
*/
|
||||||
|
const char *util_datadir(void)
|
||||||
|
{
|
||||||
|
return util_sysdir("S390TOOLS_DATADIR", TOOLS_DATADIR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the absolute name of a file installed in the s390-tools
|
||||||
|
* data directory by its relative name.
|
||||||
|
*
|
||||||
|
* Resources are handled by the library. A second call of this function
|
||||||
|
* overwrites previously returned data. Care must be taken when attempting
|
||||||
|
* to do a second call.
|
||||||
|
*
|
||||||
|
* @param[in] filename Null-terminated file name relative to the s390-tools
|
||||||
|
* data directory
|
||||||
|
* @returns Pointer to a buffer of PATH_MAX size, which contains the
|
||||||
|
* null-terminated absolute name
|
||||||
|
*/
|
||||||
|
const char *util_datadir_path(const char *filename)
|
||||||
|
{
|
||||||
|
return util_sysdir_path(filename, util_datadir());
|
||||||
|
}
|
||||||
|
|||||||
+3
-2
@@ -1,6 +1,7 @@
|
|||||||
include ../common.mak
|
include ../common.mak
|
||||||
|
|
||||||
SCRIPTS = dbginfo.sh zfcpdbf zipl-switch-to-blscfg scsi_logging_level
|
SCRIPTS = dbginfo.sh zfcpdbf zipl-switch-to-blscfg scsi_logging_level
|
||||||
|
SCRIPTS += sclpdbf
|
||||||
MAN_PAGES = dbginfo.sh.1 zfcpdbf.1 zipl-switch-to-blscfg.1
|
MAN_PAGES = dbginfo.sh.1 zfcpdbf.1 zipl-switch-to-blscfg.1
|
||||||
|
|
||||||
all:
|
all:
|
||||||
@@ -19,7 +20,7 @@ install:
|
|||||||
sed -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' cpictl > \
|
sed -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' cpictl > \
|
||||||
$(DESTDIR)$(TOOLS_LIBDIR)/cpictl
|
$(DESTDIR)$(TOOLS_LIBDIR)/cpictl
|
||||||
chown $(OWNER):$(GROUP) $(DESTDIR)$(TOOLS_LIBDIR)/cpictl
|
chown $(OWNER):$(GROUP) $(DESTDIR)$(TOOLS_LIBDIR)/cpictl
|
||||||
chmod 775 $(DESTDIR)$(TOOLS_LIBDIR)/cpictl
|
chmod 755 $(DESTDIR)$(TOOLS_LIBDIR)/cpictl
|
||||||
|
|
||||||
@for i in $(MAN_PAGES); \
|
@for i in $(MAN_PAGES); \
|
||||||
do \
|
do \
|
||||||
|
|||||||
+236
-9
@@ -24,6 +24,9 @@ readonly SYSTEM_NAME_PATH="/sys/firmware/cpi/system_name"
|
|||||||
readonly SYSPLEX_NAME_PATH="/sys/firmware/cpi/sysplex_name"
|
readonly SYSPLEX_NAME_PATH="/sys/firmware/cpi/sysplex_name"
|
||||||
readonly CPI_SET="/sys/firmware/cpi/set"
|
readonly CPI_SET="/sys/firmware/cpi/set"
|
||||||
|
|
||||||
|
# Location of os-release file - can be specified externally for testing purpose
|
||||||
|
readonly OS_RELEASE=${CPI_OS_RELEASE:-"/etc/os-release"}
|
||||||
|
|
||||||
declare LEVEL
|
declare LEVEL
|
||||||
declare TYPE
|
declare TYPE
|
||||||
declare NAME
|
declare NAME
|
||||||
@@ -37,6 +40,16 @@ readonly EXIT_FAILURE=1
|
|||||||
readonly EXIT_ARG_TOO_LONG=3
|
readonly EXIT_ARG_TOO_LONG=3
|
||||||
readonly EXIT_INVALID_CHARS=4
|
readonly EXIT_INVALID_CHARS=4
|
||||||
|
|
||||||
|
# Distro-IDs as supported by SE/HMC firmware
|
||||||
|
readonly DISTRO_GENERIC=0
|
||||||
|
readonly DISTRO_RHEL=1
|
||||||
|
readonly DISTRO_SLES=2
|
||||||
|
readonly DISTRO_UBUNTU=3
|
||||||
|
readonly DISTRO_FEDORA=4
|
||||||
|
readonly DISTRO_OPENSUSE=5
|
||||||
|
readonly DISTRO_DEBIAN=6
|
||||||
|
readonly DISTRO_RHCOS=7
|
||||||
|
|
||||||
print_help_and_exit()
|
print_help_and_exit()
|
||||||
{
|
{
|
||||||
cat <<EndHelp
|
cat <<EndHelp
|
||||||
@@ -49,7 +62,8 @@ Configure the Control-Program-Information (CPI) settings.
|
|||||||
sysplex name with values taken from environment
|
sysplex name with values taken from environment
|
||||||
variables
|
variables
|
||||||
-h, --help Print this help, then exit
|
-h, --help Print this help, then exit
|
||||||
-L, --level LEVEL Set and commit OS level to LEVEL (format xx.yy.zzABCD)
|
-L, --level LEVEL Set and commit OS level to LEVEL. Format: 0x<level> or
|
||||||
|
[[[flags:]distro_id:distro_version:]kernel_version]
|
||||||
-N, --name SYSTEM Set and commit the system name to SYSTEM
|
-N, --name SYSTEM Set and commit the system name to SYSTEM
|
||||||
-S, --sysplex SYSPLEX Set and commit the sysplex name to SYSPLEX
|
-S, --sysplex SYSPLEX Set and commit the sysplex name to SYSPLEX
|
||||||
-T, --type TYPE Set and commit OS type to TYPE
|
-T, --type TYPE Set and commit OS type to TYPE
|
||||||
@@ -109,7 +123,7 @@ fail_with()
|
|||||||
|
|
||||||
cpi_commit()
|
cpi_commit()
|
||||||
{
|
{
|
||||||
echo 1 > "$CPI_SET"
|
echo 1 > "$CPI_SET" 2> /dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
do_length_check()
|
do_length_check()
|
||||||
@@ -129,15 +143,228 @@ cpi_set_bit()
|
|||||||
LEVEL=$(printf '0x%x' $((LEVEL | (1 << (63 - $1)) )) )
|
LEVEL=$(printf '0x%x' $((LEVEL | (1 << (63 - $1)) )) )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# split_version - Split generic version string into array of sub-versions
|
||||||
|
#
|
||||||
|
# @version: Version string
|
||||||
|
# @delim: Characters that delimit sub-versions in version string
|
||||||
|
# @num: Number of sub-versions
|
||||||
|
#
|
||||||
|
# Print @num sub-versions of @version where each sub-version is delimited by
|
||||||
|
# any of the characters in @delim. Print 0 in place of non-decimal or missing
|
||||||
|
# sub-versions.
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
# version=10 delim=. num=3 => 10 0 0
|
||||||
|
# version=4.8 delim=. num=2 => 4 8
|
||||||
|
#
|
||||||
|
split_version()
|
||||||
|
{
|
||||||
|
local version="$1" delim="$2" num="$3"
|
||||||
|
local list i subver
|
||||||
|
|
||||||
|
IFS="$delim" read -r -a list <<< "$version"
|
||||||
|
|
||||||
|
for (( i=0; i<num; i++ )) ; do
|
||||||
|
subver="${list[i]:-0}"
|
||||||
|
# Handle non-number sub-versions
|
||||||
|
[[ "$subver" =~ ^[0-9]+$ ]] || subver=0
|
||||||
|
# Force decimal interpretation in case of leading zeroes
|
||||||
|
subver=$(( 10#$subver ))
|
||||||
|
printf "%s " "$subver"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# split_kver - Split Linux kernel version string into array of sub-versions
|
||||||
|
#
|
||||||
|
# @version: Linux kernel version string
|
||||||
|
# @num: Number of sub-versions
|
||||||
|
#
|
||||||
|
# Print @num sub-versions of the specified kernel @version. Print 0 in place
|
||||||
|
# of non-decimal or missing sub-versions.
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
# version=2.4-13 num=4 => 2 4 0 13
|
||||||
|
# version=3.0.93_3.0.101-0.8.2_0.8.1 num=6 => 3 0 93 3 0 101
|
||||||
|
# version=4.12.14-lp150.11.4 num=5 => 4 12 14 0 11
|
||||||
|
#
|
||||||
|
split_kver()
|
||||||
|
{
|
||||||
|
local version="$1" num="$2"
|
||||||
|
local main extra
|
||||||
|
|
||||||
|
# Separate extra version to handle short main version (e.g. 2.4-13)
|
||||||
|
IFS="-_" read -r main extra <<< "$version"
|
||||||
|
|
||||||
|
split_version "$main" "." $(( num > 3 ? 3 : num ))
|
||||||
|
[[ "$num" -gt 3 ]] && split_version "$extra" ".-_" $(( num - 3 ))
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# bytes_to_word - Convert byte array to hexadecimal word
|
||||||
|
#
|
||||||
|
# @bytes: List of numbers representing byte values
|
||||||
|
#
|
||||||
|
# Print a big-endian hexadecimal representation of the word that results from
|
||||||
|
# combining the specified byte values.
|
||||||
|
#
|
||||||
|
bytes_to_word()
|
||||||
|
{
|
||||||
|
printf "0x"
|
||||||
|
printf "%02x" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# get_system_level - Print system level word for specified distribution version
|
||||||
|
#
|
||||||
|
# @distro: Distro ID (ID value from /etc/os-release)
|
||||||
|
# @ver_str: Distro version string (VERSION_ID from /etc/os-release)
|
||||||
|
# @kver_str: Kernel version string (output of 'uname -r')
|
||||||
|
# @flags: Optional statistics flags
|
||||||
|
#
|
||||||
|
# Print a 64 bit hexadecimal system level in a format as understood by firmware.
|
||||||
|
#
|
||||||
|
# The format is 0xabccddeeeeffgghh, where
|
||||||
|
# - a=statistics flags
|
||||||
|
# - b=distro id
|
||||||
|
# - c=distro major version
|
||||||
|
# - d=distro minor version(s)
|
||||||
|
# - e=kernel sublevel 2
|
||||||
|
# - f=kernel version
|
||||||
|
# - g=kernel patchlevel
|
||||||
|
# - h=kernel sublevel 1
|
||||||
|
#
|
||||||
|
get_system_level()
|
||||||
|
{
|
||||||
|
local distro="$1" ver_str="$2" kver_str="$3" flags="${4:-0}"
|
||||||
|
local distro_id d_major d_minor d_minor2
|
||||||
|
local k_ver k_patchlvl k_sublvl k_sublvl2 bytes=()
|
||||||
|
|
||||||
|
# Extract list of sub-version numbers from version strings
|
||||||
|
read -r d_major d_minor d_minor2 <<< "$(split_version "$ver_str" "._-" 3)"
|
||||||
|
read -r k_ver k_patchlvl k_sublvl k_sublvl2 <<< "$(split_kver "$kver_str" 4)"
|
||||||
|
|
||||||
|
# Apply distro-specific logic
|
||||||
|
case "$distro" in
|
||||||
|
"rhel")
|
||||||
|
distro_id=$DISTRO_RHEL
|
||||||
|
;;
|
||||||
|
|
||||||
|
"sles")
|
||||||
|
distro_id=$DISTRO_SLES
|
||||||
|
;;
|
||||||
|
|
||||||
|
"ubuntu")
|
||||||
|
distro_id=$DISTRO_UBUNTU
|
||||||
|
|
||||||
|
# Encode minor and update version numbers in minor field
|
||||||
|
(( d_minor=((d_minor & 0xf) * 0x10) + (d_minor2 & 0xf) ))
|
||||||
|
;;
|
||||||
|
|
||||||
|
"fedora")
|
||||||
|
distro_id=$DISTRO_FEDORA
|
||||||
|
;;
|
||||||
|
|
||||||
|
"opensuse-leap")
|
||||||
|
distro_id=$DISTRO_OPENSUSE
|
||||||
|
;;
|
||||||
|
|
||||||
|
"debian")
|
||||||
|
distro_id=$DISTRO_DEBIAN
|
||||||
|
;;
|
||||||
|
|
||||||
|
"rhcos")
|
||||||
|
distro_id=$DISTRO_RHCOS
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
distro_id=$DISTRO_GENERIC
|
||||||
|
|
||||||
|
# Reset unsupported fields
|
||||||
|
d_major=0
|
||||||
|
d_minor=0
|
||||||
|
k_sublvl2=0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Assemble byte data
|
||||||
|
(( bytes[0] = (flags & 0xf) * 0x10 + distro_id ))
|
||||||
|
(( bytes[1] = d_major ))
|
||||||
|
(( bytes[2] = d_minor ))
|
||||||
|
(( bytes[3] = (k_sublvl2 / 256) & 0xff ))
|
||||||
|
(( bytes[4] = k_sublvl2 & 0xff ))
|
||||||
|
(( bytes[5] = k_ver ))
|
||||||
|
(( bytes[6] = k_patchlvl ))
|
||||||
|
(( bytes[7] = k_sublvl ))
|
||||||
|
|
||||||
|
# Print as single hex word
|
||||||
|
bytes_to_word "${bytes[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
get_distro()
|
||||||
|
{
|
||||||
|
local line ID="linux" VERSION_ID="0" VERSION="" update
|
||||||
|
|
||||||
|
[[ ! -e "$OS_RELEASE" ]] && return
|
||||||
|
|
||||||
|
# Only import required variables
|
||||||
|
while read -r line ; do
|
||||||
|
if [[ "$line" =~ ^ID= ]] || [[ "$line" =~ ^VERSION_ID= ]] ||
|
||||||
|
[[ "$line" =~ ^VERSION= ]] ; then
|
||||||
|
eval "$line"
|
||||||
|
fi
|
||||||
|
done <"$OS_RELEASE"
|
||||||
|
|
||||||
|
if [[ "$ID" == "ubuntu" ]] ; then
|
||||||
|
# Extract update version number only found in VERSION, e.g.
|
||||||
|
# VERSION_ID="18.04" VERSION="18.04.5 LTS"
|
||||||
|
update="${VERSION/*$VERSION_ID/}"
|
||||||
|
update="${update%% *}"
|
||||||
|
VERSION_ID="$VERSION_ID$update"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$ID:$VERSION_ID"
|
||||||
|
}
|
||||||
|
|
||||||
cpi_set_oslevel()
|
cpi_set_oslevel()
|
||||||
{
|
{
|
||||||
local kver=$(echo "${1:-$(uname -r)}" | grep -E -o '^[0-9]+[.][0-9]+[.][0-9]+')
|
local level="${1:-}"
|
||||||
local maj=$((${kver%%.*} % 256))
|
local flags list distro_id distro_ver kver id ver
|
||||||
local min=${kver#*.}
|
|
||||||
min=$((${min%.*} % 256))
|
if [[ "$level" =~ ^0x ]] && ! [[ "$level" =~ : ]] ; then
|
||||||
local rev=$((${kver##*.} % 256))
|
# Format: level=0x<hex>
|
||||||
local hexlevel=$(printf '0x%02x%02x%02x' $maj $min $rev)
|
printf -v LEVEL "0x%016x" "$level" 2>/dev/null ||
|
||||||
LEVEL=$(printf '0x%016x' $(((LEVEL & 0xFFFFFFFFFF000000) | hexlevel)))
|
fail_with "$PRG: Invalid hexadecimal number in $level" \
|
||||||
|
$EXIT_INVALID_CHARS
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Format: level=[[[flags:]distro_id:distro_ver:]kver]
|
||||||
|
IFS=":" read -r -a list <<< "$level:"
|
||||||
|
kver="${list[*]: -1: 1}"
|
||||||
|
distro_ver="${list[*]: -2: 1}"
|
||||||
|
distro_id="${list[*]: -3: 1}"
|
||||||
|
flags="${list[*]: -4: 1}"
|
||||||
|
|
||||||
|
if [[ -z "$kver" ]] ; then
|
||||||
|
# Use version of currently running kernel
|
||||||
|
kver="$(uname -r)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$distro_ver" ]] || [[ -z "$distro_id" ]] ; then
|
||||||
|
# Use distro ID and version from os-release file
|
||||||
|
IFS=":" read -r id ver <<< "$(get_distro)"
|
||||||
|
distro_id=${distro_id:-$id}
|
||||||
|
distro_ver=${distro_ver:-$ver}
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$flags" ]] ; then
|
||||||
|
# Keep statistics flags from current system level
|
||||||
|
flags=$(( (LEVEL >> 60) & 0xf ))
|
||||||
|
fi
|
||||||
|
|
||||||
|
LEVEL=$(get_system_level "$distro_id" "$distro_ver" "$kver" "$flags")
|
||||||
}
|
}
|
||||||
|
|
||||||
cpi_set_type()
|
cpi_set_type()
|
||||||
|
|||||||
+465
-495
File diff suppressed because it is too large
Load Diff
+40
-24
@@ -1,4 +1,4 @@
|
|||||||
.TH DBGINFO.SH 1 "April 2021" "s390-tools"
|
.TH DBGINFO.SH 1 "September 2021" "s390-tools"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
dbginfo.sh \- collect runtime, configuration and trace information
|
dbginfo.sh \- collect runtime, configuration and trace information
|
||||||
@@ -14,8 +14,10 @@ for debugging Linux on IBM Z
|
|||||||
This script collects runtime, configuration and trace information that can
|
This script collects runtime, configuration and trace information that can
|
||||||
be used to debug a Linux on IBM Z instance.
|
be used to debug a Linux on IBM Z instance.
|
||||||
For Linux on z/VM, the script also traces information about the z/VM system.
|
For Linux on z/VM, the script also traces information about the z/VM system.
|
||||||
|
KVM or DOCKER data ist collected on a host serving this.
|
||||||
|
|
||||||
The debug information is written to a file
|
The debug information is written to a file
|
||||||
/tmp/DBGINFO\-<date>\-<time>\-<hostname>\-<processorid>.tgz
|
/<DIRECTORY>/DBGINFO\-<date>\-<time>\-<hostname>\-<processorid>.tgz
|
||||||
where [date] and [time] are the date and time when the debug data was
|
where [date] and [time] are the date and time when the debug data was
|
||||||
collected. [hostname] indicates the hostname of the system the data was
|
collected. [hostname] indicates the hostname of the system the data was
|
||||||
collected from. The [processorid] is taken from the processor 0 and indicates
|
collected from. The [processorid] is taken from the processor 0 and indicates
|
||||||
@@ -32,7 +34,12 @@ Print version information, then exit.
|
|||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-d <DIRECTORY>\fP, \fB\-\-directory <DIRECTORY>\fP
|
\fB\-d <DIRECTORY>\fP, \fB\-\-directory <DIRECTORY>\fP
|
||||||
Specify the DIRECTORY where the data collection stores the temporary data and the final archive. The specified directory must already exist. If this parameter is not specified, /tmp is used by default.
|
Specify the DIRECTORY where the data collection stores the temporary data and the final archive.
|
||||||
|
The specified directory must already exist. If this parameter is not specified, /tmp is used by default.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-c\fP, \fB\-\-check\fP
|
||||||
|
Print online quick check (not saving any data) - can be combind with a preceding -d option.
|
||||||
|
|
||||||
.SH FILES
|
.SH FILES
|
||||||
A .tgz file of the form
|
A .tgz file of the form
|
||||||
@@ -56,48 +63,57 @@ Copyright IBM Corp. 2002, 2021
|
|||||||
.PP
|
.PP
|
||||||
Hardware platform = s390x
|
Hardware platform = s390x
|
||||||
.br
|
.br
|
||||||
Kernel version = 5.4.0 (5.4.0-70-generic)
|
|
||||||
.br
|
|
||||||
Runtime environment = z/VM
|
Runtime environment = z/VM
|
||||||
|
.br
|
||||||
|
Kernel version = 4.18.0 (4.18.0-305.el8.s390x)
|
||||||
|
.br
|
||||||
|
OS version / distro = Red Hat Enterprise Linux 8.4 (Ootpa)
|
||||||
|
.br
|
||||||
|
Date and time of info = 2021-08-26-15-27-58
|
||||||
.PP
|
.PP
|
||||||
1 of 16: Collecting command output
|
1 of 18: Collecting sysfs
|
||||||
.PP
|
.PP
|
||||||
2 of 16: Collecting z/VM command output
|
2 of 18: Collecting procfs
|
||||||
.PP
|
.PP
|
||||||
3 of 16: Collecting procfs
|
3 of 18: Collecting config files
|
||||||
.PP
|
.PP
|
||||||
4 of 16: Collecting sysfs
|
4 of 18: Collecting command output
|
||||||
.PP
|
.PP
|
||||||
5 of 16: Collecting log files
|
5 of 18: Collecting hyptop for z/VM - 5s output
|
||||||
.PP
|
.PP
|
||||||
6 of 16: Collecting config files
|
6 of 18: Collecting z/VM output
|
||||||
.PP
|
.PP
|
||||||
7 of 16: Collecting osa oat output
|
7 of 18: Collecting network output
|
||||||
.PP
|
.PP
|
||||||
8 of 16: Collecting ethtool output
|
8 of 18: Collecting osa oat output
|
||||||
.PP
|
.PP
|
||||||
9 of 16: Collecting tc output
|
9 of 18: Collecting ethtool output
|
||||||
.PP
|
.PP
|
||||||
10 of 16: Collecting bridge output
|
10 of 18: Collecting Trafic Control output
|
||||||
.PP
|
.PP
|
||||||
11 of 16: Collecting OpenVSwitch output
|
11 of 18: Collecting bridge output
|
||||||
.PP
|
.PP
|
||||||
12a of 16: Collecting docker container
|
12 of 18: Skip OpenVSwitch: ovs-vsctl not available
|
||||||
12b of 16: Collecting docker network
|
|
||||||
.PP
|
.PP
|
||||||
13 of 16: Collecting nvme output
|
13 of 18: Skip KVM: no virsh command
|
||||||
.PP
|
.PP
|
||||||
14 of 16: Collecting KVM data
|
14 of 18: Collecting docker output
|
||||||
.PP
|
.PP
|
||||||
15 of 16: Postprocessing
|
15 of 18: Collecting NVME storage output
|
||||||
.PP
|
.PP
|
||||||
16 of 16: Finalizing: Creating archive with collected data
|
16 of 18: Collecting log files
|
||||||
|
.PP
|
||||||
|
0 logfiles over 50 MB
|
||||||
|
.PP
|
||||||
|
17 of 18: Postprocessing
|
||||||
|
.PP
|
||||||
|
18 of 18: Finalizing: Creating archive with collected data
|
||||||
.PP
|
.PP
|
||||||
Collected data was saved to:
|
Collected data was saved to:
|
||||||
.br
|
.br
|
||||||
>> /data\-collection/DBGINFO\-2021\-04\-20\-14\-00\-07\-host\-012345.tgz <<
|
>> /data\-collection/DBGINFO\-2021\-08\-26\-15\-27\-58\-host\-012345.tgz <<
|
||||||
.br
|
.br
|
||||||
Review the collected data before sending to your service organization.
|
Please review all collected data before sending to your service organization.
|
||||||
.SH HINTS
|
.SH HINTS
|
||||||
Run the script with root authority.
|
Run the script with root authority.
|
||||||
.br
|
.br
|
||||||
|
|||||||
Executable
+1172
File diff suppressed because it is too large
Load Diff
+6
-7
@@ -887,14 +887,13 @@ sub print_scsi_common
|
|||||||
print "FCP rsp inf cod: 0x", substr($rec->[2], 44, 2), "\n";
|
print "FCP rsp inf cod: 0x", substr($rec->[2], 44, 2), "\n";
|
||||||
print "FCP rsp IU : ", payload_format(substr($rec->[2], 114, 48));
|
print "FCP rsp IU : ", payload_format(substr($rec->[2], 114, 48));
|
||||||
|
|
||||||
if (defined($pay_sns)) {
|
if ($payload_length && defined($pay_sns)) {
|
||||||
print "Sense len : ", $payload_length, "\n"
|
print "Sense len : ", $payload_length, "\n";
|
||||||
if ($payload_length);
|
print_payload($payload_length, $pay_sns, "Sense info");
|
||||||
print_payload($payload_length, $pay_sns, "Sense info")
|
} elsif ($payload_length) {
|
||||||
}
|
|
||||||
if (defined($pay_riu) && ($payload_length > FCP_RESP_WITH_EXT)) {
|
|
||||||
print "FCP rsp IU len : ", $payload_length, "\n";
|
print "FCP rsp IU len : ", $payload_length, "\n";
|
||||||
print_payload($payload_length, $pay_riu, "FCP rsp IU all");
|
print_payload($payload_length, $pay_riu, "FCP rsp IU all")
|
||||||
|
if ($payload_length > FCP_RESP_WITH_EXT);
|
||||||
}
|
}
|
||||||
print "\n";
|
print "\n";
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -1863,7 +1863,6 @@ static void close_ur_device(struct vmur *info)
|
|||||||
}
|
}
|
||||||
cpcmd_cs(cmd, &response, &cprc, 0);
|
cpcmd_cs(cmd, &response, &cprc, 0);
|
||||||
memcpy(spoolid, &response[9], 4);
|
memcpy(spoolid, &response[9], 4);
|
||||||
free(response);
|
|
||||||
if (cprc == 439) {
|
if (cprc == 439) {
|
||||||
if (info->action == PUNCH)
|
if (info->action == PUNCH)
|
||||||
sprintf(cmd, "PURGE * PUN %s", spoolid);
|
sprintf(cmd, "PURGE * PUN %s", spoolid);
|
||||||
@@ -1872,7 +1871,10 @@ static void close_ur_device(struct vmur *info)
|
|||||||
cpcmd(cmd, NULL, NULL, 0);
|
cpcmd(cmd, NULL, NULL, 0);
|
||||||
ERR_EXIT("User %s spool fileid limit exceeded.\n"
|
ERR_EXIT("User %s spool fileid limit exceeded.\n"
|
||||||
, info->user);
|
, info->user);
|
||||||
|
} else if (cprc) {
|
||||||
|
ERR_EXIT("CP command failed with rc=%i\n%s\n", cprc, response);
|
||||||
}
|
}
|
||||||
|
free(response);
|
||||||
if (info->rdr_specified) {
|
if (info->rdr_specified) {
|
||||||
if (info->node_specified)
|
if (info->node_specified)
|
||||||
printf("Reader file with spoolid %s created and "
|
printf("Reader file with spoolid %s created and "
|
||||||
|
|||||||
+9
-1
@@ -463,7 +463,15 @@ static int fill_io_devid(struct util_rec *rec, char *path)
|
|||||||
util_scandir_free(de_vec, count);
|
util_scandir_free(de_vec, count);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
strncpy(buf, "none", sizeof(buf));
|
if (util_file_read_line(buf, sizeof(buf), "%s/dev_busid",
|
||||||
|
path) == 0) {
|
||||||
|
if (cmd.opt_short) {
|
||||||
|
if (strncmp(buf, "0.0.", PREFIX_ID_LENGTH) != 0)
|
||||||
|
return 1;
|
||||||
|
memmove(buf, buf + PREFIX_ID_LENGTH,
|
||||||
|
(sizeof(buf) - PREFIX_ID_LENGTH));
|
||||||
|
}
|
||||||
|
}
|
||||||
fill_device_info(rec, NULL, NULL);
|
fill_device_info(rec, NULL, NULL);
|
||||||
}
|
}
|
||||||
if (cmd.opt_uppercase)
|
if (cmd.opt_uppercase)
|
||||||
|
|||||||
@@ -203,6 +203,7 @@ $(readlink -e $HOST_PATH)/-"
|
|||||||
|
|
||||||
read ONLINE < $ADAPTER_PATH/online
|
read ONLINE < $ADAPTER_PATH/online
|
||||||
read AVAILABILITY < $ADAPTER_PATH/availability
|
read AVAILABILITY < $ADAPTER_PATH/availability
|
||||||
|
[ -r "$SYSFS/class/fc_host/$SCSI_HOST/port_state" ] && read PORT_STATE < "$SYSFS/class/fc_host/$SCSI_HOST/port_state"
|
||||||
[ -r $ADAPTER_PATH/failed ] && read FAILED < $ADAPTER_PATH/failed
|
[ -r $ADAPTER_PATH/failed ] && read FAILED < $ADAPTER_PATH/failed
|
||||||
DEFUNCT=${ADAPTER_PATH%/*} # strip devbusid
|
DEFUNCT=${ADAPTER_PATH%/*} # strip devbusid
|
||||||
DEFUNCT=${DEFUNCT##*/} # basename
|
DEFUNCT=${DEFUNCT##*/} # basename
|
||||||
@@ -212,6 +213,8 @@ $(readlink -e $HOST_PATH)/-"
|
|||||||
HOSTMARKER=" defunct"
|
HOSTMARKER=" defunct"
|
||||||
elif [ "$ONLINE" = "0" ]; then
|
elif [ "$ONLINE" = "0" ]; then
|
||||||
HOSTMARKER=" offline"
|
HOSTMARKER=" offline"
|
||||||
|
elif [ "$PORT_STATE" = "Linkdown" ]; then
|
||||||
|
HOSTMARKER=" linkdown"
|
||||||
elif [ "$FAILED" = "1" ]; then
|
elif [ "$FAILED" = "1" ]; then
|
||||||
HOSTMARKER=" failed"
|
HOSTMARKER=" failed"
|
||||||
elif [ "$AVAILABILITY" != "good" ]; then
|
elif [ "$AVAILABILITY" != "good" ]; then
|
||||||
|
|||||||
+14
-2
@@ -115,6 +115,11 @@ Displays version information and exits.
|
|||||||
Here is an explanation of the columns displayed. Please note that some
|
Here is an explanation of the columns displayed. Please note that some
|
||||||
of the columns show up in verbose mode only.
|
of the columns show up in verbose mode only.
|
||||||
.TP
|
.TP
|
||||||
|
.B CARD.DOM
|
||||||
|
The crypto card number in hexadecimal for a crypto card line or
|
||||||
|
the crypto card number and the domain id both in hex separated by a single
|
||||||
|
dot for a queue line.
|
||||||
|
.TP
|
||||||
.B TYPE and HWTYPE
|
.B TYPE and HWTYPE
|
||||||
The HWTYPE is a numeric value showing which type of hardware the zcrypt
|
The HWTYPE is a numeric value showing which type of hardware the zcrypt
|
||||||
device driver presumes that this crypto card is. The currently known values
|
device driver presumes that this crypto card is. The currently known values
|
||||||
@@ -145,9 +150,16 @@ may be adjusted on the HMC or SE. The chzcrypt application can also
|
|||||||
trigger this state with the --config-on and --config-off options.
|
trigger this state with the --config-on and --config-off options.
|
||||||
.br
|
.br
|
||||||
lszcrypt shows 'online' when a card or queue is available for
|
lszcrypt shows 'online' when a card or queue is available for
|
||||||
cryptograhic operations. 'offline' is displayed when a card or queue
|
cryptographic operations. 'offline' is displayed when a card or queue
|
||||||
is switched to (software) offline. If a card is 'deconfigured' via
|
is switched to (software) offline. If a card is 'deconfigured' via
|
||||||
HMC, SE or chzcrypt the field shows 'deconfig'.
|
HMC, SE or chzcrypt the field shows 'deconfig'.
|
||||||
|
.br
|
||||||
|
If a queue is not bound to a device driver there is no detailed
|
||||||
|
information available and thus the status shows only '-'.
|
||||||
|
.br
|
||||||
|
If a queue is bound to the vfio-ap device driver it is up to this driver
|
||||||
|
to give some status information and what exactly this means. So lszcrypt
|
||||||
|
shows the text retrieved from the underlying sysfs attribute here.
|
||||||
.TP
|
.TP
|
||||||
.B REQUESTS
|
.B REQUESTS
|
||||||
This is the counter value of successful processed requests on card or queue
|
This is the counter value of successful processed requests on card or queue
|
||||||
@@ -168,7 +180,7 @@ S - APSC available: card/queue can handle requests with the special bit
|
|||||||
enabled.
|
enabled.
|
||||||
.br
|
.br
|
||||||
M - Accelerator card/queue with support for RSA ME with up to 4k key size.
|
M - Accelerator card/queue with support for RSA ME with up to 4k key size.
|
||||||
.br
|
.Sr
|
||||||
C - Accelerator card/queue with support for RSA CRT with up to 4k key size.
|
C - Accelerator card/queue with support for RSA CRT with up to 4k key size.
|
||||||
.br
|
.br
|
||||||
D - Card/queue is providing CCA functions (this is the CCA Coprocessor mode).
|
D - Card/queue is providing CCA functions (this is the CCA Coprocessor mode).
|
||||||
|
|||||||
+122
-68
@@ -22,6 +22,8 @@
|
|||||||
#include "lib/util_scandir.h"
|
#include "lib/util_scandir.h"
|
||||||
#include "lib/zt_common.h"
|
#include "lib/zt_common.h"
|
||||||
|
|
||||||
|
#include "misc.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Private data
|
* Private data
|
||||||
*/
|
*/
|
||||||
@@ -331,13 +333,49 @@ static void show_capability(const char *id_str)
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read driver entry in dir or in dir/subdir and store driver into buf.
|
||||||
|
* Returns:
|
||||||
|
* 0 if there is no driver link (no driver bound to this device or error)
|
||||||
|
* 1 if one of the cexXcard or cexXqueue driver is bound to this device
|
||||||
|
* 2 if the vfio is bound to this device
|
||||||
|
*/
|
||||||
|
static int read_driver(const char *dir, const char *subdir, char *buf, size_t buflen)
|
||||||
|
{
|
||||||
|
char drvlink[PATH_MAX], linktarget[PATH_MAX];
|
||||||
|
char *p, driver[256];
|
||||||
|
|
||||||
|
if (subdir)
|
||||||
|
snprintf(drvlink, sizeof(drvlink), "%s/%s/driver", dir, subdir);
|
||||||
|
else
|
||||||
|
snprintf(drvlink, sizeof(drvlink), "%s/driver", dir);
|
||||||
|
drvlink[sizeof(drvlink) - 1] = '\0';
|
||||||
|
|
||||||
|
memset(linktarget, 0, sizeof(linktarget));
|
||||||
|
|
||||||
|
if (readlink(drvlink, linktarget, sizeof(linktarget)) > 0) {
|
||||||
|
p = strrchr(linktarget, '/');
|
||||||
|
if (p) {
|
||||||
|
strncpy(driver, p + 1, sizeof(driver));
|
||||||
|
driver[sizeof(driver) - 1] = '\0';
|
||||||
|
strncpy(buf, driver, buflen);
|
||||||
|
if (misc_regex_match(driver, "cex[0-9](card|queue)"))
|
||||||
|
return 1;
|
||||||
|
else if (misc_regex_match(driver, "vfio.ap"))
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read subdevice default attributes
|
* Read subdevice default attributes
|
||||||
*/
|
*/
|
||||||
static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
|
static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
|
||||||
const char *sub_dev)
|
const char *sub_dev)
|
||||||
{
|
{
|
||||||
long value;
|
long config = -1, online = -1;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
unsigned long facility;
|
unsigned long facility;
|
||||||
|
|
||||||
@@ -346,24 +384,29 @@ static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
|
|||||||
else
|
else
|
||||||
util_rec_set(rec, "type", buf);
|
util_rec_set(rec, "type", buf);
|
||||||
|
|
||||||
if (util_path_is_readable("%s/%s/online", grp_dev, sub_dev)) {
|
if (util_path_is_readable("%s/%s/config", grp_dev, sub_dev))
|
||||||
util_file_read_l(&value, 10, "%s/%s/online", grp_dev, sub_dev);
|
util_file_read_l(&config, 10, "%s/%s/config", grp_dev, sub_dev);
|
||||||
if (value > 0)
|
if (util_path_is_readable("%s/%s/online", grp_dev, sub_dev))
|
||||||
util_rec_set(rec, "online", "online");
|
util_file_read_l(&online, 10, "%s/%s/online", grp_dev, sub_dev);
|
||||||
else {
|
|
||||||
/* device is offline, check config (if available) */
|
util_rec_set(rec, "status", "-");
|
||||||
if (util_path_is_readable("%s/%s/config", grp_dev, sub_dev)) {
|
if (config == 0) {
|
||||||
util_file_read_l(&value, 10, "%s/%s/config", grp_dev, sub_dev);
|
util_rec_set(rec, "status", "deconfig");
|
||||||
if (value > 0)
|
|
||||||
util_rec_set(rec, "online", "offline");
|
|
||||||
else
|
|
||||||
util_rec_set(rec, "online", "deconfig");
|
|
||||||
} else
|
|
||||||
util_rec_set(rec, "online", "offline");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
/* no online attribute */
|
if (online > 0)
|
||||||
util_rec_set(rec, "online", "-");
|
util_rec_set(rec, "status", "online");
|
||||||
|
else if (online == 0)
|
||||||
|
util_rec_set(rec, "status", "offline");
|
||||||
|
else {
|
||||||
|
/* no online attribute, maybe use status attribute */
|
||||||
|
if (util_path_is_readable("%s/%s/status",
|
||||||
|
grp_dev, sub_dev)) {
|
||||||
|
util_file_read_line(buf, sizeof(buf),
|
||||||
|
"%s/%s/status",
|
||||||
|
grp_dev, sub_dev);
|
||||||
|
util_rec_set(rec, "status", buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
util_file_read_ul(&facility, 16, "%s/ap_functions", grp_dev);
|
util_file_read_ul(&facility, 16, "%s/ap_functions", grp_dev);
|
||||||
@@ -376,9 +419,13 @@ static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
|
|||||||
else
|
else
|
||||||
util_rec_set(rec, "mode", "Unknown");
|
util_rec_set(rec, "mode", "Unknown");
|
||||||
|
|
||||||
util_file_read_line(buf, sizeof(buf), "%s/%s/request_count",
|
if (config == 0) {
|
||||||
grp_dev, sub_dev);
|
util_rec_set(rec, "requests", "-");
|
||||||
util_rec_set(rec, "requests", buf);
|
} else {
|
||||||
|
util_file_read_line(buf, sizeof(buf), "%s/%s/request_count",
|
||||||
|
grp_dev, sub_dev);
|
||||||
|
util_rec_set(rec, "requests", buf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -387,19 +434,29 @@ static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
|
|||||||
static void read_subdev_rec_verbose(struct util_rec *rec, const char *grp_dev,
|
static void read_subdev_rec_verbose(struct util_rec *rec, const char *grp_dev,
|
||||||
const char *sub_dev)
|
const char *sub_dev)
|
||||||
{
|
{
|
||||||
int i;
|
int i, drvinfo;
|
||||||
unsigned long facility;
|
unsigned long facility;
|
||||||
char buf[256], afile[PATH_MAX];
|
char buf[256];
|
||||||
long depth, pending1, pending2;
|
long depth, pending1, pending2, config = -1;
|
||||||
|
|
||||||
if (l.verbose == 0)
|
if (l.verbose == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
util_file_read_l(&pending1, 10, "%s/%s/pendingq_count",
|
drvinfo = read_driver(grp_dev, sub_dev, buf, sizeof(buf));
|
||||||
grp_dev, sub_dev);
|
util_rec_set(rec, "driver", drvinfo > 0 ? buf : "-no-driver-");
|
||||||
util_file_read_l(&pending2, 10, "%s/%s/requestq_count",
|
|
||||||
grp_dev, sub_dev);
|
if (util_path_is_readable("%s/config", grp_dev))
|
||||||
util_rec_set(rec, "pending", "%ld", pending1 + pending2);
|
util_file_read_l(&config, 10, "%s/config", grp_dev);
|
||||||
|
|
||||||
|
if (config == 0 || drvinfo != 1) {
|
||||||
|
util_rec_set(rec, "pending", "-");
|
||||||
|
} else {
|
||||||
|
util_file_read_l(&pending1, 10, "%s/%s/pendingq_count",
|
||||||
|
grp_dev, sub_dev);
|
||||||
|
util_file_read_l(&pending2, 10, "%s/%s/requestq_count",
|
||||||
|
grp_dev, sub_dev);
|
||||||
|
util_rec_set(rec, "pending", "%ld", pending1 + pending2);
|
||||||
|
}
|
||||||
|
|
||||||
util_file_read_line(buf, sizeof(buf), "%s/hwtype", grp_dev);
|
util_file_read_line(buf, sizeof(buf), "%s/hwtype", grp_dev);
|
||||||
util_rec_set(rec, "hwtype", buf);
|
util_rec_set(rec, "hwtype", buf);
|
||||||
@@ -412,14 +469,6 @@ static void read_subdev_rec_verbose(struct util_rec *rec, const char *grp_dev,
|
|||||||
buf[i] = facility & fac_bits[i].mask ? fac_bits[i].c : '-';
|
buf[i] = facility & fac_bits[i].mask ? fac_bits[i].c : '-';
|
||||||
buf[i] = '\0';
|
buf[i] = '\0';
|
||||||
util_rec_set(rec, "facility", buf);
|
util_rec_set(rec, "facility", buf);
|
||||||
|
|
||||||
snprintf(afile, sizeof(afile), "%s/%s/driver", grp_dev, sub_dev);
|
|
||||||
afile[sizeof(afile) - 1] = '\0';
|
|
||||||
memset(buf, 0, sizeof(buf));
|
|
||||||
if (readlink(afile, buf, sizeof(buf)) > 0)
|
|
||||||
util_rec_set(rec, "driver", strrchr(buf, '/') + 1);
|
|
||||||
else
|
|
||||||
util_rec_set(rec, "driver", "-no-driver-");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -467,7 +516,7 @@ static void show_subdevices(struct util_rec *rec, const char *grp_dev)
|
|||||||
*/
|
*/
|
||||||
static void read_rec_default(struct util_rec *rec, const char *grp_dev)
|
static void read_rec_default(struct util_rec *rec, const char *grp_dev)
|
||||||
{
|
{
|
||||||
long value;
|
long config = -1, online = -1;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
unsigned long facility;
|
unsigned long facility;
|
||||||
|
|
||||||
@@ -486,24 +535,27 @@ static void read_rec_default(struct util_rec *rec, const char *grp_dev)
|
|||||||
else
|
else
|
||||||
util_rec_set(rec, "mode", "Unknown");
|
util_rec_set(rec, "mode", "Unknown");
|
||||||
|
|
||||||
if (util_path_is_readable("%s/online", grp_dev)) {
|
if (util_path_is_readable("%s/config", grp_dev))
|
||||||
util_file_read_l(&value, 10, "%s/online", grp_dev);
|
util_file_read_l(&config, 10, "%s/config", grp_dev);
|
||||||
if (value > 0)
|
if (util_path_is_readable("%s/online", grp_dev))
|
||||||
util_rec_set(rec, "online", "online");
|
util_file_read_l(&online, 10, "%s/online", grp_dev);
|
||||||
else {
|
if (config == 0) {
|
||||||
if (util_path_is_readable("%s/config", grp_dev)) {
|
util_rec_set(rec, "status", "deconfig");
|
||||||
util_file_read_l(&value, 10, "%s/config", grp_dev);
|
} else {
|
||||||
if (value > 0)
|
if (online > 0)
|
||||||
util_rec_set(rec, "online", "offline");
|
util_rec_set(rec, "status", "online");
|
||||||
else
|
else if (online == 0)
|
||||||
util_rec_set(rec, "online", "deconfig");
|
util_rec_set(rec, "status", "offline");
|
||||||
} else
|
else
|
||||||
util_rec_set(rec, "online", "offline");
|
util_rec_set(rec, "status", "-");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
util_file_read_line(buf, sizeof(buf), "%s/request_count", grp_dev);
|
if (config == 0) {
|
||||||
util_rec_set(rec, "requests", buf);
|
util_rec_set(rec, "requests", "-");
|
||||||
|
} else {
|
||||||
|
util_file_read_line(buf, sizeof(buf), "%s/request_count", grp_dev);
|
||||||
|
util_rec_set(rec, "requests", buf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -513,15 +565,22 @@ static void read_rec_verbose(struct util_rec *rec, const char *grp_dev)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned long facility;
|
unsigned long facility;
|
||||||
char buf[256], afile[PATH_MAX];
|
char buf[256];
|
||||||
long depth, pending1, pending2;
|
long depth, pending1, pending2, config = -1;
|
||||||
|
|
||||||
if (l.verbose == 0)
|
if (l.verbose == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
util_file_read_l(&pending1, 10, "%s/pendingq_count", grp_dev);
|
if (util_path_is_readable("%s/config", grp_dev))
|
||||||
util_file_read_l(&pending2, 10, "%s/requestq_count", grp_dev);
|
util_file_read_l(&config, 10, "%s/config", grp_dev);
|
||||||
util_rec_set(rec, "pending", "%ld", pending1 + pending2);
|
|
||||||
|
if (config == 0) {
|
||||||
|
util_rec_set(rec, "pending", "-");
|
||||||
|
} else {
|
||||||
|
util_file_read_l(&pending1, 10, "%s/pendingq_count", grp_dev);
|
||||||
|
util_file_read_l(&pending2, 10, "%s/requestq_count", grp_dev);
|
||||||
|
util_rec_set(rec, "pending", "%ld", pending1 + pending2);
|
||||||
|
}
|
||||||
|
|
||||||
util_file_read_line(buf, sizeof(buf), "%s/hwtype", grp_dev);
|
util_file_read_line(buf, sizeof(buf), "%s/hwtype", grp_dev);
|
||||||
util_rec_set(rec, "hwtype", buf);
|
util_rec_set(rec, "hwtype", buf);
|
||||||
@@ -535,13 +594,8 @@ static void read_rec_verbose(struct util_rec *rec, const char *grp_dev)
|
|||||||
buf[i] = '\0';
|
buf[i] = '\0';
|
||||||
util_rec_set(rec, "facility", buf);
|
util_rec_set(rec, "facility", buf);
|
||||||
|
|
||||||
snprintf(afile, sizeof(afile), "%s/driver", grp_dev);
|
i = read_driver(grp_dev, NULL, buf, sizeof(buf));
|
||||||
afile[sizeof(afile) - 1] = '\0';
|
util_rec_set(rec, "driver", i > 0 ? buf : "-no-driver-");
|
||||||
memset(buf, 0, sizeof(buf));
|
|
||||||
if (readlink(afile, buf, sizeof(buf)) > 0)
|
|
||||||
util_rec_set(rec, "driver", strrchr(buf, '/') + 1);
|
|
||||||
else
|
|
||||||
util_rec_set(rec, "driver", "-no-driver-");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -581,10 +635,10 @@ out_free:
|
|||||||
*/
|
*/
|
||||||
static void define_rec_default(struct util_rec *rec)
|
static void define_rec_default(struct util_rec *rec)
|
||||||
{
|
{
|
||||||
util_rec_def(rec, "card", UTIL_REC_ALIGN_LEFT, 11, "CARD.DOMAIN");
|
util_rec_def(rec, "card", UTIL_REC_ALIGN_LEFT, 8, "CARD.DOM");
|
||||||
util_rec_def(rec, "type", UTIL_REC_ALIGN_LEFT, 5, "TYPE");
|
util_rec_def(rec, "type", UTIL_REC_ALIGN_LEFT, 5, "TYPE");
|
||||||
util_rec_def(rec, "mode", UTIL_REC_ALIGN_LEFT, 11, "MODE");
|
util_rec_def(rec, "mode", UTIL_REC_ALIGN_LEFT, 11, "MODE");
|
||||||
util_rec_def(rec, "online", UTIL_REC_ALIGN_LEFT, 8, "STATUS");
|
util_rec_def(rec, "status", UTIL_REC_ALIGN_LEFT, 10, "STATUS");
|
||||||
util_rec_def(rec, "requests", UTIL_REC_ALIGN_RIGHT, 8, "REQUESTS");
|
util_rec_def(rec, "requests", UTIL_REC_ALIGN_RIGHT, 8, "REQUESTS");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ all:
|
|||||||
install: all
|
install: all
|
||||||
$(MAKE) -C src install
|
$(MAKE) -C src install
|
||||||
$(MAKE) -C man install
|
$(MAKE) -C man install
|
||||||
|
$(MAKE) -C udev install
|
||||||
$(MAKE) -C dracut install
|
$(MAKE) -C dracut install
|
||||||
$(MAKE) -C initramfs install
|
$(MAKE) -C initramfs install
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ check() {
|
|||||||
[ "$_arch" = "s390" -o "$_arch" = "s390x" ] || return 1
|
[ "$_arch" = "s390" -o "$_arch" = "s390x" ] || return 1
|
||||||
|
|
||||||
# Ensure that required tools are available
|
# Ensure that required tools are available
|
||||||
require_binaries chzdev lszdev || return 1
|
require_binaries chzdev lszdev /lib/s390-tools/zdev_id || return 1
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -40,11 +40,14 @@ install() {
|
|||||||
local _tempfile
|
local _tempfile
|
||||||
|
|
||||||
# Ensure that required tools are available
|
# Ensure that required tools are available
|
||||||
inst_multiple chzdev lszdev vmcp
|
inst_multiple chzdev lszdev vmcp /lib/s390-tools/zdev_id
|
||||||
|
|
||||||
# Hook to parse zdev kernel parameter
|
# Hook to parse zdev kernel parameter
|
||||||
inst_hook cmdline 95 "$moddir/parse-zdev.sh"
|
inst_hook cmdline 95 "$moddir/parse-zdev.sh"
|
||||||
|
|
||||||
|
# Rule to automatically enable devices when running in DPM
|
||||||
|
inst_rules "81-dpm.rules"
|
||||||
|
|
||||||
# Obtain early + root device configuration
|
# Obtain early + root device configuration
|
||||||
_tempfile=$(mktemp --tmpdir dracut-zdev.XXXXXX)
|
_tempfile=$(mktemp --tmpdir dracut-zdev.XXXXXX)
|
||||||
chzdev --export "$_tempfile" --persistent --by-path / --quiet \
|
chzdev --export "$_tempfile" --persistent --by-path / --quiet \
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
# Copyright IBM Corp. 2017
|
# Copyright IBM Corp. 2017,2021
|
||||||
#
|
#
|
||||||
# s390-tools is free software; you can redistribute it and/or modify
|
# s390-tools is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the MIT license. See LICENSE for details.
|
# it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -15,11 +15,14 @@
|
|||||||
# where
|
# where
|
||||||
#
|
#
|
||||||
# no-auto: Indicates that firmware-provided I/O configuration data
|
# no-auto: Indicates that firmware-provided I/O configuration data
|
||||||
# should not be applied.
|
# should not be applied. This also affects automatic
|
||||||
|
# activation of PCI and crypto devices when running in a DPM
|
||||||
|
# LPAR.
|
||||||
#
|
#
|
||||||
|
|
||||||
zdev_fw_file="/sys/firmware/sclp_sd/config/data"
|
zdev_fw_file="/sys/firmware/sclp_sd/config/data"
|
||||||
zdev_base_args="--force --yes --no-root-update --no-settle --auto-conf --quiet"
|
zdev_base_args="--force --yes --no-root-update --no-settle --auto-conf --quiet"
|
||||||
|
zdev_id="/lib/s390-tools/zdev_id"
|
||||||
|
|
||||||
if [ -e "$zdev_fw_file" ] ; then
|
if [ -e "$zdev_fw_file" ] ; then
|
||||||
zdev_auto=1
|
zdev_auto=1
|
||||||
@@ -35,4 +38,22 @@ done
|
|||||||
|
|
||||||
if [ $zdev_auto -eq 1 ] ; then
|
if [ $zdev_auto -eq 1 ] ; then
|
||||||
chzdev --import "$zdev_fw_file" $zdev_base_args
|
chzdev --import "$zdev_fw_file" $zdev_base_args
|
||||||
|
|
||||||
|
# Get information about DPM environment
|
||||||
|
for line in $($zdev_id) ; do
|
||||||
|
eval "$line"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$ZDEV_IS_DPM,$ZDEV_NEST_LEVEL,$ZDEV_HYPERVISOR_0" = "1,1,LPAR" ] ; then
|
||||||
|
# Manually iterate over existing PCI devices - there is a udev rule
|
||||||
|
# that handles this for PCI devices added at runtime but that doesn't
|
||||||
|
# work for PCI devices defined before boot because there is no coldplug
|
||||||
|
# trigger for /sys/bus/pci/slots
|
||||||
|
for slot in /sys/bus/pci/slots/* ; do
|
||||||
|
read power < "$slot/power"
|
||||||
|
if [ "$power" = "0" ] ; then
|
||||||
|
echo 1 > "$slot/power"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ done
|
|||||||
copy_exec /sbin/chzdev
|
copy_exec /sbin/chzdev
|
||||||
copy_exec /sbin/lszdev
|
copy_exec /sbin/lszdev
|
||||||
copy_exec /sbin/vmcp
|
copy_exec /sbin/vmcp
|
||||||
|
copy_exec /lib/s390-tools/zdev_id
|
||||||
|
|
||||||
|
cp -p /usr/lib/udev/rules.d/81-dpm.rules "$DESTDIR/usr/lib/udev/rules.d/"
|
||||||
|
|
||||||
_tempfile=$(mktemp --tmpdir initramfs-zdev.XXXXXX)
|
_tempfile=$(mktemp --tmpdir initramfs-zdev.XXXXXX)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
# Copyright IBM Corp. 2017
|
# Copyright IBM Corp. 2017,2021
|
||||||
#
|
#
|
||||||
# s390-tools is free software; you can redistribute it and/or modify
|
# s390-tools is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the MIT license. See LICENSE for details.
|
# it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -15,7 +15,9 @@
|
|||||||
# where
|
# where
|
||||||
#
|
#
|
||||||
# no-auto: Indicates that firmware-provided I/O configuration data
|
# no-auto: Indicates that firmware-provided I/O configuration data
|
||||||
# should not be applied.
|
# should not be applied. This also affects automatic
|
||||||
|
# activation of PCI and crypto devices when running in a DPM
|
||||||
|
# LPAR.
|
||||||
#
|
#
|
||||||
|
|
||||||
PREREQ="udev"
|
PREREQ="udev"
|
||||||
@@ -36,6 +38,7 @@ esac
|
|||||||
|
|
||||||
zdev_fw_file="/sys/firmware/sclp_sd/config/data"
|
zdev_fw_file="/sys/firmware/sclp_sd/config/data"
|
||||||
zdev_base_args="--force --yes --no-root-update --no-settle --auto-conf --quiet"
|
zdev_base_args="--force --yes --no-root-update --no-settle --auto-conf --quiet"
|
||||||
|
zdev_id="/lib/s390-tools/zdev_id"
|
||||||
|
|
||||||
if [ -e "$zdev_fw_file" ] ; then
|
if [ -e "$zdev_fw_file" ] ; then
|
||||||
zdev_auto=1
|
zdev_auto=1
|
||||||
@@ -64,4 +67,22 @@ if [ $zdev_auto -eq 1 ] ; then
|
|||||||
udevadm trigger --type=subsystems --action=add
|
udevadm trigger --type=subsystems --action=add
|
||||||
udevadm trigger --action=add
|
udevadm trigger --action=add
|
||||||
udevadm settle || true
|
udevadm settle || true
|
||||||
|
|
||||||
|
# Get information about DPM environment
|
||||||
|
for line in $($zdev_id) ; do
|
||||||
|
eval "$line"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$ZDEV_IS_DPM,$ZDEV_NEST_LEVEL,$ZDEV_HYPERVISOR_0" = "1,1,LPAR" ] ; then
|
||||||
|
# Manually iterate over existing PCI devices - there is a udev
|
||||||
|
# rule that handles this for PCI devices added at runtime but
|
||||||
|
# that doesn't work for PCI devices defined before boot because
|
||||||
|
# there is no coldplug trigger for /sys/bus/pci/slots
|
||||||
|
for slot in /sys/bus/pci/slots/* ; do
|
||||||
|
read power < "$slot/power"
|
||||||
|
if [ "$power" = "0" ] ; then
|
||||||
|
echo 1 > "$slot/power"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
+4
-3
@@ -73,7 +73,7 @@ lszdev_objects += lcs.o lcs_auto.o
|
|||||||
# Generic CCW devtype
|
# Generic CCW devtype
|
||||||
lszdev_objects += generic_ccw.o
|
lszdev_objects += generic_ccw.o
|
||||||
|
|
||||||
all: chzdev lszdev
|
all: chzdev lszdev zdev_id
|
||||||
|
|
||||||
chzdev_usage.c: chzdev_usage.txt
|
chzdev_usage.c: chzdev_usage.txt
|
||||||
$(SED) $< >$@ -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/^/"/g' \
|
$(SED) $< >$@ -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/^/"/g' \
|
||||||
@@ -95,16 +95,17 @@ libs = $(rootdir)/libutil/libutil.a
|
|||||||
chzdev: $(chzdev_objects) $(libs)
|
chzdev: $(chzdev_objects) $(libs)
|
||||||
lszdev: $(lszdev_objects) $(libs)
|
lszdev: $(lszdev_objects) $(libs)
|
||||||
|
|
||||||
install: chzdev
|
install: chzdev zdev_id
|
||||||
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR)
|
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR)
|
||||||
$(INSTALL) -c chzdev $(DESTDIR)$(BINDIR)
|
$(INSTALL) -c chzdev $(DESTDIR)$(BINDIR)
|
||||||
$(INSTALL) -c lszdev $(DESTDIR)$(BINDIR)
|
$(INSTALL) -c lszdev $(DESTDIR)$(BINDIR)
|
||||||
|
$(INSTALL) -c zdev_id $(DESTDIR)$(TOOLS_LIBDIR)
|
||||||
ifeq ($(HAVE_DRACUT),1)
|
ifeq ($(HAVE_DRACUT),1)
|
||||||
$(INSTALL) -m 755 zdev-root-update.dracut \
|
$(INSTALL) -m 755 zdev-root-update.dracut \
|
||||||
$(DESTDIR)$(TOOLS_LIBDIR)/zdev-root-update
|
$(DESTDIR)$(TOOLS_LIBDIR)/zdev-root-update
|
||||||
endif
|
endif
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@rm -f *.o chzdev lszdev chzdev_usage.c lszdev_usage.c gmon.out *.gcda *.gcno
|
@rm -f *.o chzdev lszdev chzdev_usage.c lszdev_usage.c gmon.out *.gcda *.gcno zdev_id
|
||||||
|
|
||||||
.PHONY: all install clean
|
.PHONY: all install clean
|
||||||
|
|||||||
+56
-8
@@ -7,6 +7,7 @@
|
|||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -16,6 +17,7 @@
|
|||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
#define LSBLK_CMDLINE "lsblk -P -o NAME,MAJ:MIN,FSTYPE,UUID,MOUNTPOINT,PKNAME 2>/dev/null"
|
#define LSBLK_CMDLINE "lsblk -P -o NAME,MAJ:MIN,FSTYPE,UUID,MOUNTPOINT,PKNAME 2>/dev/null"
|
||||||
|
#define LSBLK_CMDLINE2 "lsblk -P -o NAME,MAJ:MIN,FSTYPE,UUID,MOUNTPOINTS,PKNAME 2>/dev/null"
|
||||||
|
|
||||||
struct blkinfo {
|
struct blkinfo {
|
||||||
struct devnode *devnode;
|
struct devnode *devnode;
|
||||||
@@ -82,6 +84,26 @@ void blkinfo_print(struct blkinfo *blkinfo, int level)
|
|||||||
printf("%*sparent=%s\n", level, "", blkinfo->parent);
|
printf("%*sparent=%s\n", level, "", blkinfo->parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convert each occurrence of '\xnn' in @str to character with hex code <nn>. */
|
||||||
|
static void hex_unescape(char *str)
|
||||||
|
{
|
||||||
|
unsigned int c;
|
||||||
|
|
||||||
|
while ((str = strstr(str, "\\x"))) {
|
||||||
|
if (isxdigit(str[2]) && isxdigit(str[3]) &&
|
||||||
|
sscanf(str + 2, "%2x", &c) == 1) {
|
||||||
|
str[0] = (char)c;
|
||||||
|
|
||||||
|
/* Move remainder of str including nul behind <c>. */
|
||||||
|
memmove(str + /* <c> */ 1,
|
||||||
|
str + /* '\xnn' */ 4,
|
||||||
|
strlen(str + 4) + /* <nul> */ 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static char *isolate_keyword(char **line_ptr, const char *keyword)
|
static char *isolate_keyword(char **line_ptr, const char *keyword)
|
||||||
{
|
{
|
||||||
char *start, *end;
|
char *start, *end;
|
||||||
@@ -102,30 +124,58 @@ static char *isolate_keyword(char **line_ptr, const char *keyword)
|
|||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct blkinfo *blkinfo_from_line(char *line)
|
static void add_blkinfos_from_line(struct util_list *blkinfos,
|
||||||
|
char *line)
|
||||||
{
|
{
|
||||||
char *name, *majmin, *fstype, *uuid, *mountpoint, *parent;
|
char *name, *majmin, *fstype, *uuid, *mountpoint, *mountpoints, *parent;
|
||||||
|
struct blkinfo *blkinfo;
|
||||||
|
|
||||||
name = isolate_keyword(&line, "NAME=\"");
|
name = isolate_keyword(&line, "NAME=\"");
|
||||||
majmin = isolate_keyword(&line, "MAJ:MIN=\"");
|
majmin = isolate_keyword(&line, "MAJ:MIN=\"");
|
||||||
|
if (!majmin)
|
||||||
|
majmin = isolate_keyword(&line, "MAJ_MIN=\"");
|
||||||
fstype = isolate_keyword(&line, "FSTYPE=\"");
|
fstype = isolate_keyword(&line, "FSTYPE=\"");
|
||||||
uuid = isolate_keyword(&line, "UUID=\"");
|
uuid = isolate_keyword(&line, "UUID=\"");
|
||||||
mountpoint = isolate_keyword(&line, "MOUNTPOINT=\"");
|
mountpoint = isolate_keyword(&line, "MOUNTPOINT=\"");
|
||||||
|
mountpoints = isolate_keyword(&line, "MOUNTPOINTS=\"");
|
||||||
parent = isolate_keyword(&line, "PKNAME=\"");
|
parent = isolate_keyword(&line, "PKNAME=\"");
|
||||||
|
|
||||||
return blkinfo_new(name, majmin, fstype, uuid, mountpoint, parent);
|
if (!mountpoints) {
|
||||||
|
/* Handle old lsblk output format. */
|
||||||
|
blkinfo = blkinfo_new(name, majmin, fstype, uuid, mountpoint,
|
||||||
|
parent);
|
||||||
|
ptrlist_add(blkinfos, blkinfo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore newline mount point separator encoded as hex. */
|
||||||
|
hex_unescape(mountpoints);
|
||||||
|
|
||||||
|
/* Represent each mount point as a separate blkinfo to support
|
||||||
|
* resolution of multi-mount point file systems like btrfs
|
||||||
|
* subvolumes. */
|
||||||
|
while ((mountpoint = strsep(&mountpoints, "\n"))) {
|
||||||
|
blkinfo = blkinfo_new(name, majmin, fstype, uuid, mountpoint,
|
||||||
|
parent);
|
||||||
|
ptrlist_add(blkinfos, blkinfo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct util_list *blkinfos_read(void)
|
static struct util_list *blkinfos_read(void)
|
||||||
{
|
{
|
||||||
char *output, *curr, *next;
|
char *output, *curr, *next;
|
||||||
struct util_list *blkinfos;
|
struct util_list *blkinfos;
|
||||||
struct blkinfo *blkinfo;
|
|
||||||
|
|
||||||
if (cached_blkinfos)
|
if (cached_blkinfos)
|
||||||
return cached_blkinfos;
|
return cached_blkinfos;
|
||||||
|
|
||||||
output = misc_read_cmd_output(LSBLK_CMDLINE, 0, 1);
|
output = misc_read_cmd_output(LSBLK_CMDLINE2, 0, 1);
|
||||||
|
if (output && !*output) {
|
||||||
|
/* No output might indicate no support for new lsblk command-
|
||||||
|
* line format - fall back to old format. */
|
||||||
|
free(output);
|
||||||
|
output = misc_read_cmd_output(LSBLK_CMDLINE, 0, 1);
|
||||||
|
}
|
||||||
if (!output)
|
if (!output)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -134,9 +184,7 @@ static struct util_list *blkinfos_read(void)
|
|||||||
/* Iterate over each line. */
|
/* Iterate over each line. */
|
||||||
next = output;
|
next = output;
|
||||||
while ((curr = strsep(&next, "\n"))) {
|
while ((curr = strsep(&next, "\n"))) {
|
||||||
blkinfo = blkinfo_from_line(curr);
|
add_blkinfos_from_line(blkinfos, curr);
|
||||||
if (blkinfo)
|
|
||||||
ptrlist_add(blkinfos, blkinfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(output);
|
free(output);
|
||||||
|
|||||||
+11
-4
@@ -2088,12 +2088,18 @@ static exit_code_t devtype_remove_settings(struct devtype *dt, config_t config,
|
|||||||
found = strlist_new();
|
found = strlist_new();
|
||||||
notfound = strlist_new();
|
notfound = strlist_new();
|
||||||
|
|
||||||
if (SCOPE_ACTIVE(config))
|
if (SCOPE_ACTIVE(config)) {
|
||||||
remove_settings(dt->active_settings, names, found, notfound, 1);
|
rc = remove_settings(dt->active_settings, names, found,
|
||||||
|
notfound, 1);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (SCOPE_PERSISTENT(config)) {
|
if (SCOPE_PERSISTENT(config)) {
|
||||||
remove_settings(dt->persistent_settings, names, found,
|
rc = remove_settings(dt->persistent_settings, names, found,
|
||||||
notfound, 0);
|
notfound, 0);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!util_list_is_empty(notfound)) {
|
if (!util_list_is_empty(notfound)) {
|
||||||
@@ -2104,6 +2110,7 @@ static exit_code_t devtype_remove_settings(struct devtype *dt, config_t config,
|
|||||||
rc = EXIT_SETTING_NOT_FOUND;
|
rc = EXIT_SETTING_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
strlist_free(found);
|
strlist_free(found);
|
||||||
strlist_free(notfound);
|
strlist_free(notfound);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
* zdev_id - Determine system characteristics required by zdev udev rules
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2021
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define SYSINFO "/proc/sysinfo"
|
||||||
|
#define CMDLINE "/proc/cmdline"
|
||||||
|
#define WHITESPACE " \t\n"
|
||||||
|
|
||||||
|
static void array_add(char ***array_p, int *num_p, const char *str)
|
||||||
|
{
|
||||||
|
char **array = *array_p, *copy;
|
||||||
|
int num = *num_p + 1;
|
||||||
|
|
||||||
|
array = realloc(array, num * sizeof(char *));
|
||||||
|
copy = strdup(str);
|
||||||
|
if (!array || !copy)
|
||||||
|
err(1, "Could not allocate memory");
|
||||||
|
array[num - 1] = copy;
|
||||||
|
*array_p = array;
|
||||||
|
*num_p = num;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void array_free(char **array, int num)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++)
|
||||||
|
free(array[i]);
|
||||||
|
free(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void process_sysinfo(const char *filename)
|
||||||
|
{
|
||||||
|
char *line = NULL, *substr, **cps = NULL;
|
||||||
|
int is_dpm = 0, num_cps = 0, level, i;
|
||||||
|
FILE *fd;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
fd = fopen(filename, "r");
|
||||||
|
if (!fd)
|
||||||
|
err(1, "Could not open sysinfo file '%s'", filename);
|
||||||
|
|
||||||
|
while (getline(&line, &n, fd) != -1) {
|
||||||
|
if (sscanf(line, "LPAR %m[^:]", &substr) == 1) {
|
||||||
|
if (strcmp(substr, "UUID") == 0) {
|
||||||
|
/* Heuristic: only DPM LPARs have UUIDs. */
|
||||||
|
is_dpm = 1;
|
||||||
|
} else if (strcmp(substr, "Number") == 0) {
|
||||||
|
array_add(&cps, &num_cps, "LPAR");
|
||||||
|
}
|
||||||
|
free(substr);
|
||||||
|
} else if (sscanf(line, "VM%*d Control Program: %ms ",
|
||||||
|
&substr) == 1) {
|
||||||
|
array_add(&cps, &num_cps, substr);
|
||||||
|
free(substr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(line);
|
||||||
|
fclose(fd);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ZDEV_NEST_LEVEL=n
|
||||||
|
*
|
||||||
|
* Virtualization nesting level of running system:
|
||||||
|
* 1: LPAR
|
||||||
|
* 2: first level VM
|
||||||
|
* 3: second level VM
|
||||||
|
*/
|
||||||
|
printf("ZDEV_NEST_LEVEL=%d\n", num_cps);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ZDEV_HYPERVISOR_<n>=LPAR|z/VM|KVM/Linux
|
||||||
|
*
|
||||||
|
* Type of hypervisor that provides virtualization at nesting level <n>.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < num_cps; i++) {
|
||||||
|
/* Sysinfo lists VMs in reverse order .*/
|
||||||
|
level = (i == 0) ? i : (num_cps - i);
|
||||||
|
printf("ZDEV_HYPERVISOR_%d=\"%s\"\n", i, cps[level]);
|
||||||
|
}
|
||||||
|
array_free(cps, num_cps);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ZDEV_IS_DPM=0|1
|
||||||
|
*
|
||||||
|
* Indicator if top-level LPAR is managed by Dynamic Partition
|
||||||
|
* Manager (DPM):
|
||||||
|
* 0: Classic mode
|
||||||
|
* 1: DPM mode
|
||||||
|
*/
|
||||||
|
printf("ZDEV_IS_DPM=%d\n", is_dpm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void process_cmdline(const char *filename)
|
||||||
|
{
|
||||||
|
char *line = NULL, *substr, *next = NULL, *value;
|
||||||
|
int no_auto = 0;
|
||||||
|
size_t n;
|
||||||
|
FILE *fd;
|
||||||
|
|
||||||
|
fd = fopen(filename, "r");
|
||||||
|
if (!fd)
|
||||||
|
err(1, "Could not open cmdline file '%s'", filename);
|
||||||
|
|
||||||
|
if (getline(&line, &n, fd) == -1)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
for (substr = strtok_r(line, WHITESPACE, &next); substr;
|
||||||
|
substr = strtok_r(NULL, WHITESPACE, &next)) {
|
||||||
|
if (sscanf(substr, "rd.zdev=%ms ", &value) != 1)
|
||||||
|
continue;
|
||||||
|
if (strstr(value, "no-auto"))
|
||||||
|
no_auto = 1;
|
||||||
|
|
||||||
|
free(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(line);
|
||||||
|
fclose(fd);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ZDEV_NO_AUTO=0|1
|
||||||
|
*
|
||||||
|
* Indicator if auto-configuration is requested.
|
||||||
|
* 0: Perform auto-configuration
|
||||||
|
* 1: Skip auto-configuration
|
||||||
|
*/
|
||||||
|
printf("ZDEV_NO_AUTO=%d\n", no_auto);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char *sysinfo, *cmdline;
|
||||||
|
|
||||||
|
sysinfo = argc < 2 ? SYSINFO : argv[1];
|
||||||
|
cmdline = argc < 3 ? CMDLINE : argv[2];
|
||||||
|
|
||||||
|
process_sysinfo(sysinfo);
|
||||||
|
process_cmdline(cmdline);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# Automatically activate certain s390-specific device types that are attached
|
||||||
|
# in offline state when running in an LPAR managed by the Dynamic Partition
|
||||||
|
# Manager (DPM).
|
||||||
|
#
|
||||||
|
# Note that processing is restricted to DPM as there may be use cases for
|
||||||
|
# not enabling these device types in non-DPM mode.
|
||||||
|
#
|
||||||
|
# To deactivate this processing, specify the following on the kernel command
|
||||||
|
# line:
|
||||||
|
#
|
||||||
|
# rd.zdev=no-auto
|
||||||
|
|
||||||
|
ACTION!="add", GOTO="end_dpm"
|
||||||
|
|
||||||
|
# Handle newly added PCI devices in offline state
|
||||||
|
SUBSYSTEM=="slots", ATTR{power}=="0", GOTO="check_dpm"
|
||||||
|
# Handle newly added crypto devices in offline state
|
||||||
|
SUBSYSTEM=="ap", ENV{DEVTYPE}=="ap_card", ATTR{config}=="0", GOTO="check_dpm"
|
||||||
|
|
||||||
|
GOTO="end_dpm"
|
||||||
|
|
||||||
|
LABEL="check_dpm"
|
||||||
|
|
||||||
|
IMPORT{program}="/lib/s390-tools/zdev_id"
|
||||||
|
|
||||||
|
# Check for off-switch
|
||||||
|
ENV{ZDEV_NO_AUTO}=="1", GOTO="end_dpm"
|
||||||
|
|
||||||
|
# Check for DPM LPAR
|
||||||
|
ENV{ZDEV_IS_DPM}!="1", GOTO="end_dpm"
|
||||||
|
ENV{ZDEV_NEST_LEVEL}!="1", GOTO="end_dpm"
|
||||||
|
ENV{ZDEV_HYPERVISOR_0}!="LPAR", GOTO="end_dpm"
|
||||||
|
|
||||||
|
# Enable PCI device
|
||||||
|
SUBSYSTEM=="slots", ATTR{power}="1"
|
||||||
|
# Enable crypto device
|
||||||
|
SUBSYSTEM=="ap", ATTR{config}="1"
|
||||||
|
|
||||||
|
# End of rule
|
||||||
|
LABEL="end_dpm"
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Common definitions
|
||||||
|
include ../../common.mak
|
||||||
|
|
||||||
|
UDEVDIR := /usr/lib/udev/rules.d/
|
||||||
|
RULES := 81-dpm.rules
|
||||||
|
|
||||||
|
install:
|
||||||
|
$(INSTALL) -m 755 -d $(DESTDIR)$(UDEVDIR)
|
||||||
|
$(INSTALL) -m 644 $(RULES) $(DESTDIR)$(UDEVDIR)/
|
||||||
+7
-6
@@ -30,8 +30,9 @@ check_dep:
|
|||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
"zdsfs", \
|
"zdsfs", \
|
||||||
"fuse.h", \
|
"fuse.h", \
|
||||||
"fuse-devel or libfuse-dev", \
|
"fuse3-devel or libfuse3-dev", \
|
||||||
"HAVE_FUSE=0")
|
"HAVE_FUSE=0", \
|
||||||
|
"-DFUSE_USE_VERSION=30")
|
||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
"zdsfs", \
|
"zdsfs", \
|
||||||
"curl/curl.h", \
|
"curl/curl.h", \
|
||||||
@@ -39,13 +40,13 @@ check_dep:
|
|||||||
"HAVE_CURL=0")
|
"HAVE_CURL=0")
|
||||||
|
|
||||||
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
||||||
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse)
|
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse3)
|
||||||
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse)
|
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse3)
|
||||||
CURL_CFLAGS = $(shell pkg-config --silence-errors --cflags libcurl)
|
CURL_CFLAGS = $(shell pkg-config --silence-errors --cflags libcurl)
|
||||||
CURL_LDLIBS = $(shell pkg-config --silence-errors --libs libcurl)
|
CURL_LDLIBS = $(shell pkg-config --silence-errors --libs libcurl)
|
||||||
else
|
else
|
||||||
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse
|
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse3
|
||||||
FUSE_LDLIBS = -lfuse
|
FUSE_LDLIBS = -lfuse3
|
||||||
CURL_CFLAGS = -I/usr/include/s390x-linux-gnu/curl
|
CURL_CFLAGS = -I/usr/include/s390x-linux-gnu/curl
|
||||||
CURL_LDLIBS = -lcurl
|
CURL_LDLIBS = -lcurl
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -227,9 +227,6 @@ Allow access by other users
|
|||||||
\fB\-o\fR allow_root
|
\fB\-o\fR allow_root
|
||||||
Allow access by root
|
Allow access by root
|
||||||
.TP
|
.TP
|
||||||
\fB\-o\fR nonempty
|
|
||||||
Allow mounts over non\-empty file/dir
|
|
||||||
.TP
|
|
||||||
\fB\-o\fR default_permissions
|
\fB\-o\fR default_permissions
|
||||||
Enable permission checking by kernel
|
Enable permission checking by kernel
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
+12
-10
@@ -8,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* The fuse version define tells fuse that we want to use the new API */
|
/* The fuse version define tells fuse that we want to use the new API */
|
||||||
#define FUSE_USE_VERSION 26
|
#define FUSE_USE_VERSION 30
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -312,7 +312,8 @@ void keepalive_start(void)
|
|||||||
setup_timer(zdsfsinfo.keepalive);
|
setup_timer(zdsfsinfo.keepalive);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int zdsfs_getattr(const char *path, struct stat *stbuf)
|
static int zdsfs_getattr(const char *path, struct stat *stbuf,
|
||||||
|
struct fuse_file_info *UNUSED(fi))
|
||||||
{
|
{
|
||||||
char normds[MAXDSNAMELENGTH];
|
char normds[MAXDSNAMELENGTH];
|
||||||
size_t dssize;
|
size_t dssize;
|
||||||
@@ -524,7 +525,8 @@ static int zdsfs_update_vtoc(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int zdsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
static int zdsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
||||||
off_t UNUSED(offset), struct fuse_file_info *UNUSED(fi))
|
off_t UNUSED(offset), struct fuse_file_info *UNUSED(fi),
|
||||||
|
enum fuse_readdir_flags UNUSED(flags))
|
||||||
{
|
{
|
||||||
char normds[MAXDSNAMELENGTH];
|
char normds[MAXDSNAMELENGTH];
|
||||||
char *mbrname;
|
char *mbrname;
|
||||||
@@ -544,9 +546,9 @@ static int zdsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
|||||||
* type one: the root directory contains all data sets
|
* type one: the root directory contains all data sets
|
||||||
*/
|
*/
|
||||||
if (strcmp(path, "/") == 0) {
|
if (strcmp(path, "/") == 0) {
|
||||||
filler(buf, ".", NULL, 0);
|
filler(buf, ".", NULL, 0, 0);
|
||||||
filler(buf, "..", NULL, 0);
|
filler(buf, "..", NULL, 0, 0);
|
||||||
filler(buf, METADATAFILE, NULL, 0);
|
filler(buf, METADATAFILE, NULL, 0, 0);
|
||||||
/* note that we do not need to distinguish between
|
/* note that we do not need to distinguish between
|
||||||
* normal files and directories here, that is done
|
* normal files and directories here, that is done
|
||||||
* in the rdf_getattr function
|
* in the rdf_getattr function
|
||||||
@@ -558,7 +560,7 @@ static int zdsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
|||||||
lzds_dataset_get_is_supported(ds, &issupported);
|
lzds_dataset_get_is_supported(ds, &issupported);
|
||||||
if (issupported) {
|
if (issupported) {
|
||||||
lzds_dataset_get_name(ds, &dsname);
|
lzds_dataset_get_name(ds, &dsname);
|
||||||
filler(buf, dsname, NULL, 0);
|
filler(buf, dsname, NULL, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lzds_dsiterator_free(dsit);
|
lzds_dsiterator_free(dsit);
|
||||||
@@ -572,14 +574,14 @@ static int zdsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
|||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
lzds_dataset_get_is_PDS(ds, &ispds);
|
lzds_dataset_get_is_PDS(ds, &ispds);
|
||||||
if (ispds) {
|
if (ispds) {
|
||||||
filler(buf, ".", NULL, 0);
|
filler(buf, ".", NULL, 0, 0);
|
||||||
filler(buf, "..", NULL, 0);
|
filler(buf, "..", NULL, 0, 0);
|
||||||
rc = lzds_dataset_alloc_memberiterator(ds, &it);
|
rc = lzds_dataset_alloc_memberiterator(ds, &it);
|
||||||
if (rc)
|
if (rc)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
while (!lzds_memberiterator_get_next_member(it, &member)) {
|
while (!lzds_memberiterator_get_next_member(it, &member)) {
|
||||||
lzds_pdsmember_get_name(member, &mbrname);
|
lzds_pdsmember_get_name(member, &mbrname);
|
||||||
filler(buf, mbrname, NULL, 0);
|
filler(buf, mbrname, NULL, 0, 0);
|
||||||
}
|
}
|
||||||
lzds_memberiterator_free(it);
|
lzds_memberiterator_free(it);
|
||||||
} else
|
} else
|
||||||
|
|||||||
+14
-11
@@ -1,5 +1,7 @@
|
|||||||
include ../common.mak
|
include ../common.mak
|
||||||
|
|
||||||
|
ALL_CFLAGS += -Wno-address-of-packed-member
|
||||||
|
|
||||||
#
|
#
|
||||||
# HAVE_FUSE: Allow to build zgetdump without mount support
|
# HAVE_FUSE: Allow to build zgetdump without mount support
|
||||||
#
|
#
|
||||||
@@ -13,8 +15,9 @@ check_dep_fuse:
|
|||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
"zgetdump mount support", \
|
"zgetdump mount support", \
|
||||||
"fuse.h", \
|
"fuse.h", \
|
||||||
"fuse-devel or libfuse-dev", \
|
"fuse3-devel or libfuse3-dev", \
|
||||||
"HAVE_FUSE=0")
|
"HAVE_FUSE=0", \
|
||||||
|
"-DFUSE_USE_VERSION=30")
|
||||||
endif
|
endif
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -39,28 +42,28 @@ check_dep_zlib:
|
|||||||
|
|
||||||
all: check_dep_fuse check_dep_zlib zgetdump
|
all: check_dep_fuse check_dep_zlib zgetdump
|
||||||
|
|
||||||
OBJECTS = zgetdump.o opts.o zg.o \
|
OBJECTS = zgetdump.o opts.o zg.o zg_error.o zg_print.o \
|
||||||
dfi.o dfi_vmcoreinfo.o \
|
dfi.o dfi_mem_chunk.o dfi_vmcoreinfo.o \
|
||||||
dfi_lkcd.o dfi_elf.o \
|
dfi_lkcd.o dfi_elf.o \
|
||||||
dfi_s390.o dfi_s390_ext.o\
|
dfi_s390.o dfi_s390_ext.o\
|
||||||
dfi_s390mv.o dfi_s390mv_ext.o \
|
dfi_s390mv.o dfi_s390mv_ext.o \
|
||||||
dfi_s390tape.o dfi_kdump.o \
|
dfi_s390tape.o dfi_kdump.o \
|
||||||
dfi_devmem.o dfo.o \
|
dfi_devmem.o dfo.o dfo_mem_chunk.o \
|
||||||
dfo_elf.o dfo_s390.o \
|
dfo_elf.o dfo_s390.o \
|
||||||
df_s390.o \
|
df_elf.o df_s390.o \
|
||||||
dt.o dt_s390sv.o dt_s390sv_ext.o \
|
dt.o dt_s390sv.o dt_s390sv_ext.o \
|
||||||
dt_s390mv.o dt_s390mv_ext.o \
|
dt_s390mv.o dt_s390mv_ext.o \
|
||||||
dt_scsi.o stdout.o \
|
dt_scsi.o output.o
|
||||||
|
|
||||||
ifeq ("$(HAVE_FUSE)","0")
|
ifeq ("$(HAVE_FUSE)","0")
|
||||||
FUSE_CFLAGS = -DHAVE_FUSE=0 -D_FILE_OFFSET_BITS=64
|
FUSE_CFLAGS = -DHAVE_FUSE=0 -D_FILE_OFFSET_BITS=64
|
||||||
FUSE_LDLIBS =
|
FUSE_LDLIBS =
|
||||||
else ifneq ($(shell sh -c 'command -v pkg-config'),)
|
else ifneq ($(shell sh -c 'command -v pkg-config'),)
|
||||||
FUSE_CFLAGS = -DHAVE_FUSE=1 $(shell pkg-config --silence-errors --cflags fuse)
|
FUSE_CFLAGS = -DHAVE_FUSE=1 $(shell pkg-config --silence-errors --cflags fuse3)
|
||||||
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse)
|
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse3)
|
||||||
else
|
else
|
||||||
FUSE_CFLAGS = -DHAVE_FUSE=1 -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse
|
FUSE_CFLAGS = -DHAVE_FUSE=1 -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse3
|
||||||
FUSE_LDLIBS = -lfuse
|
FUSE_LDLIBS = -lfuse3
|
||||||
endif
|
endif
|
||||||
LDLIBS += -lz $(FUSE_LDLIBS)
|
LDLIBS += -lz $(FUSE_LDLIBS)
|
||||||
ALL_CFLAGS += $(FUSE_CFLAGS)
|
ALL_CFLAGS += $(FUSE_CFLAGS)
|
||||||
|
|||||||
+191
@@ -0,0 +1,191 @@
|
|||||||
|
/*
|
||||||
|
* Copyright IBM Corp. 2001, 2018, 2021
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "df_elf.h"
|
||||||
|
|
||||||
|
#define NOTE_NAME_CORE "CORE"
|
||||||
|
#define NOTE_NAME_LINUX "LINUX"
|
||||||
|
#define NOTE_NAME_VMCOREINFO "VMCOREINFO"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize ELF header
|
||||||
|
*/
|
||||||
|
void *ehdr_init(Elf64_Ehdr *ehdr, Elf64_Half phnum)
|
||||||
|
{
|
||||||
|
memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
|
||||||
|
ehdr->e_ident[EI_CLASS] = ELFCLASS64;
|
||||||
|
ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
|
||||||
|
ehdr->e_ident[EI_VERSION] = EV_CURRENT;
|
||||||
|
ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;
|
||||||
|
ehdr->e_ident[EI_ABIVERSION] = 0;
|
||||||
|
memset(ehdr->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
|
||||||
|
ehdr->e_type = ET_CORE;
|
||||||
|
ehdr->e_machine = EM_S390;
|
||||||
|
ehdr->e_version = EV_CURRENT;
|
||||||
|
ehdr->e_entry = 0;
|
||||||
|
ehdr->e_phoff = sizeof(Elf64_Ehdr);
|
||||||
|
ehdr->e_shoff = 0;
|
||||||
|
ehdr->e_flags = 0;
|
||||||
|
ehdr->e_ehsize = sizeof(Elf64_Ehdr);
|
||||||
|
ehdr->e_phentsize = sizeof(Elf64_Phdr);
|
||||||
|
ehdr->e_phnum = phnum;
|
||||||
|
ehdr->e_shentsize = 0;
|
||||||
|
ehdr->e_shnum = 0;
|
||||||
|
ehdr->e_shstrndx = 0;
|
||||||
|
return ehdr + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize ELF note
|
||||||
|
*/
|
||||||
|
void *nt_init(void *buf, Elf64_Word type, const void *desc, int d_len,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
Elf64_Nhdr *note;
|
||||||
|
u64 len;
|
||||||
|
|
||||||
|
note = (Elf64_Nhdr *)buf;
|
||||||
|
note->n_namesz = strlen(name) + 1;
|
||||||
|
note->n_descsz = d_len;
|
||||||
|
note->n_type = type;
|
||||||
|
len = sizeof(Elf64_Nhdr);
|
||||||
|
|
||||||
|
memcpy(buf + len, name, note->n_namesz);
|
||||||
|
len = ROUNDUP(len + note->n_namesz, 4);
|
||||||
|
|
||||||
|
memcpy(buf + len, desc, note->n_descsz);
|
||||||
|
len = ROUNDUP(len + note->n_descsz, 4);
|
||||||
|
|
||||||
|
return PTR_ADD(buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize prstatus note
|
||||||
|
*/
|
||||||
|
void *nt_prstatus(void *ptr, const struct dfi_cpu *cpu)
|
||||||
|
{
|
||||||
|
struct nt_prstatus_64 nt_prstatus;
|
||||||
|
static int cpu_nr = 1;
|
||||||
|
|
||||||
|
memset(&nt_prstatus, 0, sizeof(nt_prstatus));
|
||||||
|
memcpy(&nt_prstatus.gprs, cpu->gprs, sizeof(cpu->gprs));
|
||||||
|
memcpy(&nt_prstatus.psw, cpu->psw, sizeof(cpu->psw));
|
||||||
|
memcpy(&nt_prstatus.acrs, cpu->acrs, sizeof(cpu->acrs));
|
||||||
|
nt_prstatus.pr_pid = cpu_nr;
|
||||||
|
cpu_nr++;
|
||||||
|
|
||||||
|
return nt_init(ptr, NT_PRSTATUS, &nt_prstatus, sizeof(nt_prstatus),
|
||||||
|
NOTE_NAME_CORE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize fpregset (floating point) note
|
||||||
|
*/
|
||||||
|
void *nt_fpregset(void *ptr, const struct dfi_cpu *cpu)
|
||||||
|
{
|
||||||
|
struct nt_fpregset_64 nt_fpregset;
|
||||||
|
|
||||||
|
memset(&nt_fpregset, 0, sizeof(nt_fpregset));
|
||||||
|
memcpy(&nt_fpregset.fpc, &cpu->fpc, sizeof(cpu->fpc));
|
||||||
|
memcpy(&nt_fpregset.fprs, &cpu->fprs, sizeof(cpu->fprs));
|
||||||
|
|
||||||
|
return nt_init(ptr, NT_FPREGSET, &nt_fpregset, sizeof(nt_fpregset),
|
||||||
|
NOTE_NAME_CORE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize timer note
|
||||||
|
*/
|
||||||
|
void *nt_s390_timer(void *ptr, const struct dfi_cpu *cpu)
|
||||||
|
{
|
||||||
|
return nt_init(ptr, NT_S390_TIMER, &cpu->timer, sizeof(cpu->timer),
|
||||||
|
NOTE_NAME_LINUX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize TOD clock comparator note
|
||||||
|
*/
|
||||||
|
void *nt_s390_tod_cmp(void *ptr, const struct dfi_cpu *cpu)
|
||||||
|
{
|
||||||
|
return nt_init(ptr, NT_S390_TODCMP, &cpu->todcmp,
|
||||||
|
sizeof(cpu->todcmp), NOTE_NAME_LINUX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize TOD programmable register note
|
||||||
|
*/
|
||||||
|
void *nt_s390_tod_preg(void *ptr, const struct dfi_cpu *cpu)
|
||||||
|
{
|
||||||
|
return nt_init(ptr, NT_S390_TODPREG, &cpu->todpreg,
|
||||||
|
sizeof(cpu->todpreg), NOTE_NAME_LINUX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize control register note
|
||||||
|
*/
|
||||||
|
void *nt_s390_ctrs(void *ptr, const struct dfi_cpu *cpu)
|
||||||
|
{
|
||||||
|
return nt_init(ptr, NT_S390_CTRS, &cpu->ctrs, sizeof(cpu->ctrs),
|
||||||
|
NOTE_NAME_LINUX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize prefix register note
|
||||||
|
*/
|
||||||
|
void *nt_s390_prefix(void *ptr, const struct dfi_cpu *cpu)
|
||||||
|
{
|
||||||
|
return nt_init(ptr, NT_S390_PREFIX, &cpu->prefix,
|
||||||
|
sizeof(cpu->prefix), NOTE_NAME_LINUX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize vxrs_low register note
|
||||||
|
*/
|
||||||
|
void *nt_s390_vxrs_low(void *ptr, const struct dfi_cpu *cpu)
|
||||||
|
{
|
||||||
|
return nt_init(ptr, NT_S390_VXRS_LOW, &cpu->vxrs_low,
|
||||||
|
sizeof(cpu->vxrs_low), NOTE_NAME_LINUX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize vxrs_high register note
|
||||||
|
*/
|
||||||
|
void *nt_s390_vxrs_high(void *ptr, const struct dfi_cpu *cpu)
|
||||||
|
{
|
||||||
|
return nt_init(ptr, NT_S390_VXRS_HIGH, &cpu->vxrs_high,
|
||||||
|
sizeof(cpu->vxrs_high), NOTE_NAME_LINUX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize prpsinfo note
|
||||||
|
*/
|
||||||
|
void *nt_prpsinfo(void *ptr)
|
||||||
|
{
|
||||||
|
struct nt_prpsinfo_64 prpsinfo;
|
||||||
|
|
||||||
|
memset(&prpsinfo, 0, sizeof(prpsinfo));
|
||||||
|
prpsinfo.pr_state = 0;
|
||||||
|
prpsinfo.pr_sname = 'R';
|
||||||
|
prpsinfo.pr_zomb = 0;
|
||||||
|
strcpy(prpsinfo.pr_fname, "vmlinux");
|
||||||
|
|
||||||
|
return nt_init(ptr, NT_PRPSINFO, &prpsinfo, sizeof(prpsinfo),
|
||||||
|
NOTE_NAME_CORE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize vmcoreinfo note
|
||||||
|
*/
|
||||||
|
void *nt_vmcoreinfo(void *ptr, const char *vmcoreinfo)
|
||||||
|
{
|
||||||
|
if (!vmcoreinfo)
|
||||||
|
return ptr;
|
||||||
|
return nt_init(ptr, 0, vmcoreinfo, strlen(vmcoreinfo),
|
||||||
|
NOTE_NAME_VMCOREINFO);
|
||||||
|
}
|
||||||
+17
-1
@@ -17,8 +17,8 @@
|
|||||||
|
|
||||||
#include "lib/zt_common.h"
|
#include "lib/zt_common.h"
|
||||||
|
|
||||||
#include "dfo.h"
|
|
||||||
#include "zg.h"
|
#include "zg.h"
|
||||||
|
#include "dfi.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* S390 CPU timer note (u64)
|
* S390 CPU timer note (u64)
|
||||||
@@ -116,4 +116,20 @@ static inline void df_elf_ensure_s390x(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *ehdr_init(Elf64_Ehdr *ehdr, Elf64_Half phnum);
|
||||||
|
|
||||||
|
void *nt_init(void *buf, Elf64_Word type, const void *desc, int d_len,
|
||||||
|
const char *name);
|
||||||
|
void *nt_prstatus(void *ptr, const struct dfi_cpu *cpu);
|
||||||
|
void *nt_fpregset(void *ptr, const struct dfi_cpu *cpu);
|
||||||
|
void *nt_s390_timer(void *ptr, const struct dfi_cpu *cpu);
|
||||||
|
void *nt_s390_tod_cmp(void *ptr, const struct dfi_cpu *cpu);
|
||||||
|
void *nt_s390_tod_preg(void *ptr, const struct dfi_cpu *cpu);
|
||||||
|
void *nt_s390_ctrs(void *ptr, const struct dfi_cpu *cpu);
|
||||||
|
void *nt_s390_prefix(void *ptr, const struct dfi_cpu *cpu);
|
||||||
|
void *nt_s390_vxrs_low(void *ptr, const struct dfi_cpu *cpu);
|
||||||
|
void *nt_s390_vxrs_high(void *ptr, const struct dfi_cpu *cpu);
|
||||||
|
void *nt_prpsinfo(void *ptr);
|
||||||
|
void *nt_vmcoreinfo(void *ptr, const char *vmcoreinfo);
|
||||||
|
|
||||||
#endif /* DF_ELF_H */
|
#endif /* DF_ELF_H */
|
||||||
|
|||||||
+10
-4
@@ -17,7 +17,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "zgetdump.h"
|
#include "df_s390.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check, if we can access the lowcore information in the dump
|
* Check, if we can access the lowcore information in the dump
|
||||||
@@ -37,9 +37,10 @@ static int check_addr_max(struct df_s390_hdr *hdr, u64 addr_max)
|
|||||||
/*
|
/*
|
||||||
* Convert lowcore information into internal CPU representation
|
* Convert lowcore information into internal CPU representation
|
||||||
*/
|
*/
|
||||||
void df_s390_cpu_info_add(struct df_s390_hdr *hdr, u64 addr_max)
|
int df_s390_cpu_info_add(struct df_s390_hdr *hdr, u64 addr_max)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (hdr->version < 5 && hdr->magic == DF_S390_MAGIC) {
|
if (hdr->version < 5 && hdr->magic == DF_S390_MAGIC) {
|
||||||
/* No Prefix registers in header */
|
/* No Prefix registers in header */
|
||||||
@@ -53,8 +54,13 @@ void df_s390_cpu_info_add(struct df_s390_hdr *hdr, u64 addr_max)
|
|||||||
dfi_cpu_info_init(DFI_CPU_CONTENT_ALL);
|
dfi_cpu_info_init(DFI_CPU_CONTENT_ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < hdr->cpu_cnt; i++)
|
for (i = 0; i < hdr->cpu_cnt; i++) {
|
||||||
dfi_cpu_add_from_lc(hdr->lc_vec[i]);
|
rc = dfi_cpu_add_from_lc(hdr->lc_vec[i]);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
+1
-1
@@ -127,7 +127,7 @@ struct df_s390_dumper {
|
|||||||
*/
|
*/
|
||||||
extern void df_s390_hdr_add(struct df_s390_hdr *hdr);
|
extern void df_s390_hdr_add(struct df_s390_hdr *hdr);
|
||||||
extern void df_s390_em_add(struct df_s390_em *em);
|
extern void df_s390_em_add(struct df_s390_em *em);
|
||||||
extern void df_s390_cpu_info_add(struct df_s390_hdr *hdr, u64 addr_max);
|
extern int df_s390_cpu_info_add(struct df_s390_hdr *hdr, u64 addr_max);
|
||||||
extern int df_s390_em_verify(struct df_s390_em *em, struct df_s390_hdr *hdr);
|
extern int df_s390_em_verify(struct df_s390_em *em, struct df_s390_hdr *hdr);
|
||||||
extern void df_s390_dumper_read(struct zg_fh *fh, int32_t blk_size,
|
extern void df_s390_dumper_read(struct zg_fh *fh, int32_t blk_size,
|
||||||
struct df_s390_dumper *dumper);
|
struct df_s390_dumper *dumper);
|
||||||
|
|||||||
+58
-494
@@ -9,12 +9,19 @@
|
|||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <time.h>
|
#include "lib/util_log.h"
|
||||||
|
|
||||||
#include "zgetdump.h"
|
#include "zgetdump.h"
|
||||||
|
#include "dfi_mem_chunk.h"
|
||||||
|
#include "dfi_vmcoreinfo.h"
|
||||||
|
#include "dfi.h"
|
||||||
|
|
||||||
#define TIME_FMT_STR "%a, %d %b %Y %H:%M:%S %z"
|
#define TIME_FMT_STR "%a, %d %b %Y %H:%M:%S %z"
|
||||||
#define PROGRESS_HASH_CNT 50
|
#define PROGRESS_HASH_CNT 50
|
||||||
|
|
||||||
|
#define KDUMP_OLDMEM_BASE 0x10418
|
||||||
|
#define KDUMP_OLDMEM_SIZE 0x10420
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DFI vector - ensure that tape is the first in the list and devmem the second!
|
* DFI vector - ensure that tape is the first in the list and devmem the second!
|
||||||
*/
|
*/
|
||||||
@@ -47,17 +54,6 @@ struct cpus {
|
|||||||
unsigned int cnt;
|
unsigned int cnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Memory information
|
|
||||||
*/
|
|
||||||
struct mem {
|
|
||||||
struct dfi_mem_chunk *chunk_cache;
|
|
||||||
u64 start_addr;
|
|
||||||
u64 end_addr;
|
|
||||||
unsigned int chunk_cnt;
|
|
||||||
struct util_list chunk_list;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dump header attribute information
|
* Dump header attribute information
|
||||||
*/
|
*/
|
||||||
@@ -81,8 +77,6 @@ struct attr {
|
|||||||
static struct {
|
static struct {
|
||||||
enum dfi_arch arch;
|
enum dfi_arch arch;
|
||||||
struct attr attr;
|
struct attr attr;
|
||||||
struct mem mem_phys;
|
|
||||||
struct mem mem_virt;
|
|
||||||
struct cpus cpus;
|
struct cpus cpus;
|
||||||
struct dfi *dfi;
|
struct dfi *dfi;
|
||||||
unsigned long kdump_base;
|
unsigned long kdump_base;
|
||||||
@@ -109,125 +103,6 @@ static void date_print(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize DFI memory chunks
|
|
||||||
*/
|
|
||||||
static void mem_init(struct mem *mem)
|
|
||||||
{
|
|
||||||
mem->start_addr = U64_MAX;
|
|
||||||
mem->end_addr = 0;
|
|
||||||
util_list_init(&mem->chunk_list, struct dfi_mem_chunk, list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Memory chunk compare function for list sorting
|
|
||||||
*/
|
|
||||||
static int mem_chunk_cmp_fn(void *a, void *b, void *UNUSED(data))
|
|
||||||
{
|
|
||||||
struct dfi_mem_chunk *mem_chunk1 = a;
|
|
||||||
struct dfi_mem_chunk *mem_chunk2 = b;
|
|
||||||
|
|
||||||
return mem_chunk1->start < mem_chunk2->start ? -1 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Update DFI memory chunks
|
|
||||||
*/
|
|
||||||
static void mem_update(struct mem *mem)
|
|
||||||
{
|
|
||||||
struct dfi_mem_chunk *mem_chunk;
|
|
||||||
|
|
||||||
util_list_sort(&mem->chunk_list, mem_chunk_cmp_fn, NULL);
|
|
||||||
mem->start_addr = U64_MAX;
|
|
||||||
mem->end_addr = 0;
|
|
||||||
util_list_iterate(&mem->chunk_list, mem_chunk) {
|
|
||||||
mem->start_addr = MIN(mem->start_addr, mem_chunk->start);
|
|
||||||
mem->end_addr = MAX(mem->end_addr, mem_chunk->end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Print memory map
|
|
||||||
*/
|
|
||||||
static void mem_map_print(void)
|
|
||||||
{
|
|
||||||
struct dfi_mem_chunk *mem_chunk;
|
|
||||||
u64 print_start = 0, print_end = 0;
|
|
||||||
const char *zero_str;
|
|
||||||
u32 volnr = 0;
|
|
||||||
|
|
||||||
STDERR("\nMemory map:\n");
|
|
||||||
/*
|
|
||||||
* Print each memory chunk if verbose specified
|
|
||||||
*/
|
|
||||||
if (g.opts.verbose_specified) {
|
|
||||||
dfi_mem_chunk_iterate(mem_chunk) {
|
|
||||||
zero_str = "";
|
|
||||||
if (mem_chunk->read_fn == dfi_mem_chunk_read_zero)
|
|
||||||
zero_str = " zeroes";
|
|
||||||
STDERR(" %016llx - %016llx (%llu MB%s)\n",
|
|
||||||
mem_chunk->start, mem_chunk->end,
|
|
||||||
TO_MIB(mem_chunk->size), zero_str);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Merge adjacent memory chunks from the same volume
|
|
||||||
*/
|
|
||||||
dfi_mem_chunk_iterate(mem_chunk) {
|
|
||||||
if (print_end == 0) {
|
|
||||||
print_start = mem_chunk->start;
|
|
||||||
print_end = mem_chunk->end;
|
|
||||||
volnr = mem_chunk->volnr;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (mem_chunk->start != print_end + 1 ||
|
|
||||||
mem_chunk->volnr != volnr) {
|
|
||||||
STDERR(" %016llx - %016llx (%llu MB)\n", print_start,
|
|
||||||
print_end, TO_MIB(print_end - print_start + 1));
|
|
||||||
print_start = mem_chunk->start;
|
|
||||||
volnr = mem_chunk->volnr;
|
|
||||||
}
|
|
||||||
print_end = mem_chunk->end;
|
|
||||||
}
|
|
||||||
STDERR(" %016llx - %016llx (%llu MB)\n", print_start,
|
|
||||||
print_end, TO_MIB(print_end - print_start + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Is memory range valid?
|
|
||||||
*/
|
|
||||||
int dfi_mem_range_valid(u64 addr, u64 len)
|
|
||||||
{
|
|
||||||
struct dfi_mem_chunk *mem_chunk;
|
|
||||||
u64 addr_end = addr + len;
|
|
||||||
|
|
||||||
do {
|
|
||||||
mem_chunk = dfi_mem_chunk_find(addr);
|
|
||||||
if (!mem_chunk)
|
|
||||||
return 0;
|
|
||||||
addr += MIN(len, mem_chunk->end - addr + 1);
|
|
||||||
} while (addr < addr_end);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Is memory already mapped at range?
|
|
||||||
*/
|
|
||||||
static int mem_range_mapped(u64 start, u64 size)
|
|
||||||
{
|
|
||||||
struct dfi_mem_chunk *mem_chunk;
|
|
||||||
u64 end = start + size - 1;
|
|
||||||
|
|
||||||
dfi_mem_chunk_iterate(mem_chunk) {
|
|
||||||
if (mem_chunk->start > end)
|
|
||||||
continue;
|
|
||||||
if (mem_chunk->end < start)
|
|
||||||
continue;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* Print dump information (--info option)
|
* Print dump information (--info option)
|
||||||
*/
|
*/
|
||||||
@@ -236,7 +111,7 @@ void dfi_info_print(void)
|
|||||||
STDERR("General dump info:\n");
|
STDERR("General dump info:\n");
|
||||||
STDERR(" Dump format........: %s\n", l.dfi->name);
|
STDERR(" Dump format........: %s\n", l.dfi->name);
|
||||||
if (l.attr.dfi_version)
|
if (l.attr.dfi_version)
|
||||||
STDERR(" Version............: %d\n", *l.attr.dfi_version);
|
STDERR(" Version............: %u\n", *l.attr.dfi_version);
|
||||||
date_print();
|
date_print();
|
||||||
if (l.attr.dump_method)
|
if (l.attr.dump_method)
|
||||||
STDERR(" Dump method........: %s\n", l.attr.dump_method);
|
STDERR(" Dump method........: %s\n", l.attr.dump_method);
|
||||||
@@ -248,259 +123,32 @@ void dfi_info_print(void)
|
|||||||
STDERR(" UTS kernel version.: %s\n", l.attr.utsname->version);
|
STDERR(" UTS kernel version.: %s\n", l.attr.utsname->version);
|
||||||
}
|
}
|
||||||
if (l.attr.vol_nr)
|
if (l.attr.vol_nr)
|
||||||
STDERR(" Volume number......: %d\n", *l.attr.vol_nr);
|
STDERR(" Volume number......: %u\n", *l.attr.vol_nr);
|
||||||
if (l.attr.build_arch)
|
if (l.attr.build_arch)
|
||||||
STDERR(" Build arch.........: %s\n",
|
STDERR(" Build arch.........: %s\n",
|
||||||
dfi_arch_str(*l.attr.build_arch));
|
dfi_arch_str(*l.attr.build_arch));
|
||||||
STDERR(" System arch........: %s\n", dfi_arch_str(l.arch));
|
STDERR(" System arch........: %s\n", dfi_arch_str(l.arch));
|
||||||
if (l.cpus.cnt)
|
if (l.cpus.cnt)
|
||||||
STDERR(" CPU count (online).: %d\n", l.cpus.cnt);
|
STDERR(" CPU count (online).: %u\n", l.cpus.cnt);
|
||||||
if (l.attr.real_cpu_cnt)
|
if (l.attr.real_cpu_cnt)
|
||||||
STDERR(" CPU count (real)...: %d\n", *l.attr.real_cpu_cnt);
|
STDERR(" CPU count (real)...: %u\n", *l.attr.real_cpu_cnt);
|
||||||
if (dfi_mem_range())
|
if (dfi_mem_range())
|
||||||
STDERR(" Dump memory range..: %lld MB\n",
|
STDERR(" Dump memory range..: %lld MB\n",
|
||||||
TO_MIB(dfi_mem_range()));
|
TO_MIB(dfi_mem_range()));
|
||||||
if (l.attr.mem_size_real)
|
if (l.attr.mem_size_real)
|
||||||
STDERR(" Real memory range..: %lld MB\n",
|
STDERR(" Real memory range..: %lld MB\n",
|
||||||
TO_MIB(*l.attr.mem_size_real));
|
TO_MIB(*l.attr.mem_size_real));
|
||||||
if (l.attr.file_size)
|
if (l.attr.file_size)
|
||||||
STDERR(" Dump file size.....: %lld MB\n",
|
STDERR(" Dump file size.....: %lld MB\n",
|
||||||
TO_MIB(*l.attr.file_size));
|
TO_MIB(*l.attr.file_size));
|
||||||
if (dfi_mem_range())
|
if (dfi_mem_range())
|
||||||
mem_map_print();
|
dfi_mem_map_print(g.opts.verbose);
|
||||||
if (l.dfi->info_dump) {
|
if (l.dfi->info_dump) {
|
||||||
STDERR("\nDump device info:\n");
|
STDERR("\nDump device info:\n");
|
||||||
l.dfi->info_dump();
|
l.dfi->info_dump();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Add memory chunk to memory
|
|
||||||
*/
|
|
||||||
static void mem_chunk_create(struct mem *mem, u64 start, u64 size, void *data,
|
|
||||||
dfi_mem_chunk_read_fn read_fn,
|
|
||||||
dfi_mem_chunk_free_fn free_fn)
|
|
||||||
{
|
|
||||||
struct dfi_mem_chunk *mem_chunk;
|
|
||||||
|
|
||||||
mem_chunk = zg_alloc(sizeof(*mem_chunk));
|
|
||||||
mem_chunk->start = start;
|
|
||||||
mem_chunk->end = start + size - 1;
|
|
||||||
mem_chunk->size = size;
|
|
||||||
mem_chunk->read_fn = read_fn;
|
|
||||||
mem_chunk->free_fn = free_fn;
|
|
||||||
mem_chunk->data = data;
|
|
||||||
|
|
||||||
util_list_add_tail(&mem->chunk_list, mem_chunk);
|
|
||||||
mem->start_addr = MIN(mem->start_addr, mem_chunk->start);
|
|
||||||
mem->end_addr = MAX(mem->end_addr, mem_chunk->end);
|
|
||||||
mem->chunk_cache = mem_chunk;
|
|
||||||
mem->chunk_cnt++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if memory chunk contains address
|
|
||||||
*/
|
|
||||||
static int mem_chunk_has_addr(struct dfi_mem_chunk *mem_chunk, u64 addr)
|
|
||||||
{
|
|
||||||
return (addr >= mem_chunk->start && addr <= mem_chunk->end);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Find memory chunk that contains address
|
|
||||||
*/
|
|
||||||
static struct dfi_mem_chunk *mem_chunk_find(struct mem *mem, u64 addr)
|
|
||||||
{
|
|
||||||
struct dfi_mem_chunk *mem_chunk;
|
|
||||||
|
|
||||||
if (mem_chunk_has_addr(mem->chunk_cache, addr))
|
|
||||||
return mem->chunk_cache;
|
|
||||||
util_list_iterate(&mem->chunk_list, mem_chunk) {
|
|
||||||
if (mem_chunk_has_addr(mem_chunk, addr)) {
|
|
||||||
mem->chunk_cache = mem_chunk;
|
|
||||||
return mem_chunk;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read memory at given address
|
|
||||||
*/
|
|
||||||
static void mem_read(struct mem *mem, u64 addr, void *buf, size_t cnt)
|
|
||||||
{
|
|
||||||
struct dfi_mem_chunk *mem_chunk;
|
|
||||||
u64 size, off, copied = 0;
|
|
||||||
|
|
||||||
while (copied != cnt) {
|
|
||||||
mem_chunk = mem_chunk_find(mem, addr);
|
|
||||||
size = MIN(cnt - copied, mem_chunk->end - addr + 1);
|
|
||||||
off = addr - mem_chunk->start;
|
|
||||||
mem_chunk->read_fn(mem_chunk, off, buf + copied, size);
|
|
||||||
copied += size;
|
|
||||||
addr += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read memory for virtual map memory chunk
|
|
||||||
*/
|
|
||||||
static void mem_chunk_map_read_fn(struct dfi_mem_chunk *mem_chunk, u64 off,
|
|
||||||
void *buf, u64 cnt)
|
|
||||||
{
|
|
||||||
u64 *start = mem_chunk->data;
|
|
||||||
|
|
||||||
dfi_mem_phys_read(*start + off, buf, cnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if memory chunk is a virtual mapping
|
|
||||||
*/
|
|
||||||
static int mem_chunk_is_map(struct dfi_mem_chunk *mem_chunk)
|
|
||||||
{
|
|
||||||
return mem_chunk->read_fn == mem_chunk_map_read_fn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return physical start address for memory chunk
|
|
||||||
*/
|
|
||||||
static u64 mem_chunk_start_phys(struct dfi_mem_chunk *mem_chunk)
|
|
||||||
{
|
|
||||||
if (mem_chunk_is_map(mem_chunk))
|
|
||||||
return *((u64 *) mem_chunk->data);
|
|
||||||
else
|
|
||||||
return mem_chunk->start;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add virtual memory chunk with simple virtual mapping
|
|
||||||
*/
|
|
||||||
static void mem_chunk_map_add(u64 start, u64 size, u64 start_p)
|
|
||||||
{
|
|
||||||
u64 *data = zg_alloc(sizeof(*data));
|
|
||||||
|
|
||||||
*data = start_p;
|
|
||||||
dfi_mem_chunk_virt_add(start, size, data, mem_chunk_map_read_fn,
|
|
||||||
zg_free);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add virtual memory chunk
|
|
||||||
*/
|
|
||||||
void dfi_mem_chunk_virt_add(u64 start, u64 size, void *data,
|
|
||||||
dfi_mem_chunk_read_fn read_fn,
|
|
||||||
dfi_mem_chunk_free_fn free_fn)
|
|
||||||
{
|
|
||||||
if (size == 0)
|
|
||||||
return;
|
|
||||||
mem_chunk_create(&l.mem_virt, start, size, data, read_fn, free_fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add memory chunk with volume index
|
|
||||||
*/
|
|
||||||
void dfi_mem_chunk_add_vol(u64 start, u64 size, void *data,
|
|
||||||
dfi_mem_chunk_read_fn read_fn,
|
|
||||||
dfi_mem_chunk_free_fn free_fn,
|
|
||||||
u32 volnr)
|
|
||||||
{
|
|
||||||
if (size == 0)
|
|
||||||
return;
|
|
||||||
mem_chunk_create(&l.mem_phys, start, size, data, read_fn, free_fn);
|
|
||||||
mem_chunk_create(&l.mem_virt, start, size, data, read_fn, NULL);
|
|
||||||
l.mem_virt.chunk_cache->volnr = volnr;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add memory chunk
|
|
||||||
*/
|
|
||||||
void dfi_mem_chunk_add(u64 start, u64 size, void *data,
|
|
||||||
dfi_mem_chunk_read_fn read_fn,
|
|
||||||
dfi_mem_chunk_free_fn free_fn)
|
|
||||||
{
|
|
||||||
dfi_mem_chunk_add_vol(start, size, data, read_fn, free_fn, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read zero pages
|
|
||||||
*/
|
|
||||||
void dfi_mem_chunk_read_zero(struct dfi_mem_chunk *UNUSED(mem_chunk),
|
|
||||||
u64 UNUSED(off), void *buf, u64 cnt)
|
|
||||||
{
|
|
||||||
memset(buf, 0, cnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return mem_chunk list head
|
|
||||||
*/
|
|
||||||
struct util_list *dfi_mem_chunk_list(void)
|
|
||||||
{
|
|
||||||
return &l.mem_virt.chunk_list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return number of memory chunks in input dump
|
|
||||||
*/
|
|
||||||
unsigned int dfi_mem_chunk_cnt(void)
|
|
||||||
{
|
|
||||||
return l.mem_virt.chunk_cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return maximum memory range
|
|
||||||
*/
|
|
||||||
u64 dfi_mem_range(void)
|
|
||||||
{
|
|
||||||
if (l.mem_virt.start_addr == U64_MAX)
|
|
||||||
return 0;
|
|
||||||
return l.mem_virt.end_addr - l.mem_virt.start_addr + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return first memory chunk
|
|
||||||
*/
|
|
||||||
struct dfi_mem_chunk *dfi_mem_chunk_first(void)
|
|
||||||
{
|
|
||||||
if (util_list_is_empty(&l.mem_virt.chunk_list))
|
|
||||||
return NULL;
|
|
||||||
return util_list_start(&l.mem_virt.chunk_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return last memory chunk
|
|
||||||
*/
|
|
||||||
struct dfi_mem_chunk *dfi_mem_chunk_last(void)
|
|
||||||
{
|
|
||||||
if (util_list_is_empty(&l.mem_virt.chunk_list))
|
|
||||||
return NULL;
|
|
||||||
return util_list_end(&l.mem_virt.chunk_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return next memory chunk
|
|
||||||
*/
|
|
||||||
struct dfi_mem_chunk *dfi_mem_chunk_next(struct dfi_mem_chunk *mem_chunk)
|
|
||||||
{
|
|
||||||
return util_list_next(&l.mem_virt.chunk_list, mem_chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return previous memory chunk
|
|
||||||
*/
|
|
||||||
struct dfi_mem_chunk *dfi_mem_chunk_prev(struct dfi_mem_chunk *mem_chunk)
|
|
||||||
{
|
|
||||||
return util_list_prev(&l.mem_virt.chunk_list, mem_chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Find memory chunk for given address
|
|
||||||
*/
|
|
||||||
struct dfi_mem_chunk *dfi_mem_chunk_find(u64 addr)
|
|
||||||
{
|
|
||||||
return mem_chunk_find(&l.mem_virt, addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize CPU info
|
* Initialize CPU info
|
||||||
*/
|
*/
|
||||||
@@ -600,33 +248,6 @@ struct util_list *dfi_cpu_list(void)
|
|||||||
return &l.cpus.list;
|
return &l.cpus.list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Read memory at given address and do kdump swap if necessary
|
|
||||||
*/
|
|
||||||
void dfi_mem_read(u64 addr, void *buf, size_t cnt)
|
|
||||||
{
|
|
||||||
mem_read(&l.mem_virt, addr, buf, cnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read physical memory at given address
|
|
||||||
*/
|
|
||||||
void dfi_mem_phys_read(u64 addr, void *buf, size_t cnt)
|
|
||||||
{
|
|
||||||
mem_read(&l.mem_phys, addr, buf, cnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read memory at given address with return code
|
|
||||||
*/
|
|
||||||
int dfi_mem_read_rc(u64 addr, void *buf, size_t cnt)
|
|
||||||
{
|
|
||||||
if (!dfi_mem_range_valid(addr, cnt))
|
|
||||||
return -EINVAL;
|
|
||||||
dfi_mem_read(addr, buf, cnt);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get input dump format name
|
* Get input dump format name
|
||||||
*/
|
*/
|
||||||
@@ -665,6 +286,7 @@ const char *dfi_arch_str(enum dfi_arch arch)
|
|||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
ABORT("dfi_arch_str: Invalid dfi arch: %d", arch);
|
ABORT("dfi_arch_str: Invalid dfi arch: %d", arch);
|
||||||
|
return NULL; /* UNREACHABLE */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -886,7 +508,7 @@ static void lc2cpu_64(struct dfi_cpu *cpu, struct dfi_lowcore_64 *lc)
|
|||||||
/* Add VX registers if available */
|
/* Add VX registers if available */
|
||||||
if (!dfi_cpu_lc_has_vx_sa(lc))
|
if (!dfi_cpu_lc_has_vx_sa(lc))
|
||||||
return;
|
return;
|
||||||
if (dfi_mem_read_rc(lc->vector_save_area_addr, &vx_sa, sizeof(vx_sa))) {
|
if (dfi_mem_virt_read(lc->vector_save_area_addr, &vx_sa, sizeof(vx_sa))) {
|
||||||
STDERR("zgetdump: Vector registers save area is beyond dump memory limit for CPU %d\n", cpu->cpu_id);
|
STDERR("zgetdump: Vector registers save area is beyond dump memory limit for CPU %d\n", cpu->cpu_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -917,7 +539,7 @@ static void lc2cpu_32(struct dfi_cpu_32 *cpu, struct dfi_lowcore_32 *lc)
|
|||||||
* Note: When this function is called, the memory chunks have to be already
|
* Note: When this function is called, the memory chunks have to be already
|
||||||
* defined by the DFI dump specific code.
|
* defined by the DFI dump specific code.
|
||||||
*/
|
*/
|
||||||
void dfi_cpu_add_from_lc(u32 lc_addr)
|
int dfi_cpu_add_from_lc(u32 lc_addr)
|
||||||
{
|
{
|
||||||
struct dfi_cpu *cpu = dfi_cpu_alloc();
|
struct dfi_cpu *cpu = dfi_cpu_alloc();
|
||||||
|
|
||||||
@@ -930,12 +552,14 @@ void dfi_cpu_add_from_lc(u32 lc_addr)
|
|||||||
if (l.arch == DFI_ARCH_32) {
|
if (l.arch == DFI_ARCH_32) {
|
||||||
struct dfi_cpu_32 cpu_32;
|
struct dfi_cpu_32 cpu_32;
|
||||||
struct dfi_lowcore_32 lc;
|
struct dfi_lowcore_32 lc;
|
||||||
dfi_mem_read(lc_addr, &lc, sizeof(lc));
|
if (dfi_mem_virt_read(lc_addr, &lc, sizeof(lc)))
|
||||||
|
return -EINVAL;
|
||||||
lc2cpu_32(&cpu_32, &lc);
|
lc2cpu_32(&cpu_32, &lc);
|
||||||
cpu_32_to_64(cpu, &cpu_32);
|
cpu_32_to_64(cpu, &cpu_32);
|
||||||
} else {
|
} else {
|
||||||
struct dfi_lowcore_64 lc;
|
struct dfi_lowcore_64 lc;
|
||||||
dfi_mem_read(lc_addr, &lc, sizeof(lc));
|
if (dfi_mem_virt_read(lc_addr, &lc, sizeof(lc)))
|
||||||
|
return -EINVAL;
|
||||||
lc2cpu_64(cpu, &lc);
|
lc2cpu_64(cpu, &lc);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -943,6 +567,7 @@ void dfi_cpu_add_from_lc(u32 lc_addr)
|
|||||||
ABORT("dfi_cpu_add_from_lc() called for CONTENT_NONE");
|
ABORT("dfi_cpu_add_from_lc() called for CONTENT_NONE");
|
||||||
}
|
}
|
||||||
dfi_cpu_add(cpu);
|
dfi_cpu_add(cpu);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -984,89 +609,6 @@ unsigned long dfi_kdump_base(void)
|
|||||||
return l.kdump_base;
|
return l.kdump_base;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Unmap memory region
|
|
||||||
*/
|
|
||||||
static void mem_unmap(u64 start, u64 size)
|
|
||||||
{
|
|
||||||
u64 start_phys, end_phys, addr_phys, addr_virt, size_virt;
|
|
||||||
struct dfi_mem_chunk *mem_chunk, *tmp;
|
|
||||||
u64 end = start + size - 1;
|
|
||||||
|
|
||||||
util_list_iterate_safe(&l.mem_virt.chunk_list, mem_chunk, tmp) {
|
|
||||||
/*
|
|
||||||
* Chunk not hit?
|
|
||||||
*/
|
|
||||||
if (mem_chunk->start >= start + size)
|
|
||||||
continue;
|
|
||||||
if (mem_chunk->end < start)
|
|
||||||
continue;
|
|
||||||
/*
|
|
||||||
* Chunk completely unmapped
|
|
||||||
*
|
|
||||||
* UNMAP: UUUUUUUUU || UUUUUU
|
|
||||||
* CHUNK: CCCC || CCCCCC
|
|
||||||
* TO:
|
|
||||||
*/
|
|
||||||
if (mem_chunk->start >= start && mem_chunk->end <= end)
|
|
||||||
goto free;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get real start and end addresses
|
|
||||||
*/
|
|
||||||
start_phys = mem_chunk_start_phys(mem_chunk);
|
|
||||||
end_phys = start_phys + mem_chunk->size - 1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Chunk hit at start or in the middle?
|
|
||||||
*
|
|
||||||
* UNMAP: UUUUUU || UU || UUU
|
|
||||||
* CHUNK: CCCCC || CCCCCC || CCCC
|
|
||||||
* TO: NN || NN || NNN
|
|
||||||
*/
|
|
||||||
if (mem_chunk->end > end) {
|
|
||||||
addr_virt = end + 1;
|
|
||||||
size_virt = mem_chunk->end - end;
|
|
||||||
addr_phys = end_phys - size_virt + 1;
|
|
||||||
mem_chunk_map_add(addr_virt, size_virt, addr_phys);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Chunk hit at end or in the middle?
|
|
||||||
*
|
|
||||||
* UNMAP: UUUUUU || UU || UUU
|
|
||||||
* CHUNK: CCCCC || CCCCCC || CCC
|
|
||||||
* TO: NN || NN || NN
|
|
||||||
*/
|
|
||||||
if (mem_chunk->start < start) {
|
|
||||||
addr_virt = mem_chunk->start;
|
|
||||||
size_virt = start - addr_virt;
|
|
||||||
addr_phys = start_phys;
|
|
||||||
mem_chunk_map_add(addr_virt, size_virt, addr_phys);
|
|
||||||
}
|
|
||||||
free:
|
|
||||||
util_list_remove(&l.mem_virt.chunk_list, mem_chunk);
|
|
||||||
l.mem_virt.chunk_cnt--;
|
|
||||||
if (mem_chunk->data && mem_chunk->free_fn)
|
|
||||||
mem_chunk->free_fn(mem_chunk->data);
|
|
||||||
zg_free(mem_chunk);
|
|
||||||
}
|
|
||||||
mem_update(&l.mem_virt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Map memory region
|
|
||||||
*/
|
|
||||||
static void mem_map(u64 start, u64 size, u64 start_phys)
|
|
||||||
{
|
|
||||||
if (mem_range_mapped(start, size)) {
|
|
||||||
mem_map_print();
|
|
||||||
ABORT("Map request for already mapped region (%llx/%llx/%llx)",
|
|
||||||
start, size, start_phys);
|
|
||||||
}
|
|
||||||
mem_chunk_map_add(start, size, start_phys);
|
|
||||||
mem_update(&l.mem_virt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if dump contains a kdump dump and initialize kdump_base and kdump_size
|
* Check if dump contains a kdump dump and initialize kdump_base and kdump_size
|
||||||
*/
|
*/
|
||||||
@@ -1074,8 +616,12 @@ static void kdump_init(void)
|
|||||||
{
|
{
|
||||||
unsigned long base, size;
|
unsigned long base, size;
|
||||||
|
|
||||||
dfi_mem_phys_read(0x10418, &base, sizeof(base));
|
util_log_print(UTIL_LOG_TRACE, "DFI kdump initialization\n");
|
||||||
dfi_mem_phys_read(0x10420, &size, sizeof(size));
|
|
||||||
|
if (dfi_mem_phys_read(KDUMP_OLDMEM_BASE, &base, sizeof(base)))
|
||||||
|
return;
|
||||||
|
if (dfi_mem_phys_read(KDUMP_OLDMEM_SIZE, &size, sizeof(size)))
|
||||||
|
return;
|
||||||
if (base == 0 || size == 0)
|
if (base == 0 || size == 0)
|
||||||
return;
|
return;
|
||||||
if (base % MIB || size % MIB)
|
if (base % MIB || size % MIB)
|
||||||
@@ -1084,6 +630,9 @@ static void kdump_init(void)
|
|||||||
return;
|
return;
|
||||||
l.kdump_base = base;
|
l.kdump_base = base;
|
||||||
l.kdump_size = size;
|
l.kdump_size = size;
|
||||||
|
util_log_print(UTIL_LOG_INFO,
|
||||||
|
"DFI found valid kdump base 0x%016lx size 0x%016lx\n",
|
||||||
|
l.kdump_base, l.kdump_size);
|
||||||
/*
|
/*
|
||||||
* For dumped kdump and user has selected "prod" we swap
|
* For dumped kdump and user has selected "prod" we swap
|
||||||
* the crashkernel memory with old memory. If user selected "kdump",
|
* the crashkernel memory with old memory. If user selected "kdump",
|
||||||
@@ -1093,11 +642,11 @@ static void kdump_init(void)
|
|||||||
if (!g.opts.select_specified)
|
if (!g.opts.select_specified)
|
||||||
return;
|
return;
|
||||||
if (g.opts.select == OPTS_SELECT_PROD) {
|
if (g.opts.select == OPTS_SELECT_PROD) {
|
||||||
mem_unmap(0, size);
|
dfi_mem_unmap(0, size);
|
||||||
mem_unmap(base, size);
|
dfi_mem_unmap(base, size);
|
||||||
mem_map(0, size, base);
|
dfi_mem_map(0, size, base);
|
||||||
} else if (g.opts.select == OPTS_SELECT_KDUMP) {
|
} else if (g.opts.select == OPTS_SELECT_KDUMP) {
|
||||||
mem_unmap(l.kdump_size, U64_MAX - l.kdump_size);
|
dfi_mem_unmap(l.kdump_size, U64_MAX - l.kdump_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1126,8 +675,8 @@ static void kdump_select_prod_init(void)
|
|||||||
}
|
}
|
||||||
dfi_cpu_info_init(DFI_CPU_CONTENT_ALL);
|
dfi_cpu_info_init(DFI_CPU_CONTENT_ALL);
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
if (dfi_mem_read_rc(ptr + i * sizeof(long), &prefix,
|
if (dfi_mem_virt_read(ptr + i * sizeof(long), &prefix,
|
||||||
sizeof(prefix)))
|
sizeof(prefix)))
|
||||||
continue;
|
continue;
|
||||||
if (prefix == 0)
|
if (prefix == 0)
|
||||||
continue;
|
continue;
|
||||||
@@ -1146,9 +695,11 @@ static void utsname_init(void)
|
|||||||
unsigned long ptr;
|
unsigned long ptr;
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
|
|
||||||
|
util_log_print(UTIL_LOG_TRACE, "DFI utsname initialization\n");
|
||||||
|
|
||||||
if (dfi_vmcoreinfo_symbol(&ptr, "init_uts_ns"))
|
if (dfi_vmcoreinfo_symbol(&ptr, "init_uts_ns"))
|
||||||
return;
|
return;
|
||||||
if (dfi_mem_read_rc(ptr, buf, sizeof(buf)))
|
if (dfi_mem_virt_read(ptr, buf, sizeof(buf)))
|
||||||
return;
|
return;
|
||||||
utsname = memchr(buf, 'L', sizeof(buf) - sizeof(*utsname));
|
utsname = memchr(buf, 'L', sizeof(buf) - sizeof(*utsname));
|
||||||
if (!utsname)
|
if (!utsname)
|
||||||
@@ -1156,6 +707,8 @@ static void utsname_init(void)
|
|||||||
if (strncmp(utsname->sysname, "Linux", sizeof(utsname->version)) != 0)
|
if (strncmp(utsname->sysname, "Linux", sizeof(utsname->version)) != 0)
|
||||||
return;
|
return;
|
||||||
dfi_attr_utsname_set(utsname);
|
dfi_attr_utsname_set(utsname);
|
||||||
|
util_log_print(UTIL_LOG_INFO, "DFI utsname release %s version %s\n",
|
||||||
|
utsname->release, utsname->version);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1165,7 +718,9 @@ static void livedump_init(void)
|
|||||||
{
|
{
|
||||||
u64 magic;
|
u64 magic;
|
||||||
|
|
||||||
if (dfi_mem_read_rc(0, &magic, sizeof(magic)))
|
util_log_print(UTIL_LOG_TRACE, "DFI livedump initialization\n");
|
||||||
|
|
||||||
|
if (dfi_mem_virt_read(0, &magic, sizeof(magic)))
|
||||||
return;
|
return;
|
||||||
if (magic == dfi_live_dump_magic)
|
if (magic == dfi_live_dump_magic)
|
||||||
dfi_attr_dump_method_set(DFI_DUMP_METHOD_LIVE);
|
dfi_attr_dump_method_set(DFI_DUMP_METHOD_LIVE);
|
||||||
@@ -1201,12 +756,16 @@ int dfi_init(void)
|
|||||||
struct dfi *dfi;
|
struct dfi *dfi;
|
||||||
int i = 0, rc;
|
int i = 0, rc;
|
||||||
|
|
||||||
|
util_log_print(UTIL_LOG_TRACE, "DFI initialization\n");
|
||||||
|
|
||||||
l.arch = DFI_ARCH_UNKNOWN;
|
l.arch = DFI_ARCH_UNKNOWN;
|
||||||
mem_init(&l.mem_virt);
|
rc = dfi_mem_chunk_init();
|
||||||
mem_init(&l.mem_phys);
|
if (rc)
|
||||||
|
return rc;
|
||||||
attr_init();
|
attr_init();
|
||||||
dfi_cpu_info_init(DFI_CPU_CONTENT_NONE);
|
dfi_cpu_info_init(DFI_CPU_CONTENT_NONE);
|
||||||
while ((dfi = dfi_vec[i])) {
|
while ((dfi = dfi_vec[i])) {
|
||||||
|
util_log_print(UTIL_LOG_DEBUG, "DFI trying %s\n", dfi->name);
|
||||||
l.dfi = dfi;
|
l.dfi = dfi;
|
||||||
g.fh = dfi_dump_open(g.opts.device);
|
g.fh = dfi_dump_open(g.opts.device);
|
||||||
rc = dfi->init();
|
rc = dfi->init();
|
||||||
@@ -1218,12 +777,15 @@ int dfi_init(void)
|
|||||||
utsname_init();
|
utsname_init();
|
||||||
livedump_init();
|
livedump_init();
|
||||||
}
|
}
|
||||||
|
util_log_print(UTIL_LOG_DEBUG, "DFI %s returned with rc %d\n",
|
||||||
|
dfi->name, rc);
|
||||||
if (rc == 0 || rc == -EINVAL)
|
if (rc == 0 || rc == -EINVAL)
|
||||||
return rc;
|
return rc;
|
||||||
zg_close(g.fh);
|
zg_close(g.fh);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
ERR_EXIT("No valid dump found on \"%s\"", g.opts.device);
|
ERR_EXIT("No valid dump found on \"%s\"", g.opts.device);
|
||||||
|
return -1; /* UNREACHABLE */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1231,6 +793,8 @@ int dfi_init(void)
|
|||||||
*/
|
*/
|
||||||
void dfi_exit(void)
|
void dfi_exit(void)
|
||||||
{
|
{
|
||||||
|
util_log_print(UTIL_LOG_TRACE, "DFI exit\n");
|
||||||
|
|
||||||
if (l.dfi && l.dfi->exit)
|
if (l.dfi && l.dfi->exit)
|
||||||
l.dfi->exit();
|
l.dfi->exit();
|
||||||
}
|
}
|
||||||
|
|||||||
+61
-111
@@ -12,13 +12,12 @@
|
|||||||
#ifndef DFI_H
|
#ifndef DFI_H
|
||||||
#define DFI_H
|
#define DFI_H
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
#include <linux/utsname.h>
|
#include <linux/utsname.h>
|
||||||
|
|
||||||
#include "lib/zt_common.h"
|
#include "lib/zt_common.h"
|
||||||
#include "lib/util_list.h"
|
#include "lib/util_list.h"
|
||||||
|
|
||||||
#include "zg.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CPU info functions and definitions
|
* CPU info functions and definitions
|
||||||
*/
|
*/
|
||||||
@@ -116,11 +115,11 @@ struct dfi_cpu_32 {
|
|||||||
struct dfi_vxrs vxrs_high[16];
|
struct dfi_vxrs vxrs_high[16];
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void dfi_cpu_64_to_32(struct dfi_cpu_32 *cpu_32, struct dfi_cpu *cpu_64);
|
void dfi_cpu_64_to_32(struct dfi_cpu_32 *cpu_32, struct dfi_cpu *cpu_64);
|
||||||
|
|
||||||
extern enum dfi_arch dfi_arch(void);
|
enum dfi_arch dfi_arch(void);
|
||||||
extern void dfi_arch_set(enum dfi_arch arch);
|
void dfi_arch_set(enum dfi_arch arch);
|
||||||
extern const char *dfi_arch_str(enum dfi_arch arch);
|
const char *dfi_arch_str(enum dfi_arch arch);
|
||||||
|
|
||||||
enum dfi_cpu_content {
|
enum dfi_cpu_content {
|
||||||
DFI_CPU_CONTENT_NONE, /* No register information available */
|
DFI_CPU_CONTENT_NONE, /* No register information available */
|
||||||
@@ -129,113 +128,62 @@ enum dfi_cpu_content {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define DFI_CPU_CONTENT_FAC_VX 0x00000001
|
#define DFI_CPU_CONTENT_FAC_VX 0x00000001
|
||||||
extern int dfi_cpu_content_fac_check(int flags);
|
int dfi_cpu_content_fac_check(int flags);
|
||||||
extern void dfi_cpu_content_fac_add(int flags);
|
void dfi_cpu_content_fac_add(int flags);
|
||||||
|
|
||||||
#define dfi_cpu_iterate(cpu) \
|
#define dfi_cpu_iterate(cpu) \
|
||||||
util_list_iterate(dfi_cpu_list(), cpu)
|
util_list_iterate(dfi_cpu_list(), cpu)
|
||||||
|
|
||||||
extern struct util_list *dfi_cpu_list(void);
|
struct util_list *dfi_cpu_list(void);
|
||||||
extern void dfi_cpu_info_init(enum dfi_cpu_content content);
|
void dfi_cpu_info_init(enum dfi_cpu_content content);
|
||||||
extern struct dfi_cpu *dfi_cpu_alloc(void);
|
struct dfi_cpu *dfi_cpu_alloc(void);
|
||||||
extern struct dfi_cpu *dfi_cpu(unsigned int cpu_nr);
|
struct dfi_cpu *dfi_cpu(unsigned int cpu_nr);
|
||||||
extern void dfi_cpu_add(struct dfi_cpu *cpu);
|
void dfi_cpu_add(struct dfi_cpu *cpu);
|
||||||
extern unsigned int dfi_cpu_cnt(void);
|
unsigned int dfi_cpu_cnt(void);
|
||||||
extern enum dfi_cpu_content dfi_cpu_content(void);
|
enum dfi_cpu_content dfi_cpu_content(void);
|
||||||
extern void dfi_cpu_add_from_lc(u32 lc_addr);
|
int dfi_cpu_add_from_lc(u32 lc_addr);
|
||||||
|
|
||||||
#define DFI_VX_SA_SIZE (32 * 16)
|
#define DFI_VX_SA_SIZE (32 * 16)
|
||||||
extern int dfi_cpu_lc_has_vx_sa(void *lc);
|
int dfi_cpu_lc_has_vx_sa(void *lc);
|
||||||
extern void dfi_cpu_vx_copy(void *buf, struct dfi_cpu *cpu);
|
void dfi_cpu_vx_copy(void *buf, struct dfi_cpu *cpu);
|
||||||
|
|
||||||
/*
|
|
||||||
* Mem chunk functions and definitions
|
|
||||||
*/
|
|
||||||
struct dfi_mem_chunk;
|
|
||||||
|
|
||||||
typedef void (*dfi_mem_chunk_read_fn)(struct dfi_mem_chunk *mem_chunk,
|
|
||||||
u64 off, void *buf, u64 cnt);
|
|
||||||
typedef void (*dfi_mem_chunk_free_fn)(void *data);
|
|
||||||
|
|
||||||
struct dfi_mem_chunk {
|
|
||||||
struct util_list_node list; /* List */
|
|
||||||
u64 start; /* Start address in memory */
|
|
||||||
u64 end; /* End address in memory */
|
|
||||||
u64 size; /* Size of chunk in dump file */
|
|
||||||
dfi_mem_chunk_read_fn read_fn; /* Chunk read callback */
|
|
||||||
dfi_mem_chunk_free_fn free_fn; /* Free data callback */
|
|
||||||
void *data; /* Data for callback */
|
|
||||||
u32 volnr; /* Volume id where chunk resides */
|
|
||||||
};
|
|
||||||
|
|
||||||
extern void dfi_mem_chunk_read_zero(struct dfi_mem_chunk *UNUSED(mem_chunk),
|
|
||||||
u64 UNUSED(off), void *buf, u64 cnt);
|
|
||||||
extern void dfi_mem_chunk_add_vol(u64 start, u64 size, void *data,
|
|
||||||
dfi_mem_chunk_read_fn read_fn,
|
|
||||||
dfi_mem_chunk_free_fn free_fn,
|
|
||||||
u32 volnr);
|
|
||||||
extern void dfi_mem_chunk_add(u64 start, u64 size, void *data,
|
|
||||||
dfi_mem_chunk_read_fn read_fn,
|
|
||||||
dfi_mem_chunk_free_fn free_fn);
|
|
||||||
extern void dfi_mem_chunk_virt_add(u64 start, u64 size, void *data,
|
|
||||||
dfi_mem_chunk_read_fn read_fn,
|
|
||||||
dfi_mem_chunk_free_fn free_fn);
|
|
||||||
extern u64 dfi_mem_range(void);
|
|
||||||
extern int dfi_mem_range_valid(u64 addr, u64 len);
|
|
||||||
extern unsigned int dfi_mem_chunk_cnt(void);
|
|
||||||
extern struct dfi_mem_chunk *dfi_mem_chunk_first(void);
|
|
||||||
extern struct dfi_mem_chunk *dfi_mem_chunk_last(void);
|
|
||||||
extern struct dfi_mem_chunk *dfi_mem_chunk_next(struct dfi_mem_chunk *chunk);
|
|
||||||
extern struct dfi_mem_chunk *dfi_mem_chunk_prev(struct dfi_mem_chunk *chunk);
|
|
||||||
extern struct dfi_mem_chunk *dfi_mem_chunk_find(u64 addr);
|
|
||||||
|
|
||||||
extern struct util_list *dfi_mem_chunk_list(void);
|
|
||||||
#define dfi_mem_chunk_iterate(mem_chunk) \
|
|
||||||
util_list_iterate(dfi_mem_chunk_list(), mem_chunk)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dump header attribute set/get functions
|
* Dump header attribute set/get functions
|
||||||
*/
|
*/
|
||||||
extern void dfi_attr_time_set(struct timeval *time);
|
void dfi_attr_time_set(struct timeval *time);
|
||||||
extern struct timeval *dfi_attr_time(void);
|
struct timeval *dfi_attr_time(void);
|
||||||
|
|
||||||
extern void dfi_attr_time_end_set(struct timeval *time_end);
|
void dfi_attr_time_end_set(struct timeval *time_end);
|
||||||
extern struct timeval *dfi_attr_time_end(void);
|
struct timeval *dfi_attr_time_end(void);
|
||||||
|
|
||||||
extern void dfi_attr_cpu_id_set(u64 cpu_id);
|
void dfi_attr_cpu_id_set(u64 cpu_id);
|
||||||
extern u64 *dfi_attr_cpu_id(void);
|
u64 *dfi_attr_cpu_id(void);
|
||||||
|
|
||||||
extern void dfi_attr_utsname_set(struct new_utsname *utsname);
|
void dfi_attr_utsname_set(struct new_utsname *utsname);
|
||||||
extern struct new_utsname *dfi_attr_utsname(void);
|
struct new_utsname *dfi_attr_utsname(void);
|
||||||
|
|
||||||
extern void dfi_attr_dump_method_set(char *dump_method);
|
void dfi_attr_dump_method_set(char *dump_method);
|
||||||
extern char *dfi_attr_dump_method(void);
|
char *dfi_attr_dump_method(void);
|
||||||
|
|
||||||
extern void dfi_attr_mem_size_real_set(u64 mem_size_real);
|
void dfi_attr_mem_size_real_set(u64 mem_size_real);
|
||||||
extern u64 *dfi_attr_mem_size_real(void);
|
u64 *dfi_attr_mem_size_real(void);
|
||||||
|
|
||||||
extern void dfi_attr_file_size_set(u64 dump_size);
|
void dfi_attr_file_size_set(u64 dump_size);
|
||||||
extern u64 *dfi_attr_file_size(void);
|
u64 *dfi_attr_file_size(void);
|
||||||
|
|
||||||
extern void dfi_attr_vol_nr_set(unsigned int vol_nr);
|
void dfi_attr_vol_nr_set(unsigned int vol_nr);
|
||||||
extern unsigned int *dfi_attr_vol_nr(void);
|
unsigned int *dfi_attr_vol_nr(void);
|
||||||
|
|
||||||
extern void dfi_attr_version_set(unsigned int dfi_version);
|
void dfi_attr_version_set(unsigned int dfi_version);
|
||||||
extern unsigned int *dfi_attr_dfi_version(void);
|
unsigned int *dfi_attr_dfi_version(void);
|
||||||
|
|
||||||
extern void dfi_attr_build_arch_set(enum dfi_arch build_arch);
|
void dfi_attr_build_arch_set(enum dfi_arch build_arch);
|
||||||
extern enum dfi_arch *dfi_attr_build_arch(void);
|
enum dfi_arch *dfi_attr_build_arch(void);
|
||||||
|
|
||||||
extern void dfi_attr_real_cpu_cnt_set(u32 real_cpu_cnt);
|
void dfi_attr_real_cpu_cnt_set(u32 real_cpu_cnt);
|
||||||
extern u32 *dfi_attr_real_cpu_cnt(void);
|
u32 *dfi_attr_real_cpu_cnt(void);
|
||||||
|
|
||||||
/*
|
void dfi_info_print(void);
|
||||||
* DFI external functions
|
|
||||||
*/
|
|
||||||
extern void dfi_mem_read(u64 addr, void *buf, size_t cnt);
|
|
||||||
extern int dfi_mem_read_rc(u64 addr, void *buf, size_t cnt);
|
|
||||||
extern void dfi_mem_phys_read(u64 addr, void *buf, size_t cnt);
|
|
||||||
extern void dfi_info_print(void);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DFI feature bits
|
* DFI feature bits
|
||||||
@@ -243,25 +191,13 @@ extern void dfi_info_print(void);
|
|||||||
#define DFI_FEAT_SEEK 0x1 /* Necessary for fuse mount */
|
#define DFI_FEAT_SEEK 0x1 /* Necessary for fuse mount */
|
||||||
#define DFI_FEAT_COPY 0x2 /* Necessary for stdout */
|
#define DFI_FEAT_COPY 0x2 /* Necessary for stdout */
|
||||||
|
|
||||||
extern int dfi_feat_seek(void);
|
int dfi_feat_seek(void);
|
||||||
extern int dfi_feat_copy(void);
|
int dfi_feat_copy(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DFI kdump functions
|
* DFI kdump functions
|
||||||
*/
|
*/
|
||||||
extern unsigned long dfi_kdump_base(void);
|
unsigned long dfi_kdump_base(void);
|
||||||
|
|
||||||
/*
|
|
||||||
* DFI vmcoreinfo functions
|
|
||||||
*/
|
|
||||||
extern void dfi_vmcoreinfo_init(void);
|
|
||||||
extern char *dfi_vmcoreinfo_get(void);
|
|
||||||
extern int dfi_vmcoreinfo_tag(char *str, int len, const char *sym);
|
|
||||||
extern int dfi_vmcoreinfo_symbol(unsigned long *val, const char *sym);
|
|
||||||
extern int dfi_vmcoreinfo_offset(unsigned long *offs, const char *sym);
|
|
||||||
extern int dfi_vmcoreinfo_size(unsigned long *size, const char *sym);
|
|
||||||
extern int dfi_vmcoreinfo_length(unsigned long *len, const char *sym);
|
|
||||||
extern int dfi_vmcoreinfo_val(unsigned long *val, const char *sym);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DFI operations
|
* DFI operations
|
||||||
@@ -274,14 +210,14 @@ struct dfi {
|
|||||||
int feat_bits;
|
int feat_bits;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const char *dfi_name(void);
|
const char *dfi_name(void);
|
||||||
extern int dfi_init(void);
|
int dfi_init(void);
|
||||||
extern void dfi_exit(void);
|
void dfi_exit(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dump access
|
* Dump access
|
||||||
*/
|
*/
|
||||||
extern struct zg_fh *dfi_dump_open(const char *path);
|
struct zg_fh *dfi_dump_open(const char *path);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Live dump memory magic
|
* Live dump memory magic
|
||||||
@@ -293,4 +229,18 @@ extern u64 dfi_live_dump_magic;
|
|||||||
*/
|
*/
|
||||||
#define DFI_DUMP_METHOD_LIVE "live"
|
#define DFI_DUMP_METHOD_LIVE "live"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Supported DFI dump formats
|
||||||
|
*/
|
||||||
|
extern struct dfi dfi_s390tape;
|
||||||
|
extern struct dfi dfi_s390mv;
|
||||||
|
extern struct dfi dfi_s390mv_ext;
|
||||||
|
extern struct dfi dfi_s390;
|
||||||
|
extern struct dfi dfi_s390_ext;
|
||||||
|
extern struct dfi dfi_lkcd;
|
||||||
|
extern struct dfi dfi_elf;
|
||||||
|
extern struct dfi dfi_kdump;
|
||||||
|
extern struct dfi dfi_kdump_flat;
|
||||||
|
extern struct dfi dfi_devmem;
|
||||||
|
|
||||||
#endif /* DFI_H */
|
#endif /* DFI_H */
|
||||||
|
|||||||
@@ -21,6 +21,9 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "zgetdump.h"
|
#include "zgetdump.h"
|
||||||
|
#include "df_s390.h"
|
||||||
|
#include "dfi.h"
|
||||||
|
#include "dfi_mem_chunk.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add live dump magic to buffer
|
* Add live dump magic to buffer
|
||||||
|
|||||||
+72
-41
@@ -16,7 +16,14 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "lib/util_libc.h"
|
||||||
|
#include "lib/util_log.h"
|
||||||
|
|
||||||
#include "zgetdump.h"
|
#include "zgetdump.h"
|
||||||
|
#include "zg.h"
|
||||||
|
#include "df_elf.h"
|
||||||
|
#include "dfi.h"
|
||||||
|
#include "dfi_mem_chunk.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read memory for given memory chunk
|
* Read memory for given memory chunk
|
||||||
@@ -37,56 +44,68 @@ static int pt_load_add(Elf64_Phdr *phdr)
|
|||||||
{
|
{
|
||||||
u64 *off_ptr;
|
u64 *off_ptr;
|
||||||
|
|
||||||
|
util_log_print(UTIL_LOG_DEBUG,
|
||||||
|
"DFI ELF p_paddr 0x%016lx p_vaddr 0x%016lx p_offset 0x%016lx p_filesz 0x%016lx p_memsz 0x%016lx\n",
|
||||||
|
phdr->p_paddr, phdr->p_vaddr, phdr->p_offset,
|
||||||
|
phdr->p_filesz, phdr->p_memsz);
|
||||||
|
|
||||||
if (phdr->p_paddr != phdr->p_vaddr) {
|
if (phdr->p_paddr != phdr->p_vaddr) {
|
||||||
phdr->p_paddr = phdr->p_vaddr;
|
phdr->p_paddr = phdr->p_vaddr;
|
||||||
STDERR("Dump file \"%s\" is a user space core dump\n",
|
STDERR("Dump file \"%s\" is a user space core dump\n",
|
||||||
g.opts.device);
|
g.opts.device);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
if (phdr->p_memsz == 0)
|
||||||
|
return -EINVAL;
|
||||||
if (phdr->p_offset + phdr->p_filesz > zg_size(g.fh))
|
if (phdr->p_offset + phdr->p_filesz > zg_size(g.fh))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (phdr->p_filesz == 0) {
|
if (phdr->p_filesz > phdr->p_memsz)
|
||||||
/* Add zero memory chunk */
|
return -EINVAL;
|
||||||
dfi_mem_chunk_add(phdr->p_paddr, phdr->p_memsz, NULL,
|
if (phdr->p_filesz > 0) {
|
||||||
dfi_mem_chunk_read_zero, NULL);
|
|
||||||
} else {
|
|
||||||
off_ptr = zg_alloc(sizeof(*off_ptr));
|
off_ptr = zg_alloc(sizeof(*off_ptr));
|
||||||
*off_ptr = phdr->p_offset;
|
*off_ptr = phdr->p_offset;
|
||||||
dfi_mem_chunk_add(phdr->p_paddr, phdr->p_memsz, off_ptr,
|
dfi_mem_chunk_add(phdr->p_paddr, phdr->p_filesz, off_ptr,
|
||||||
dfi_elf_mem_chunk_read_fn, zg_free);
|
dfi_elf_mem_chunk_read_fn, zg_free);
|
||||||
}
|
}
|
||||||
|
if (phdr->p_memsz - phdr->p_filesz > 0) {
|
||||||
|
/* Add zero memory chunk */
|
||||||
|
dfi_mem_chunk_add(phdr->p_paddr + phdr->p_filesz,
|
||||||
|
phdr->p_memsz - phdr->p_filesz, NULL,
|
||||||
|
dfi_mem_chunk_read_zero, NULL);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Skip name of note
|
|
||||||
*/
|
|
||||||
static void nt_name_skip(Elf64_Nhdr *note)
|
|
||||||
{
|
|
||||||
zg_seek_cur(g.fh, ROUNDUP(note->n_namesz, 4), ZG_CHECK);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read note
|
* Read note
|
||||||
*/
|
*/
|
||||||
static int nt_read(Elf64_Nhdr *note, void *buf)
|
static int nt_read(const Elf64_Nhdr *note, void *buf, size_t buf_len)
|
||||||
{
|
{
|
||||||
off_t buf_len = ROUNDUP(note->n_descsz, 4);
|
ssize_t nread;
|
||||||
char tmp_buf[buf_len];
|
|
||||||
|
|
||||||
nt_name_skip(note);
|
/* We cannot read more than the current note provides */
|
||||||
if (zg_read(g.fh, tmp_buf, buf_len, ZG_CHECK_ERR) != buf_len)
|
if (note->n_descsz < buf_len)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (buf)
|
/* Skip note's name and position file at note's descriptor */
|
||||||
memcpy(buf, tmp_buf, note->n_descsz);
|
zg_seek_cur(g.fh, ROUNDUP(note->n_namesz, 4), ZG_CHECK);
|
||||||
|
/* Read note's descriptor */
|
||||||
|
nread = zg_read(g.fh, buf, buf_len, ZG_CHECK_ERR);
|
||||||
|
if (nread < 0 || (size_t)nread != buf_len)
|
||||||
|
return -EINVAL;
|
||||||
|
/* Skip the rest of note's descriptor until the next note */
|
||||||
|
zg_seek_cur(g.fh, ROUNDUP(note->n_descsz, 4) - buf_len, ZG_CHECK);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip note
|
* Skip note
|
||||||
*/
|
*/
|
||||||
static int nt_skip(Elf64_Nhdr *note)
|
static void nt_skip(const Elf64_Nhdr *note)
|
||||||
{
|
{
|
||||||
return nt_read(note, NULL);
|
/* Skip note's name + descriptor and position file at the next note */
|
||||||
|
zg_seek_cur(g.fh,
|
||||||
|
ROUNDUP(note->n_namesz, 4) + ROUNDUP(note->n_descsz, 4),
|
||||||
|
ZG_CHECK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -107,7 +126,7 @@ static struct dfi_cpu *nt_prstatus_read(Elf64_Nhdr *note)
|
|||||||
struct dfi_cpu *cpu = dfi_cpu_alloc();
|
struct dfi_cpu *cpu = dfi_cpu_alloc();
|
||||||
struct nt_prstatus_64 nt_prstatus;
|
struct nt_prstatus_64 nt_prstatus;
|
||||||
|
|
||||||
if (nt_read(note, &nt_prstatus))
|
if (nt_read(note, &nt_prstatus, sizeof(nt_prstatus)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
memcpy(cpu->gprs, &nt_prstatus.gprs, sizeof(cpu->gprs));
|
memcpy(cpu->gprs, &nt_prstatus.gprs, sizeof(cpu->gprs));
|
||||||
@@ -126,7 +145,7 @@ static int nt_fpregset_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
|||||||
struct nt_fpregset_64 nt_fpregset;
|
struct nt_fpregset_64 nt_fpregset;
|
||||||
|
|
||||||
check_cpu(cpu, "FPREGSET");
|
check_cpu(cpu, "FPREGSET");
|
||||||
if (nt_read(note, &nt_fpregset))
|
if (nt_read(note, &nt_fpregset, sizeof(nt_fpregset)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
memcpy(&cpu->fpc, &nt_fpregset.fpc, sizeof(cpu->fpc));
|
memcpy(&cpu->fpc, &nt_fpregset.fpc, sizeof(cpu->fpc));
|
||||||
@@ -140,7 +159,7 @@ static int nt_fpregset_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
|||||||
static int nt_s390_timer_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
static int nt_s390_timer_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
||||||
{
|
{
|
||||||
check_cpu(cpu, "S390_TIMER");
|
check_cpu(cpu, "S390_TIMER");
|
||||||
return nt_read(note, &cpu->timer);
|
return nt_read(note, &cpu->timer, sizeof(cpu->timer));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -149,7 +168,7 @@ static int nt_s390_timer_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
|||||||
static int nt_s390_todcmp_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
static int nt_s390_todcmp_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
||||||
{
|
{
|
||||||
check_cpu(cpu, "S390_TODCMP");
|
check_cpu(cpu, "S390_TODCMP");
|
||||||
return nt_read(note, &cpu->todcmp);
|
return nt_read(note, &cpu->todcmp, sizeof(cpu->todcmp));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -158,7 +177,7 @@ static int nt_s390_todcmp_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
|||||||
static int nt_s390_todpreg_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
static int nt_s390_todpreg_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
||||||
{
|
{
|
||||||
check_cpu(cpu, "S390_TODPREG");
|
check_cpu(cpu, "S390_TODPREG");
|
||||||
return nt_read(note, &cpu->todpreg);
|
return nt_read(note, &cpu->todpreg, sizeof(cpu->todpreg));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -167,7 +186,7 @@ static int nt_s390_todpreg_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
|||||||
static int nt_s390_ctrs_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
static int nt_s390_ctrs_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
||||||
{
|
{
|
||||||
check_cpu(cpu, "S390_CTRS");
|
check_cpu(cpu, "S390_CTRS");
|
||||||
return nt_read(note, &cpu->ctrs);
|
return nt_read(note, &cpu->ctrs, sizeof(cpu->ctrs));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -176,7 +195,7 @@ static int nt_s390_ctrs_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
|||||||
static int nt_s390_prefix_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
static int nt_s390_prefix_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
||||||
{
|
{
|
||||||
check_cpu(cpu, "S390_PREFIX");
|
check_cpu(cpu, "S390_PREFIX");
|
||||||
return nt_read(note, &cpu->prefix);
|
return nt_read(note, &cpu->prefix, sizeof(cpu->prefix));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -185,7 +204,7 @@ static int nt_s390_prefix_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
|||||||
static int nt_s390_vxrs_low_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
static int nt_s390_vxrs_low_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
||||||
{
|
{
|
||||||
check_cpu(cpu, "S390_VXRS_LOW");
|
check_cpu(cpu, "S390_VXRS_LOW");
|
||||||
return nt_read(note, &cpu->vxrs_low);
|
return nt_read(note, &cpu->vxrs_low, sizeof(cpu->vxrs_low));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -194,7 +213,7 @@ static int nt_s390_vxrs_low_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
|||||||
static int nt_s390_vxrs_high_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
static int nt_s390_vxrs_high_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
||||||
{
|
{
|
||||||
check_cpu(cpu, "S390_VXRS_HIGH");
|
check_cpu(cpu, "S390_VXRS_HIGH");
|
||||||
return nt_read(note, &cpu->vxrs_high);
|
return nt_read(note, &cpu->vxrs_high, sizeof(cpu->vxrs_high));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -202,7 +221,6 @@ static int nt_s390_vxrs_high_read(struct dfi_cpu *cpu, Elf64_Nhdr *note)
|
|||||||
*/
|
*/
|
||||||
static int pt_notes_add(Elf64_Phdr *phdr)
|
static int pt_notes_add(Elf64_Phdr *phdr)
|
||||||
{
|
{
|
||||||
u64 start_off = zg_tell(g.fh, ZG_CHECK);
|
|
||||||
struct dfi_cpu *cpu_current = NULL;
|
struct dfi_cpu *cpu_current = NULL;
|
||||||
u64 notes_start_off;
|
u64 notes_start_off;
|
||||||
Elf64_Nhdr note;
|
Elf64_Nhdr note;
|
||||||
@@ -214,6 +232,8 @@ static int pt_notes_add(Elf64_Phdr *phdr)
|
|||||||
rc = zg_read(g.fh, ¬e, sizeof(note), ZG_CHECK_ERR);
|
rc = zg_read(g.fh, ¬e, sizeof(note), ZG_CHECK_ERR);
|
||||||
if (rc != sizeof(note))
|
if (rc != sizeof(note))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
util_log_print(UTIL_LOG_DEBUG, "DFI ELF n_type 0x%x\n",
|
||||||
|
note.n_type);
|
||||||
switch (note.n_type) {
|
switch (note.n_type) {
|
||||||
case NT_PRSTATUS:
|
case NT_PRSTATUS:
|
||||||
cpu_current = nt_prstatus_read(¬e);
|
cpu_current = nt_prstatus_read(¬e);
|
||||||
@@ -255,12 +275,10 @@ static int pt_notes_add(Elf64_Phdr *phdr)
|
|||||||
dfi_cpu_content_fac_add(DFI_CPU_CONTENT_FAC_VX);
|
dfi_cpu_content_fac_add(DFI_CPU_CONTENT_FAC_VX);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (nt_skip(¬e))
|
nt_skip(¬e);
|
||||||
return -EINVAL;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
zg_seek(g.fh, start_off, ZG_CHECK);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,9 +305,11 @@ static int read_elf_hdr(Elf64_Ehdr *ehdr)
|
|||||||
static int dfi_elf_init(void)
|
static int dfi_elf_init(void)
|
||||||
{
|
{
|
||||||
Elf64_Ehdr ehdr;
|
Elf64_Ehdr ehdr;
|
||||||
Elf64_Phdr phdr;
|
Elf64_Phdr *phdr;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
util_log_print(UTIL_LOG_DEBUG, "DFI ELF initialization\n");
|
||||||
|
|
||||||
if (read_elf_hdr(&ehdr) != 0)
|
if (read_elf_hdr(&ehdr) != 0)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
@@ -297,21 +317,32 @@ static int dfi_elf_init(void)
|
|||||||
dfi_arch_set(DFI_ARCH_64);
|
dfi_arch_set(DFI_ARCH_64);
|
||||||
dfi_cpu_info_init(DFI_CPU_CONTENT_ALL);
|
dfi_cpu_info_init(DFI_CPU_CONTENT_ALL);
|
||||||
|
|
||||||
|
phdr = util_malloc(sizeof(*phdr) * ehdr.e_phnum);
|
||||||
|
zg_seek(g.fh, ehdr.e_phoff, ZG_CHECK);
|
||||||
|
zg_read(g.fh, phdr, sizeof(*phdr) * ehdr.e_phnum, ZG_CHECK);
|
||||||
|
util_log_print(UTIL_LOG_DEBUG, "DFI ELF e_phnum %u\n", ehdr.e_phnum);
|
||||||
for (i = 0; i < ehdr.e_phnum; i++) {
|
for (i = 0; i < ehdr.e_phnum; i++) {
|
||||||
zg_read(g.fh, &phdr, sizeof(phdr), ZG_CHECK);
|
util_log_print(UTIL_LOG_DEBUG, "DFI ELF p_type[%d] 0x%lx\n",
|
||||||
switch (phdr.p_type) {
|
i, phdr[i].p_type);
|
||||||
|
switch (phdr[i].p_type) {
|
||||||
case PT_LOAD:
|
case PT_LOAD:
|
||||||
if (pt_load_add(&phdr))
|
if (pt_load_add(&phdr[i])) {
|
||||||
|
free(phdr);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case PT_NOTE:
|
case PT_NOTE:
|
||||||
if (pt_notes_add(&phdr))
|
if (pt_notes_add(&phdr[i])) {
|
||||||
|
free(phdr);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
free(phdr);
|
||||||
|
|
||||||
dfi_attr_version_set(ehdr.e_ident[EI_VERSION]);
|
dfi_attr_version_set(ehdr.e_ident[EI_VERSION]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,12 @@
|
|||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include "zgetdump.h"
|
#include "zgetdump.h"
|
||||||
|
#include "zg.h"
|
||||||
|
#include "dfi.h"
|
||||||
|
#include "dfi_mem_chunk.h"
|
||||||
|
|
||||||
struct df_kdump_hdr {
|
struct df_kdump_hdr {
|
||||||
char signature[8];
|
char signature[8];
|
||||||
|
|||||||
+19
-5
@@ -9,8 +9,15 @@
|
|||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
#include "zgetdump.h"
|
#include "zgetdump.h"
|
||||||
|
#include "zg.h"
|
||||||
|
#include "df_lkcd.h"
|
||||||
|
#include "dfi.h"
|
||||||
|
#include "dfi_mem_chunk.h"
|
||||||
|
|
||||||
#define MEM_HOLE_SIZE_MIN (1024 * 1024)
|
#define MEM_HOLE_SIZE_MIN (1024 * 1024)
|
||||||
#define IDX_KIB 64 /* One index entry per IDX_KIB */
|
#define IDX_KIB 64 /* One index entry per IDX_KIB */
|
||||||
@@ -267,19 +274,25 @@ static int mem_init(void)
|
|||||||
/*
|
/*
|
||||||
* Initialize CPU information
|
* Initialize CPU information
|
||||||
*/
|
*/
|
||||||
static void cpu_init(void)
|
static int cpu_init(void)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (l.hdr_asm.magic != DF_LKCD_MAGIC_ASM) {
|
if (l.hdr_asm.magic != DF_LKCD_MAGIC_ASM) {
|
||||||
/* Old LKCD dump without asm header */
|
/* Old LKCD dump without asm header */
|
||||||
dfi_cpu_info_init(DFI_CPU_CONTENT_NONE);
|
dfi_cpu_info_init(DFI_CPU_CONTENT_NONE);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dfi_cpu_info_init(DFI_CPU_CONTENT_ALL);
|
dfi_cpu_info_init(DFI_CPU_CONTENT_ALL);
|
||||||
for (i = 0; i < l.hdr_asm.cpu_cnt; i++)
|
for (i = 0; i < l.hdr_asm.cpu_cnt; i++) {
|
||||||
dfi_cpu_add_from_lc(l.hdr_asm.lc_vec[i]);
|
rc = dfi_cpu_add_from_lc(l.hdr_asm.lc_vec[i]);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -321,7 +334,8 @@ static int dfi_lkcd_init(void)
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
if (mem_init() != 0)
|
if (mem_init() != 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
cpu_init();
|
if (cpu_init() != 0)
|
||||||
|
return -EINVAL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,527 @@
|
|||||||
|
/*
|
||||||
|
* Copyright IBM Corp. 2001, 2018
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "lib/util_libc.h"
|
||||||
|
#include "lib/util_log.h"
|
||||||
|
|
||||||
|
#include "zg.h"
|
||||||
|
#include "dfi_mem_chunk.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Memory information
|
||||||
|
*/
|
||||||
|
struct mem {
|
||||||
|
struct dfi_mem_chunk *chunk_cache;
|
||||||
|
u64 start_addr;
|
||||||
|
u64 end_addr;
|
||||||
|
unsigned int chunk_cnt;
|
||||||
|
struct util_list chunk_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* File local static data
|
||||||
|
*/
|
||||||
|
static struct {
|
||||||
|
struct mem mem_phys;
|
||||||
|
struct mem mem_virt;
|
||||||
|
} l;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize DFI memory chunks
|
||||||
|
*/
|
||||||
|
static void mem_init(struct mem *mem)
|
||||||
|
{
|
||||||
|
mem->start_addr = U64_MAX;
|
||||||
|
mem->end_addr = 0;
|
||||||
|
util_list_init(&mem->chunk_list, struct dfi_mem_chunk, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Memory chunk compare function for list sorting
|
||||||
|
*/
|
||||||
|
static int mem_chunk_cmp_fn(void *a, void *b, void *UNUSED(data))
|
||||||
|
{
|
||||||
|
struct dfi_mem_chunk *mem_chunk1 = a;
|
||||||
|
struct dfi_mem_chunk *mem_chunk2 = b;
|
||||||
|
|
||||||
|
return mem_chunk1->start < mem_chunk2->start ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update DFI memory chunks
|
||||||
|
*/
|
||||||
|
static void mem_update(struct mem *mem)
|
||||||
|
{
|
||||||
|
struct dfi_mem_chunk *mem_chunk;
|
||||||
|
|
||||||
|
util_list_sort(&mem->chunk_list, mem_chunk_cmp_fn, NULL);
|
||||||
|
mem->start_addr = U64_MAX;
|
||||||
|
mem->end_addr = 0;
|
||||||
|
util_list_iterate(&mem->chunk_list, mem_chunk) {
|
||||||
|
mem->start_addr = MIN(mem->start_addr, mem_chunk->start);
|
||||||
|
mem->end_addr = MAX(mem->end_addr, mem_chunk->end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print memory map
|
||||||
|
*/
|
||||||
|
void dfi_mem_map_print(bool verbose)
|
||||||
|
{
|
||||||
|
struct dfi_mem_chunk *mem_chunk;
|
||||||
|
u64 print_start = 0, print_end = 0;
|
||||||
|
const char *zero_str;
|
||||||
|
u32 volnr = 0;
|
||||||
|
|
||||||
|
STDERR("\nMemory map:\n");
|
||||||
|
/*
|
||||||
|
* Print each memory chunk if verbose specified
|
||||||
|
*/
|
||||||
|
if (verbose) {
|
||||||
|
dfi_mem_chunk_iterate(mem_chunk) {
|
||||||
|
zero_str = "";
|
||||||
|
if (mem_chunk->read_fn == dfi_mem_chunk_read_zero)
|
||||||
|
zero_str = " zeroes";
|
||||||
|
STDERR(" %016llx - %016llx (%llu MB%s)\n",
|
||||||
|
mem_chunk->start, mem_chunk->end,
|
||||||
|
TO_MIB(mem_chunk->size), zero_str);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Merge adjacent memory chunks from the same volume
|
||||||
|
*/
|
||||||
|
dfi_mem_chunk_iterate(mem_chunk) {
|
||||||
|
if (print_end == 0) {
|
||||||
|
print_start = mem_chunk->start;
|
||||||
|
print_end = mem_chunk->end;
|
||||||
|
volnr = mem_chunk->volnr;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (mem_chunk->start != print_end + 1 ||
|
||||||
|
mem_chunk->volnr != volnr) {
|
||||||
|
STDERR(" %016llx - %016llx (%llu MB)\n", print_start,
|
||||||
|
print_end, TO_MIB(print_end - print_start + 1));
|
||||||
|
print_start = mem_chunk->start;
|
||||||
|
volnr = mem_chunk->volnr;
|
||||||
|
}
|
||||||
|
print_end = mem_chunk->end;
|
||||||
|
}
|
||||||
|
STDERR(" %016llx - %016llx (%llu MB)\n", print_start,
|
||||||
|
print_end, TO_MIB(print_end - print_start + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if memory chunk contains address
|
||||||
|
*/
|
||||||
|
static int mem_chunk_has_addr(struct dfi_mem_chunk *mem_chunk, u64 addr)
|
||||||
|
{
|
||||||
|
return (addr >= mem_chunk->start && addr <= mem_chunk->end);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find memory chunk that contains address
|
||||||
|
*/
|
||||||
|
static struct dfi_mem_chunk *mem_chunk_find(struct mem *mem, u64 addr)
|
||||||
|
{
|
||||||
|
struct dfi_mem_chunk *mem_chunk;
|
||||||
|
|
||||||
|
if (mem->chunk_cache && mem_chunk_has_addr(mem->chunk_cache, addr))
|
||||||
|
return mem->chunk_cache;
|
||||||
|
util_list_iterate(&mem->chunk_list, mem_chunk) {
|
||||||
|
if (mem_chunk_has_addr(mem_chunk, addr)) {
|
||||||
|
mem->chunk_cache = mem_chunk;
|
||||||
|
return mem_chunk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Is memory range valid?
|
||||||
|
*/
|
||||||
|
static int mem_range_valid(struct mem *mem, u64 addr, u64 len)
|
||||||
|
{
|
||||||
|
struct dfi_mem_chunk *mem_chunk;
|
||||||
|
u64 addr_end = addr + len;
|
||||||
|
|
||||||
|
/* check for unsigned wrap */
|
||||||
|
if (addr_end < addr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
mem_chunk = mem_chunk_find(mem, addr);
|
||||||
|
if (!mem_chunk)
|
||||||
|
return 0;
|
||||||
|
addr += MIN(len, mem_chunk->end - addr + 1);
|
||||||
|
} while (addr < addr_end);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Is memory already mapped at range?
|
||||||
|
*/
|
||||||
|
static int mem_range_mapped(u64 start, u64 size)
|
||||||
|
{
|
||||||
|
struct dfi_mem_chunk *mem_chunk;
|
||||||
|
u64 end = start + size - 1;
|
||||||
|
|
||||||
|
dfi_mem_chunk_iterate(mem_chunk) {
|
||||||
|
if (mem_chunk->start > end)
|
||||||
|
continue;
|
||||||
|
if (mem_chunk->end < start)
|
||||||
|
continue;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add memory chunk to memory
|
||||||
|
*/
|
||||||
|
static void mem_chunk_create(struct mem *mem, u64 start, u64 size, void *data,
|
||||||
|
dfi_mem_chunk_read_fn read_fn,
|
||||||
|
dfi_mem_chunk_free_fn free_fn)
|
||||||
|
{
|
||||||
|
struct dfi_mem_chunk *mem_chunk;
|
||||||
|
|
||||||
|
mem_chunk = util_malloc(sizeof(*mem_chunk));
|
||||||
|
mem_chunk->start = start;
|
||||||
|
mem_chunk->end = start + size - 1;
|
||||||
|
mem_chunk->size = size;
|
||||||
|
mem_chunk->read_fn = read_fn;
|
||||||
|
mem_chunk->free_fn = free_fn;
|
||||||
|
mem_chunk->data = data;
|
||||||
|
|
||||||
|
util_list_add_tail(&mem->chunk_list, mem_chunk);
|
||||||
|
mem->start_addr = MIN(mem->start_addr, mem_chunk->start);
|
||||||
|
mem->end_addr = MAX(mem->end_addr, mem_chunk->end);
|
||||||
|
mem->chunk_cache = mem_chunk;
|
||||||
|
mem->chunk_cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read memory at given address
|
||||||
|
*/
|
||||||
|
static void mem_read(struct mem *mem, u64 addr, void *buf, size_t cnt)
|
||||||
|
{
|
||||||
|
struct dfi_mem_chunk *mem_chunk;
|
||||||
|
u64 size, off, copied = 0;
|
||||||
|
|
||||||
|
while (copied != cnt) {
|
||||||
|
mem_chunk = mem_chunk_find(mem, addr);
|
||||||
|
size = MIN(cnt - copied, mem_chunk->end - addr + 1);
|
||||||
|
off = addr - mem_chunk->start;
|
||||||
|
mem_chunk->read_fn(mem_chunk, off, buf + copied, size);
|
||||||
|
copied += size;
|
||||||
|
addr += size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read memory for virtual map memory chunk
|
||||||
|
*/
|
||||||
|
static void mem_chunk_map_read_fn(struct dfi_mem_chunk *mem_chunk, u64 off,
|
||||||
|
void *buf, u64 cnt)
|
||||||
|
{
|
||||||
|
u64 *start = mem_chunk->data;
|
||||||
|
|
||||||
|
dfi_mem_phys_read(*start + off, buf, cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if memory chunk is a virtual mapping
|
||||||
|
*/
|
||||||
|
static int mem_chunk_is_map(struct dfi_mem_chunk *mem_chunk)
|
||||||
|
{
|
||||||
|
return mem_chunk->read_fn == mem_chunk_map_read_fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return physical start address for memory chunk
|
||||||
|
*/
|
||||||
|
static u64 mem_chunk_start_phys(struct dfi_mem_chunk *mem_chunk)
|
||||||
|
{
|
||||||
|
if (mem_chunk_is_map(mem_chunk))
|
||||||
|
return *((u64 *) mem_chunk->data);
|
||||||
|
else
|
||||||
|
return mem_chunk->start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add virtual memory chunk
|
||||||
|
*/
|
||||||
|
static void mem_chunk_virt_add(u64 start, u64 size, void *data,
|
||||||
|
dfi_mem_chunk_read_fn read_fn,
|
||||||
|
dfi_mem_chunk_free_fn free_fn)
|
||||||
|
{
|
||||||
|
util_log_print(UTIL_LOG_DEBUG,
|
||||||
|
"DFI add %svirt mem chunk start 0x%016lx size 0x%016lx\n",
|
||||||
|
read_fn == dfi_mem_chunk_read_zero ? "zero " : "",
|
||||||
|
start, size);
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
return;
|
||||||
|
mem_chunk_create(&l.mem_virt, start, size, data, read_fn, free_fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add virtual memory chunk with simple virtual mapping
|
||||||
|
*/
|
||||||
|
static void mem_chunk_map_add(u64 start, u64 size, u64 start_p)
|
||||||
|
{
|
||||||
|
u64 *data = util_malloc(sizeof(*data));
|
||||||
|
|
||||||
|
*data = start_p;
|
||||||
|
mem_chunk_virt_add(start, size, data, mem_chunk_map_read_fn, free);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add memory chunk with volume index
|
||||||
|
*/
|
||||||
|
void dfi_mem_chunk_add_vol(u64 start, u64 size, void *data,
|
||||||
|
dfi_mem_chunk_read_fn read_fn,
|
||||||
|
dfi_mem_chunk_free_fn free_fn,
|
||||||
|
u32 volnr)
|
||||||
|
{
|
||||||
|
util_log_print(UTIL_LOG_DEBUG,
|
||||||
|
"DFI add %svol mem chunk start 0x%016lx size 0x%016lx volnr %u\n",
|
||||||
|
read_fn == dfi_mem_chunk_read_zero ? "zero " : "",
|
||||||
|
start, size, volnr);
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
return;
|
||||||
|
mem_chunk_create(&l.mem_phys, start, size, data, read_fn, free_fn);
|
||||||
|
mem_chunk_create(&l.mem_virt, start, size, data, read_fn, NULL);
|
||||||
|
l.mem_virt.chunk_cache->volnr = volnr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add memory chunk
|
||||||
|
*/
|
||||||
|
void dfi_mem_chunk_add(u64 start, u64 size, void *data,
|
||||||
|
dfi_mem_chunk_read_fn read_fn,
|
||||||
|
dfi_mem_chunk_free_fn free_fn)
|
||||||
|
{
|
||||||
|
dfi_mem_chunk_add_vol(start, size, data, read_fn, free_fn, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read zero pages
|
||||||
|
*/
|
||||||
|
void dfi_mem_chunk_read_zero(struct dfi_mem_chunk *UNUSED(mem_chunk),
|
||||||
|
u64 UNUSED(off), void *buf, u64 cnt)
|
||||||
|
{
|
||||||
|
memset(buf, 0, cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return mem_chunk list head
|
||||||
|
*/
|
||||||
|
struct util_list *dfi_mem_chunk_list(void)
|
||||||
|
{
|
||||||
|
return &l.mem_virt.chunk_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return number of memory chunks in input dump
|
||||||
|
*/
|
||||||
|
unsigned int dfi_mem_chunk_cnt(void)
|
||||||
|
{
|
||||||
|
return l.mem_virt.chunk_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return maximum memory range
|
||||||
|
*/
|
||||||
|
u64 dfi_mem_range(void)
|
||||||
|
{
|
||||||
|
if (l.mem_virt.start_addr == U64_MAX)
|
||||||
|
return 0;
|
||||||
|
return l.mem_virt.end_addr - l.mem_virt.start_addr + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Is memory range valid?
|
||||||
|
*/
|
||||||
|
int dfi_mem_range_valid(u64 addr, u64 len)
|
||||||
|
{
|
||||||
|
return mem_range_valid(&l.mem_virt, addr, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return first memory chunk
|
||||||
|
*/
|
||||||
|
struct dfi_mem_chunk *dfi_mem_chunk_first(void)
|
||||||
|
{
|
||||||
|
if (util_list_is_empty(&l.mem_virt.chunk_list))
|
||||||
|
return NULL;
|
||||||
|
return util_list_start(&l.mem_virt.chunk_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return last memory chunk
|
||||||
|
*/
|
||||||
|
struct dfi_mem_chunk *dfi_mem_chunk_last(void)
|
||||||
|
{
|
||||||
|
if (util_list_is_empty(&l.mem_virt.chunk_list))
|
||||||
|
return NULL;
|
||||||
|
return util_list_end(&l.mem_virt.chunk_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return next memory chunk
|
||||||
|
*/
|
||||||
|
struct dfi_mem_chunk *dfi_mem_chunk_next(struct dfi_mem_chunk *mem_chunk)
|
||||||
|
{
|
||||||
|
return util_list_next(&l.mem_virt.chunk_list, mem_chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return previous memory chunk
|
||||||
|
*/
|
||||||
|
struct dfi_mem_chunk *dfi_mem_chunk_prev(struct dfi_mem_chunk *mem_chunk)
|
||||||
|
{
|
||||||
|
return util_list_prev(&l.mem_virt.chunk_list, mem_chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find memory chunk for given address
|
||||||
|
*/
|
||||||
|
struct dfi_mem_chunk *dfi_mem_chunk_find(u64 addr)
|
||||||
|
{
|
||||||
|
return mem_chunk_find(&l.mem_virt, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read physical memory at given address
|
||||||
|
*/
|
||||||
|
int dfi_mem_phys_read(u64 addr, void *buf, size_t cnt)
|
||||||
|
{
|
||||||
|
util_log_print(UTIL_LOG_TRACE,
|
||||||
|
"DFI phys mem read addr 0x%016lx size 0x%016lx\n",
|
||||||
|
addr, cnt);
|
||||||
|
if (!mem_range_valid(&l.mem_phys, addr, cnt))
|
||||||
|
return -EINVAL;
|
||||||
|
mem_read(&l.mem_phys, addr, buf, cnt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read virtual memory at given address
|
||||||
|
*/
|
||||||
|
int dfi_mem_virt_read(u64 addr, void *buf, size_t cnt)
|
||||||
|
{
|
||||||
|
util_log_print(UTIL_LOG_TRACE,
|
||||||
|
"DFI virt mem read addr 0x%016lx size 0x%016lx\n",
|
||||||
|
addr, cnt);
|
||||||
|
if (!mem_range_valid(&l.mem_virt, addr, cnt))
|
||||||
|
return -EINVAL;
|
||||||
|
mem_read(&l.mem_virt, addr, buf, cnt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unmap memory region
|
||||||
|
*/
|
||||||
|
void dfi_mem_unmap(u64 start, u64 size)
|
||||||
|
{
|
||||||
|
u64 start_phys, end_phys, addr_phys, addr_virt, size_virt;
|
||||||
|
struct dfi_mem_chunk *mem_chunk, *tmp;
|
||||||
|
u64 end = start + size - 1;
|
||||||
|
|
||||||
|
util_list_iterate_safe(&l.mem_virt.chunk_list, mem_chunk, tmp) {
|
||||||
|
/*
|
||||||
|
* Chunk not hit?
|
||||||
|
*/
|
||||||
|
if (mem_chunk->start >= start + size)
|
||||||
|
continue;
|
||||||
|
if (mem_chunk->end < start)
|
||||||
|
continue;
|
||||||
|
/*
|
||||||
|
* Chunk completely unmapped
|
||||||
|
*
|
||||||
|
* UNMAP: UUUUUUUUU || UUUUUU
|
||||||
|
* CHUNK: CCCC || CCCCCC
|
||||||
|
* TO:
|
||||||
|
*/
|
||||||
|
if (mem_chunk->start >= start && mem_chunk->end <= end)
|
||||||
|
goto free;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get real start and end addresses
|
||||||
|
*/
|
||||||
|
start_phys = mem_chunk_start_phys(mem_chunk);
|
||||||
|
end_phys = start_phys + mem_chunk->size - 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chunk hit at start or in the middle?
|
||||||
|
*
|
||||||
|
* UNMAP: UUUUUU || UU || UUU
|
||||||
|
* CHUNK: CCCCC || CCCCCC || CCCC
|
||||||
|
* TO: NN || NN || NNN
|
||||||
|
*/
|
||||||
|
if (mem_chunk->end > end) {
|
||||||
|
addr_virt = end + 1;
|
||||||
|
size_virt = mem_chunk->end - end;
|
||||||
|
addr_phys = end_phys - size_virt + 1;
|
||||||
|
mem_chunk_map_add(addr_virt, size_virt, addr_phys);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Chunk hit at end or in the middle?
|
||||||
|
*
|
||||||
|
* UNMAP: UUUUUU || UU || UUU
|
||||||
|
* CHUNK: CCCCC || CCCCCC || CCC
|
||||||
|
* TO: NN || NN || NN
|
||||||
|
*/
|
||||||
|
if (mem_chunk->start < start) {
|
||||||
|
addr_virt = mem_chunk->start;
|
||||||
|
size_virt = start - addr_virt;
|
||||||
|
addr_phys = start_phys;
|
||||||
|
mem_chunk_map_add(addr_virt, size_virt, addr_phys);
|
||||||
|
}
|
||||||
|
free:
|
||||||
|
util_list_remove(&l.mem_virt.chunk_list, mem_chunk);
|
||||||
|
l.mem_virt.chunk_cnt--;
|
||||||
|
if (mem_chunk->data && mem_chunk->free_fn)
|
||||||
|
mem_chunk->free_fn(mem_chunk->data);
|
||||||
|
free(mem_chunk);
|
||||||
|
}
|
||||||
|
mem_update(&l.mem_virt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Map memory region
|
||||||
|
*/
|
||||||
|
void dfi_mem_map(u64 start, u64 size, u64 start_phys)
|
||||||
|
{
|
||||||
|
if (mem_range_mapped(start, size)) {
|
||||||
|
dfi_mem_map_print(false);
|
||||||
|
ABORT("Map request for already mapped region (%llx/%llx/%llx)",
|
||||||
|
start, size, start_phys);
|
||||||
|
}
|
||||||
|
mem_chunk_map_add(start, size, start_phys);
|
||||||
|
mem_update(&l.mem_virt);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dfi_mem_chunk_init(void)
|
||||||
|
{
|
||||||
|
mem_init(&l.mem_virt);
|
||||||
|
mem_init(&l.mem_phys);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dfi_mem_chunk_deinit(void)
|
||||||
|
{
|
||||||
|
memset(&l, 0, sizeof(l));
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright IBM Corp. 2001, 2018
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DFI_MEM_CHUNK_H
|
||||||
|
#define DFI_MEM_CHUNK_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "lib/zt_common.h"
|
||||||
|
#include "lib/util_list.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mem chunk functions and definitions
|
||||||
|
*/
|
||||||
|
struct dfi_mem_chunk;
|
||||||
|
|
||||||
|
typedef void (*dfi_mem_chunk_read_fn)(struct dfi_mem_chunk *mem_chunk,
|
||||||
|
u64 off, void *buf, u64 cnt);
|
||||||
|
typedef void (*dfi_mem_chunk_free_fn)(void *data);
|
||||||
|
|
||||||
|
struct dfi_mem_chunk {
|
||||||
|
struct util_list_node list; /* List */
|
||||||
|
u64 start; /* Start address in memory */
|
||||||
|
u64 end; /* End address in memory */
|
||||||
|
u64 size; /* Size of chunk in dump file */
|
||||||
|
dfi_mem_chunk_read_fn read_fn; /* Chunk read callback */
|
||||||
|
dfi_mem_chunk_free_fn free_fn; /* Free data callback */
|
||||||
|
void *data; /* Data for callback */
|
||||||
|
u32 volnr; /* Volume id where chunk resides */
|
||||||
|
};
|
||||||
|
|
||||||
|
void dfi_mem_chunk_read_zero(struct dfi_mem_chunk *UNUSED(mem_chunk),
|
||||||
|
u64 UNUSED(off), void *buf, u64 cnt);
|
||||||
|
void dfi_mem_chunk_add_vol(u64 start, u64 size, void *data,
|
||||||
|
dfi_mem_chunk_read_fn read_fn,
|
||||||
|
dfi_mem_chunk_free_fn free_fn,
|
||||||
|
u32 volnr);
|
||||||
|
void dfi_mem_chunk_add(u64 start, u64 size, void *data,
|
||||||
|
dfi_mem_chunk_read_fn read_fn,
|
||||||
|
dfi_mem_chunk_free_fn free_fn);
|
||||||
|
u64 dfi_mem_range(void);
|
||||||
|
int dfi_mem_range_valid(u64 addr, u64 len);
|
||||||
|
unsigned int dfi_mem_chunk_cnt(void);
|
||||||
|
struct dfi_mem_chunk *dfi_mem_chunk_first(void);
|
||||||
|
struct dfi_mem_chunk *dfi_mem_chunk_last(void);
|
||||||
|
struct dfi_mem_chunk *dfi_mem_chunk_next(struct dfi_mem_chunk *chunk);
|
||||||
|
struct dfi_mem_chunk *dfi_mem_chunk_prev(struct dfi_mem_chunk *chunk);
|
||||||
|
struct dfi_mem_chunk *dfi_mem_chunk_find(u64 addr);
|
||||||
|
|
||||||
|
struct util_list *dfi_mem_chunk_list(void);
|
||||||
|
#define dfi_mem_chunk_iterate(mem_chunk) \
|
||||||
|
util_list_iterate(dfi_mem_chunk_list(), mem_chunk)
|
||||||
|
|
||||||
|
int dfi_mem_virt_read(u64 addr, void *buf, size_t cnt);
|
||||||
|
int dfi_mem_phys_read(u64 addr, void *buf, size_t cnt);
|
||||||
|
|
||||||
|
void dfi_mem_map_print(bool verbose);
|
||||||
|
|
||||||
|
void dfi_mem_unmap(u64 start, u64 size);
|
||||||
|
void dfi_mem_map(u64 start, u64 size, u64 start_phys);
|
||||||
|
|
||||||
|
int dfi_mem_chunk_init(void);
|
||||||
|
void dfi_mem_chunk_deinit(void);
|
||||||
|
|
||||||
|
#endif /* DFI_MEM_CHUNK_H */
|
||||||
+36
-13
@@ -17,8 +17,16 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "lib/util_log.h"
|
||||||
|
|
||||||
#include "zgetdump.h"
|
#include "zgetdump.h"
|
||||||
|
#include "zg.h"
|
||||||
|
#include "dfi.h"
|
||||||
|
#include "dfi_mem_chunk.h"
|
||||||
|
#include "df_elf.h"
|
||||||
|
#include "df_s390.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* File local static data
|
* File local static data
|
||||||
@@ -68,6 +76,9 @@ static int read_s390_hdr(void)
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
if (l.hdr.magic != magic_number)
|
if (l.hdr.magic != magic_number)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
if (l.hdr.cpu_cnt > DF_S390_CPU_MAX)
|
||||||
|
return -ENODEV;
|
||||||
|
util_log_print(UTIL_LOG_INFO, "DFI S390 version %u\n", l.hdr.version);
|
||||||
df_s390_hdr_add(&l.hdr);
|
df_s390_hdr_add(&l.hdr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -95,6 +106,9 @@ static int mem_chunks_add(void)
|
|||||||
{
|
{
|
||||||
u64 rc;
|
u64 rc;
|
||||||
|
|
||||||
|
util_log_print(UTIL_LOG_DEBUG, "DFI S390 mem_size 0x%016lx\n",
|
||||||
|
l.hdr.mem_size);
|
||||||
|
|
||||||
/* Single memory chunk for non-extended dump format */
|
/* Single memory chunk for non-extended dump format */
|
||||||
dfi_mem_chunk_add(0, l.hdr.mem_size, NULL,
|
dfi_mem_chunk_add(0, l.hdr.mem_size, NULL,
|
||||||
dfi_s390_mem_chunk_read,
|
dfi_s390_mem_chunk_read,
|
||||||
@@ -112,39 +126,43 @@ static int mem_chunks_add(void)
|
|||||||
*/
|
*/
|
||||||
static int mem_chunks_add_ext(void)
|
static int mem_chunks_add_ext(void)
|
||||||
{
|
{
|
||||||
struct df_s390_dump_segm_hdr dump_segm;
|
struct df_s390_dump_segm_hdr dump_segm = { 0 };
|
||||||
u64 rc, *off_ptr, old = 0, dump_size = 0;
|
u64 rc, off, old = 0, dump_size = 0;
|
||||||
|
|
||||||
off_ptr = zg_alloc(sizeof(*off_ptr));
|
off = zg_seek(g.fh, DF_S390_HDR_SIZE, ZG_CHECK_NONE);
|
||||||
*off_ptr = zg_seek(g.fh, DF_S390_HDR_SIZE, ZG_CHECK_NONE);
|
if (off != DF_S390_HDR_SIZE)
|
||||||
if (*off_ptr != DF_S390_HDR_SIZE)
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
while (*off_ptr < DF_S390_HDR_SIZE + l.hdr.mem_size - PAGE_SIZE) {
|
while (off < DF_S390_HDR_SIZE + l.hdr.mem_size - PAGE_SIZE) {
|
||||||
rc = zg_read(g.fh, &dump_segm, PAGE_SIZE, ZG_CHECK_ERR);
|
rc = zg_read(g.fh, &dump_segm, PAGE_SIZE, ZG_CHECK_ERR);
|
||||||
if (rc != PAGE_SIZE)
|
if (rc != PAGE_SIZE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
*off_ptr += PAGE_SIZE;
|
util_log_print(UTIL_LOG_DEBUG,
|
||||||
|
"DFI S390 dump segment start 0x%016lx size 0x%016lx stop marker %d\n",
|
||||||
|
dump_segm.start, dump_segm.len, dump_segm.stop_marker);
|
||||||
|
off += PAGE_SIZE;
|
||||||
/* Add zero memory chunk */
|
/* Add zero memory chunk */
|
||||||
dfi_mem_chunk_add(old, dump_segm.start - old, NULL,
|
dfi_mem_chunk_add(old, dump_segm.start - old, NULL,
|
||||||
dfi_mem_chunk_read_zero, NULL);
|
dfi_mem_chunk_read_zero, NULL);
|
||||||
/* Add memory chunk for a dump segment */
|
/* Add memory chunk for a dump segment */
|
||||||
|
u64 *off_ptr = zg_alloc(sizeof(*off_ptr));
|
||||||
|
*off_ptr = off;
|
||||||
dfi_mem_chunk_add(dump_segm.start, dump_segm.len, off_ptr,
|
dfi_mem_chunk_add(dump_segm.start, dump_segm.len, off_ptr,
|
||||||
dfi_s390_ext_mem_chunk_read, zg_free);
|
dfi_s390_ext_mem_chunk_read, zg_free);
|
||||||
|
off_ptr = NULL;
|
||||||
old = dump_segm.start + dump_segm.len;
|
old = dump_segm.start + dump_segm.len;
|
||||||
dump_size += dump_segm.len;
|
dump_size += dump_segm.len;
|
||||||
off_ptr = zg_alloc(sizeof(*off_ptr));
|
off = zg_seek_cur(g.fh, dump_segm.len, ZG_CHECK_NONE);
|
||||||
*off_ptr = zg_seek_cur(g.fh, dump_segm.len, ZG_CHECK_NONE);
|
|
||||||
if (dump_segm.stop_marker)
|
if (dump_segm.stop_marker)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* Check if the last dump segment found */
|
||||||
|
if (!dump_segm.stop_marker)
|
||||||
|
return -EINVAL;
|
||||||
/* Add zero memory chunk at the end */
|
/* Add zero memory chunk at the end */
|
||||||
dfi_mem_chunk_add(old, l.hdr.mem_size - old, NULL,
|
dfi_mem_chunk_add(old, l.hdr.mem_size - old, NULL,
|
||||||
dfi_mem_chunk_read_zero, NULL);
|
dfi_mem_chunk_read_zero, NULL);
|
||||||
/* Set the actual size of the dump file */
|
/* Set the actual size of the dump file */
|
||||||
dfi_attr_file_size_set(dump_size);
|
dfi_attr_file_size_set(dump_size);
|
||||||
/* Check if the last dump segment found */
|
|
||||||
if (!dump_segm.stop_marker)
|
|
||||||
return -EINVAL;
|
|
||||||
/* Read and verify the end marker */
|
/* Read and verify the end marker */
|
||||||
return read_s390_em();
|
return read_s390_em();
|
||||||
}
|
}
|
||||||
@@ -156,6 +174,9 @@ int dfi_s390_init_gen(bool extended)
|
|||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
util_log_print(UTIL_LOG_DEBUG, "DFI S390 %sinitialization\n",
|
||||||
|
extended ? "extended " : "");
|
||||||
|
|
||||||
l.extended = extended;
|
l.extended = extended;
|
||||||
if (read_s390_hdr() != 0)
|
if (read_s390_hdr() != 0)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
@@ -165,7 +186,9 @@ int dfi_s390_init_gen(bool extended)
|
|||||||
rc = mem_chunks_add_ext();
|
rc = mem_chunks_add_ext();
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
df_s390_cpu_info_add(&l.hdr, l.hdr.mem_size);
|
rc = df_s390_cpu_info_add(&l.hdr, l.hdr.mem_size);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
zg_seek(g.fh, sizeof(l.hdr), ZG_CHECK);
|
zg_seek(g.fh, sizeof(l.hdr), ZG_CHECK);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,9 @@
|
|||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "zgetdump.h"
|
#include "dt.h"
|
||||||
|
#include "df_s390.h"
|
||||||
|
#include "dfi.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize s390 input dump format (extended)
|
* Initialize s390 input dump format (extended)
|
||||||
|
|||||||
+10
-1
@@ -20,12 +20,17 @@
|
|||||||
#include <sys/sysmacros.h>
|
#include <sys/sysmacros.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include "lib/util_file.h"
|
#include "lib/util_file.h"
|
||||||
#include "lib/util_path.h"
|
#include "lib/util_path.h"
|
||||||
|
|
||||||
#include "zgetdump.h"
|
#include "zgetdump.h"
|
||||||
|
#include "dt.h"
|
||||||
|
#include "df_s390.h"
|
||||||
|
#include "dfi.h"
|
||||||
#include "dfi_s390mv.h"
|
#include "dfi_s390mv.h"
|
||||||
|
#include "dfi_mem_chunk.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Volume information
|
* Volume information
|
||||||
@@ -574,6 +579,8 @@ static void set_magic_numbers(void)
|
|||||||
*/
|
*/
|
||||||
int dfi_s390mv_init_gen(bool extended)
|
int dfi_s390mv_init_gen(bool extended)
|
||||||
{
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
l.extended = extended;
|
l.extended = extended;
|
||||||
set_magic_numbers();
|
set_magic_numbers();
|
||||||
if (open_dump() != 0)
|
if (open_dump() != 0)
|
||||||
@@ -590,7 +597,9 @@ int dfi_s390mv_init_gen(bool extended)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (l.dump_incomplete)
|
if (l.dump_incomplete)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
df_s390_cpu_info_add(&l.hdr, l.hdr.mem_end);
|
rc = df_s390_cpu_info_add(&l.hdr, l.hdr.mem_end);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
df_s390_em_add(&l.em);
|
df_s390_em_add(&l.em);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "zgetdump.h"
|
#include "zgetdump.h"
|
||||||
|
#include "dt.h"
|
||||||
|
#include "df_s390.h"
|
||||||
|
#include "dfi.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize s390 multi-volume input dump format (extedend)
|
* Initialize s390 multi-volume input dump format (extedend)
|
||||||
|
|||||||
@@ -17,8 +17,12 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include "zgetdump.h"
|
#include "zgetdump.h"
|
||||||
|
#include "df_s390.h"
|
||||||
|
#include "dfi.h"
|
||||||
|
#include "dfi_mem_chunk.h"
|
||||||
|
|
||||||
#define TAPE_BLK_SIZE 32768 /* Defined by zipl tape dumper */
|
#define TAPE_BLK_SIZE 32768 /* Defined by zipl tape dumper */
|
||||||
|
|
||||||
@@ -166,7 +170,9 @@ static int vol_init(void)
|
|||||||
|
|
||||||
/* Init memory read & CPU info */
|
/* Init memory read & CPU info */
|
||||||
mem_read_init();
|
mem_read_init();
|
||||||
df_s390_cpu_info_add(&hdr, hdr.mem_size - 1);
|
rc = df_s390_cpu_info_add(&hdr, hdr.mem_size - 1);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+26
-8
@@ -9,11 +9,16 @@
|
|||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <elf.h>
|
#include <elf.h>
|
||||||
|
|
||||||
#include "lib/zt_common.h"
|
#include "lib/zt_common.h"
|
||||||
|
#include "lib/util_log.h"
|
||||||
|
|
||||||
#include "zgetdump.h"
|
#include "zg.h"
|
||||||
|
#include "dfi_mem_chunk.h"
|
||||||
|
#include "dfi_vmcoreinfo.h"
|
||||||
|
|
||||||
#ifdef __s390x__
|
#ifdef __s390x__
|
||||||
#define LC_VMCORE_INFO 0xe0c
|
#define LC_VMCORE_INFO 0xe0c
|
||||||
@@ -22,7 +27,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LC_OS_INFO 0xe18
|
#define LC_OS_INFO 0xe18
|
||||||
#define OS_INFO_MAGIC 0x4f53494e464f535aULL /* OSINFOSZ */
|
#define OS_INFO_MAGIC 0x4f53494e464f535aULL /* OSINFOSZ */
|
||||||
|
|
||||||
struct os_info {
|
struct os_info {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
@@ -62,10 +67,13 @@ static struct os_info *os_info_get(void)
|
|||||||
static struct os_info os_info;
|
static struct os_info os_info;
|
||||||
unsigned long addr;
|
unsigned long addr;
|
||||||
|
|
||||||
dfi_mem_read(LC_OS_INFO, &addr, sizeof(addr));
|
util_log_print(UTIL_LOG_TRACE, "DFI get osinfo\n");
|
||||||
|
|
||||||
|
if (dfi_mem_virt_read(LC_OS_INFO, &addr, sizeof(addr)))
|
||||||
|
return NULL;
|
||||||
if (addr % 0x1000)
|
if (addr % 0x1000)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (dfi_mem_read_rc(addr, &os_info, sizeof(os_info)))
|
if (dfi_mem_virt_read(addr, &os_info, sizeof(os_info)))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (os_info.magic != OS_INFO_MAGIC)
|
if (os_info.magic != OS_INFO_MAGIC)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -83,32 +91,42 @@ void dfi_vmcoreinfo_init(void)
|
|||||||
Elf64_Nhdr note;
|
Elf64_Nhdr note;
|
||||||
char str[128];
|
char str[128];
|
||||||
|
|
||||||
|
util_log_print(UTIL_LOG_TRACE, "DFI vmcoreinfo initialization\n");
|
||||||
|
|
||||||
l.os_info = os_info_get();
|
l.os_info = os_info_get();
|
||||||
|
|
||||||
if (l.os_info && l.os_info->vmcoreinfo_size) {
|
if (l.os_info && l.os_info->vmcoreinfo_size) {
|
||||||
|
util_log_print(UTIL_LOG_DEBUG, "DFI found valid osinfo\n");
|
||||||
addr = l.os_info->vmcoreinfo_addr;
|
addr = l.os_info->vmcoreinfo_addr;
|
||||||
size = l.os_info->vmcoreinfo_size;
|
size = l.os_info->vmcoreinfo_size;
|
||||||
} else {
|
} else {
|
||||||
dfi_mem_read(LC_VMCORE_INFO, &addr, sizeof(addr));
|
if (dfi_mem_virt_read(LC_VMCORE_INFO, &addr, sizeof(addr)))
|
||||||
|
return;
|
||||||
if (addr == 0)
|
if (addr == 0)
|
||||||
return;
|
return;
|
||||||
if (dfi_mem_read_rc(addr, ¬e, sizeof(note)))
|
if (dfi_mem_virt_read(addr, ¬e, sizeof(note)))
|
||||||
|
return;
|
||||||
|
if (note.n_namesz == 0 || note.n_namesz > sizeof(str))
|
||||||
return;
|
return;
|
||||||
memset(str, 0, sizeof(str));
|
memset(str, 0, sizeof(str));
|
||||||
if (dfi_mem_read_rc(addr + sizeof(note), str, note.n_namesz))
|
if (dfi_mem_virt_read(addr + sizeof(note), str, note.n_namesz))
|
||||||
return;
|
return;
|
||||||
if (memcmp(str, "VMCOREINFO", sizeof("VMCOREINFO")) != 0)
|
if (memcmp(str, "VMCOREINFO", sizeof("VMCOREINFO")) != 0)
|
||||||
return;
|
return;
|
||||||
size = note.n_descsz;
|
size = note.n_descsz;
|
||||||
addr += 24;
|
addr += 24;
|
||||||
}
|
}
|
||||||
|
util_log_print(UTIL_LOG_DEBUG,
|
||||||
|
"DFI vmcoreinfo addr 0x%016lx size 0x%016lx\n",
|
||||||
|
addr, size);
|
||||||
l.vmcoreinfo = zg_alloc(size + 1);
|
l.vmcoreinfo = zg_alloc(size + 1);
|
||||||
if (dfi_mem_read_rc(addr, l.vmcoreinfo, size)) {
|
if (dfi_mem_virt_read(addr, l.vmcoreinfo, size)) {
|
||||||
zg_free(l.vmcoreinfo);
|
zg_free(l.vmcoreinfo);
|
||||||
l.vmcoreinfo = NULL;
|
l.vmcoreinfo = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
l.vmcoreinfo[size] = 0;
|
l.vmcoreinfo[size] = 0;
|
||||||
|
util_log_print(UTIL_LOG_INFO, "DFI found valid vmcoreinfo\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright IBM Corp. 2001, 2018
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DFI_VMCOREINFO_H
|
||||||
|
#define DFI_VMCOREINFO_H
|
||||||
|
|
||||||
|
void dfi_vmcoreinfo_init(void);
|
||||||
|
char *dfi_vmcoreinfo_get(void);
|
||||||
|
int dfi_vmcoreinfo_tag(char *str, int len, const char *sym);
|
||||||
|
int dfi_vmcoreinfo_symbol(unsigned long *val, const char *sym);
|
||||||
|
int dfi_vmcoreinfo_offset(unsigned long *offs, const char *sym);
|
||||||
|
int dfi_vmcoreinfo_size(unsigned long *size, const char *sym);
|
||||||
|
int dfi_vmcoreinfo_length(unsigned long *len, const char *sym);
|
||||||
|
int dfi_vmcoreinfo_val(unsigned long *val, const char *sym);
|
||||||
|
|
||||||
|
#endif /* DFI_VMCOREINFO_H */
|
||||||
+12
-105
@@ -9,11 +9,12 @@
|
|||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <time.h>
|
#include <string.h>
|
||||||
#include "zgetdump.h"
|
#include <errno.h>
|
||||||
|
|
||||||
#define dfo_chunk_iterate(dfo_chunk) \
|
#include "zg.h"
|
||||||
util_list_iterate(&l.dump.chunk_list, dfo_chunk)
|
#include "dfo_mem_chunk.h"
|
||||||
|
#include "dfo.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DFO vector
|
* DFO vector
|
||||||
@@ -24,70 +25,14 @@ static struct dfo *dfo_vec[] = {
|
|||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Dump (output) information
|
|
||||||
*/
|
|
||||||
struct dump {
|
|
||||||
u64 off; /* Current file offset in dump */
|
|
||||||
u64 size; /* Size of dump in bytes */
|
|
||||||
unsigned int chunk_cnt; /* Number of dump chunks */
|
|
||||||
struct util_list chunk_list; /* DFO chunk list */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* File local static data
|
* File local static data
|
||||||
*/
|
*/
|
||||||
static struct {
|
static struct {
|
||||||
struct dump dump;
|
u64 off; /* Current file offset in dump */
|
||||||
struct dfo *dfo;
|
struct dfo *dfo;
|
||||||
} l;
|
} l;
|
||||||
|
|
||||||
/*
|
|
||||||
* Add dump chunk
|
|
||||||
*/
|
|
||||||
void dfo_chunk_add(u64 start, u64 size, void *data, dfo_chunk_read_fn read_fn)
|
|
||||||
{
|
|
||||||
struct dfo_chunk *dfo_chunk;
|
|
||||||
|
|
||||||
dfo_chunk = zg_alloc(sizeof(*dfo_chunk));
|
|
||||||
dfo_chunk->start = start;
|
|
||||||
dfo_chunk->end = start + size - 1;
|
|
||||||
dfo_chunk->data = data;
|
|
||||||
dfo_chunk->read_fn = read_fn;
|
|
||||||
util_list_add_head(&l.dump.chunk_list, dfo_chunk);
|
|
||||||
l.dump.chunk_cnt++;
|
|
||||||
l.dump.size = MAX(l.dump.size, dfo_chunk->end + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dump chunk function: Copy zero pages for chunk
|
|
||||||
*/
|
|
||||||
void dfo_chunk_zero_fn(struct dfo_chunk *dfo_chunk, u64 off, void *buf, u64 cnt)
|
|
||||||
{
|
|
||||||
(void) dfo_chunk;
|
|
||||||
(void) off;
|
|
||||||
|
|
||||||
memset(buf, 0, cnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dump chunk function: Copy given buffer for chunk
|
|
||||||
*/
|
|
||||||
void dfo_chunk_buf_fn(struct dfo_chunk *dfo_chunk, u64 off, void *buf, u64 cnt)
|
|
||||||
{
|
|
||||||
memcpy(buf, dfo_chunk->data + off, cnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dump chunk function: Copy given memory range for chunk
|
|
||||||
*/
|
|
||||||
void dfo_chunk_mem_fn(struct dfo_chunk *dfo_chunk, u64 off, void *buf, u64 cnt)
|
|
||||||
{
|
|
||||||
struct dfi_mem_chunk *mem_chunk = dfo_chunk->data;
|
|
||||||
|
|
||||||
mem_chunk->read_fn(mem_chunk, off, buf, cnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get DFO name
|
* Get DFO name
|
||||||
*/
|
*/
|
||||||
@@ -121,55 +66,17 @@ void dfo_init(void)
|
|||||||
{
|
{
|
||||||
if (!l.dfo)
|
if (!l.dfo)
|
||||||
ABORT("DFO not set");
|
ABORT("DFO not set");
|
||||||
util_list_init(&l.dump.chunk_list, struct dfo_chunk, list);
|
if (dfo_chunk_init())
|
||||||
|
ABORT("DFO memory chunk init failed");
|
||||||
l.dfo->init();
|
l.dfo->init();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Find dump chunk for offset "off"
|
|
||||||
*
|
|
||||||
* This function is a bit hacky. DFO chunks can overlap. If two DFO chunks
|
|
||||||
* overlap, the last registered chunk wins. The dfo_chunk_find() function
|
|
||||||
* reflects that by returning the first memory chunk that is found in
|
|
||||||
* the dfo chunk list.
|
|
||||||
*
|
|
||||||
* In addition to that it calculates the "virtual end" of that chunk. An
|
|
||||||
* overlapping chunk can limit the "virtual end" of an underlying chunk so
|
|
||||||
* that the "virtual end" of that chunk is lower than the "real end".
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
*
|
|
||||||
* chunk 1.: |------|
|
|
||||||
* chunk 2.: |---------------------|
|
|
||||||
* off.....: ^
|
|
||||||
* virt end: ^
|
|
||||||
* real end: ^
|
|
||||||
*
|
|
||||||
* In this case chunk 2 will be returned and "end" is set to the start of
|
|
||||||
* chunk 1.
|
|
||||||
*/
|
|
||||||
static struct dfo_chunk *dfo_chunk_find(u64 off, u64 *end)
|
|
||||||
{
|
|
||||||
struct dfo_chunk *dfo_chunk;
|
|
||||||
|
|
||||||
*end = U64_MAX;
|
|
||||||
dfo_chunk_iterate(dfo_chunk) {
|
|
||||||
if (dfo_chunk->start <= off && dfo_chunk->end >= off) {
|
|
||||||
*end = MIN(*end, dfo_chunk->end);
|
|
||||||
return dfo_chunk;
|
|
||||||
} else if (dfo_chunk->start > off) {
|
|
||||||
*end = MIN(*end, dfo_chunk->start - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Seek to output dump offset "off"
|
* Seek to output dump offset "off"
|
||||||
*/
|
*/
|
||||||
void dfo_seek(u64 off)
|
void dfo_seek(u64 off)
|
||||||
{
|
{
|
||||||
l.dump.off = off;
|
l.off = off;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -179,7 +86,7 @@ u64 dfo_read(void *buf, u64 cnt)
|
|||||||
{
|
{
|
||||||
struct dfo_chunk *dfo_chunk;
|
struct dfo_chunk *dfo_chunk;
|
||||||
u64 copied = 0, end, size;
|
u64 copied = 0, end, size;
|
||||||
u64 off = l.dump.off;
|
u64 off = l.off;
|
||||||
|
|
||||||
while (copied != cnt) {
|
while (copied != cnt) {
|
||||||
dfo_chunk = dfo_chunk_find(off, &end);
|
dfo_chunk = dfo_chunk_find(off, &end);
|
||||||
@@ -192,7 +99,7 @@ u64 dfo_read(void *buf, u64 cnt)
|
|||||||
off += size;
|
off += size;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
l.dump.off = off;
|
l.off = off;
|
||||||
return copied;
|
return copied;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,5 +108,5 @@ out:
|
|||||||
*/
|
*/
|
||||||
u64 dfo_size(void)
|
u64 dfo_size(void)
|
||||||
{
|
{
|
||||||
return l.dump.size;
|
return dfo_chunk_dump_size();
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-31
@@ -12,37 +12,12 @@
|
|||||||
#ifndef DFO_H
|
#ifndef DFO_H
|
||||||
#define DFO_H
|
#define DFO_H
|
||||||
|
|
||||||
#include "lib/util_list.h"
|
u64 dfo_read(void *buf, u64 cnt);
|
||||||
#include "zg.h"
|
void dfo_seek(u64 addr);
|
||||||
|
u64 dfo_size(void);
|
||||||
struct dfo_chunk;
|
const char *dfo_name(void);
|
||||||
|
void dfo_init(void);
|
||||||
typedef void (*dfo_chunk_read_fn)(struct dfo_chunk *chunk, u64 off,
|
int dfo_set(const char *dfo_name);
|
||||||
void *buf, u64 cnt);
|
|
||||||
|
|
||||||
struct dfo_chunk {
|
|
||||||
struct util_list_node list;
|
|
||||||
u64 start;
|
|
||||||
u64 end;
|
|
||||||
dfo_chunk_read_fn read_fn;
|
|
||||||
void *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern void dfo_chunk_zero_fn(struct dfo_chunk *chunk, u64 off, void *buf,
|
|
||||||
u64 cnt);
|
|
||||||
extern void dfo_chunk_buf_fn(struct dfo_chunk *chunk, u64 off, void *buf,
|
|
||||||
u64 cnt);
|
|
||||||
extern void dfo_chunk_mem_fn(struct dfo_chunk *chunk, u64 off, void *buf,
|
|
||||||
u64 cnt);
|
|
||||||
extern void dfo_chunk_add(u64 start, u64 size, void *data,
|
|
||||||
dfo_chunk_read_fn read_fn);
|
|
||||||
|
|
||||||
extern u64 dfo_read(void *buf, u64 cnt);
|
|
||||||
extern void dfo_seek(u64 addr);
|
|
||||||
extern u64 dfo_size(void);
|
|
||||||
extern const char *dfo_name(void);
|
|
||||||
extern void dfo_init(void);
|
|
||||||
extern int dfo_set(const char *dfo_name);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DFO operations
|
* DFO operations
|
||||||
@@ -52,4 +27,10 @@ struct dfo {
|
|||||||
void (*init)(void);
|
void (*init)(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Supported DFO dump formats
|
||||||
|
*/
|
||||||
|
extern struct dfo dfo_s390;
|
||||||
|
extern struct dfo dfo_elf;
|
||||||
|
|
||||||
#endif /* DFO_H */
|
#endif /* DFO_H */
|
||||||
|
|||||||
+31
-212
@@ -16,62 +16,31 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "zgetdump.h"
|
#include "df_elf.h"
|
||||||
|
#include "dfi.h"
|
||||||
|
#include "dfi_mem_chunk.h"
|
||||||
|
#include "dfo_mem_chunk.h"
|
||||||
|
#include "dfi_vmcoreinfo.h"
|
||||||
|
#include "dfo.h"
|
||||||
|
|
||||||
#define HDR_PER_CPU_SIZE 0x4a0
|
#define HDR_PER_CPU_SIZE 0x4a0
|
||||||
#define HDR_PER_MEMC_SIZE 0x100
|
#define HDR_PER_MEMC_SIZE 0x100
|
||||||
#define HDR_BASE_SIZE 0x2000
|
#define HDR_BASE_SIZE 0x2000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* File local static data
|
* Initialize ELF loads program headers
|
||||||
*/
|
*/
|
||||||
static struct {
|
static u64 load_phdrs_init(Elf64_Phdr *phdr, u64 elf_offset)
|
||||||
void *hdr;
|
|
||||||
u32 hdr_size;
|
|
||||||
} l;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize ELF header
|
|
||||||
*/
|
|
||||||
static void *ehdr_init(Elf64_Ehdr *ehdr)
|
|
||||||
{
|
|
||||||
memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
|
|
||||||
ehdr->e_ident[EI_CLASS] = ELFCLASS64;
|
|
||||||
ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
|
|
||||||
ehdr->e_ident[EI_VERSION] = EV_CURRENT;
|
|
||||||
ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;
|
|
||||||
ehdr->e_ident[EI_ABIVERSION] = 0;
|
|
||||||
memset(ehdr->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
|
|
||||||
ehdr->e_type = ET_CORE;
|
|
||||||
ehdr->e_machine = EM_S390;
|
|
||||||
ehdr->e_version = EV_CURRENT;
|
|
||||||
ehdr->e_entry = 0;
|
|
||||||
ehdr->e_phoff = sizeof(Elf64_Ehdr);
|
|
||||||
ehdr->e_shoff = 0;
|
|
||||||
ehdr->e_flags = 0;
|
|
||||||
ehdr->e_ehsize = sizeof(Elf64_Ehdr);
|
|
||||||
ehdr->e_phentsize = sizeof(Elf64_Phdr);
|
|
||||||
ehdr->e_phnum = dfi_mem_chunk_cnt() + 1;
|
|
||||||
ehdr->e_shentsize = 0;
|
|
||||||
ehdr->e_shnum = 0;
|
|
||||||
ehdr->e_shstrndx = 0;
|
|
||||||
return ehdr + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize ELF loads
|
|
||||||
*/
|
|
||||||
static u64 loads_init(Elf64_Phdr *phdr, u64 loads_offset)
|
|
||||||
{
|
{
|
||||||
struct dfi_mem_chunk *mem_chunk;
|
struct dfi_mem_chunk *mem_chunk;
|
||||||
u64 mem_size = 0;
|
u64 mem_size = 0;
|
||||||
|
|
||||||
dfi_mem_chunk_iterate(mem_chunk) {
|
dfi_mem_chunk_iterate(mem_chunk) {
|
||||||
phdr->p_type = PT_LOAD;
|
phdr->p_type = PT_LOAD;
|
||||||
phdr->p_offset = loads_offset;
|
phdr->p_offset = elf_offset;
|
||||||
phdr->p_vaddr = mem_chunk->start;
|
phdr->p_vaddr = mem_chunk->start;
|
||||||
phdr->p_paddr = mem_chunk->start;
|
phdr->p_paddr = phdr->p_vaddr;
|
||||||
phdr->p_memsz = mem_chunk->end - mem_chunk->start + 1;
|
phdr->p_memsz = mem_chunk->size;
|
||||||
if (mem_chunk->read_fn == dfi_mem_chunk_read_zero)
|
if (mem_chunk->read_fn == dfi_mem_chunk_read_zero)
|
||||||
/* Zero memory chunk */
|
/* Zero memory chunk */
|
||||||
phdr->p_filesz = 0;
|
phdr->p_filesz = 0;
|
||||||
@@ -79,7 +48,7 @@ static u64 loads_init(Elf64_Phdr *phdr, u64 loads_offset)
|
|||||||
phdr->p_filesz = phdr->p_memsz;
|
phdr->p_filesz = phdr->p_memsz;
|
||||||
phdr->p_flags = PF_R | PF_W | PF_X;
|
phdr->p_flags = PF_R | PF_W | PF_X;
|
||||||
phdr->p_align = PAGE_SIZE;
|
phdr->p_align = PAGE_SIZE;
|
||||||
loads_offset += phdr->p_filesz;
|
elf_offset += phdr->p_filesz;
|
||||||
mem_size += phdr->p_memsz;
|
mem_size += phdr->p_memsz;
|
||||||
phdr++;
|
phdr++;
|
||||||
}
|
}
|
||||||
@@ -87,160 +56,12 @@ static u64 loads_init(Elf64_Phdr *phdr, u64 loads_offset)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize ELF note
|
* Initialize the program header entries for the notes and the related segment
|
||||||
|
* data.
|
||||||
*/
|
*/
|
||||||
static void *nt_init(void *buf, Elf64_Word type, void *desc, int d_len,
|
static void *notes_init(Elf64_Phdr *phdr, void *segment_start, u64 elf_offset)
|
||||||
const char *name)
|
|
||||||
{
|
{
|
||||||
Elf64_Nhdr *note;
|
void *ptr = segment_start;
|
||||||
u64 len;
|
|
||||||
|
|
||||||
note = (Elf64_Nhdr *)buf;
|
|
||||||
note->n_namesz = strlen(name) + 1;
|
|
||||||
note->n_descsz = d_len;
|
|
||||||
note->n_type = type;
|
|
||||||
len = sizeof(Elf64_Nhdr);
|
|
||||||
|
|
||||||
memcpy(buf + len, name, note->n_namesz);
|
|
||||||
len = ROUNDUP(len + note->n_namesz, 4);
|
|
||||||
|
|
||||||
memcpy(buf + len, desc, note->n_descsz);
|
|
||||||
len = ROUNDUP(len + note->n_descsz, 4);
|
|
||||||
|
|
||||||
return PTR_ADD(buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize prstatus note
|
|
||||||
*/
|
|
||||||
static void *nt_prstatus(void *ptr, struct dfi_cpu *cpu)
|
|
||||||
{
|
|
||||||
struct nt_prstatus_64 nt_prstatus;
|
|
||||||
static int cpu_nr = 1;
|
|
||||||
|
|
||||||
memset(&nt_prstatus, 0, sizeof(nt_prstatus));
|
|
||||||
memcpy(&nt_prstatus.gprs, cpu->gprs, sizeof(cpu->gprs));
|
|
||||||
memcpy(&nt_prstatus.psw, cpu->psw, sizeof(cpu->psw));
|
|
||||||
memcpy(&nt_prstatus.acrs, cpu->acrs, sizeof(cpu->acrs));
|
|
||||||
nt_prstatus.pr_pid = cpu_nr;
|
|
||||||
cpu_nr++;
|
|
||||||
|
|
||||||
return nt_init(ptr, NT_PRSTATUS, &nt_prstatus, sizeof(nt_prstatus),
|
|
||||||
"CORE");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize fpregset (floating point) note
|
|
||||||
*/
|
|
||||||
static void *nt_fpregset(void *ptr, struct dfi_cpu *cpu)
|
|
||||||
{
|
|
||||||
struct nt_fpregset_64 nt_fpregset;
|
|
||||||
|
|
||||||
memset(&nt_fpregset, 0, sizeof(nt_fpregset));
|
|
||||||
memcpy(&nt_fpregset.fpc, &cpu->fpc, sizeof(cpu->fpc));
|
|
||||||
memcpy(&nt_fpregset.fprs, &cpu->fprs, sizeof(cpu->fprs));
|
|
||||||
|
|
||||||
return nt_init(ptr, NT_FPREGSET, &nt_fpregset, sizeof(nt_fpregset),
|
|
||||||
"CORE");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize timer note
|
|
||||||
*/
|
|
||||||
static void *nt_s390_timer(void *ptr, struct dfi_cpu *cpu)
|
|
||||||
{
|
|
||||||
return nt_init(ptr, NT_S390_TIMER, &cpu->timer, sizeof(cpu->timer),
|
|
||||||
"LINUX");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize TOD clock comparator note
|
|
||||||
*/
|
|
||||||
static void *nt_s390_tod_cmp(void *ptr, struct dfi_cpu *cpu)
|
|
||||||
{
|
|
||||||
return nt_init(ptr, NT_S390_TODCMP, &cpu->todcmp,
|
|
||||||
sizeof(cpu->todcmp), "LINUX");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize TOD programmable register note
|
|
||||||
*/
|
|
||||||
static void *nt_s390_tod_preg(void *ptr, struct dfi_cpu *cpu)
|
|
||||||
{
|
|
||||||
return nt_init(ptr, NT_S390_TODPREG, &cpu->todpreg,
|
|
||||||
sizeof(cpu->todpreg), "LINUX");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize control register note
|
|
||||||
*/
|
|
||||||
static void *nt_s390_ctrs(void *ptr, struct dfi_cpu *cpu)
|
|
||||||
{
|
|
||||||
return nt_init(ptr, NT_S390_CTRS, &cpu->ctrs, sizeof(cpu->ctrs),
|
|
||||||
"LINUX");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize prefix register note
|
|
||||||
*/
|
|
||||||
static void *nt_s390_prefix(void *ptr, struct dfi_cpu *cpu)
|
|
||||||
{
|
|
||||||
return nt_init(ptr, NT_S390_PREFIX, &cpu->prefix,
|
|
||||||
sizeof(cpu->prefix), "LINUX");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize vxrs_low register note
|
|
||||||
*/
|
|
||||||
static void *nt_s390_vxrs_low(void *ptr, struct dfi_cpu *cpu)
|
|
||||||
{
|
|
||||||
return nt_init(ptr, NT_S390_VXRS_LOW, &cpu->vxrs_low,
|
|
||||||
sizeof(cpu->vxrs_low), "LINUX");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize vxrs_high register note
|
|
||||||
*/
|
|
||||||
static void *nt_s390_vxrs_high(void *ptr, struct dfi_cpu *cpu)
|
|
||||||
{
|
|
||||||
return nt_init(ptr, NT_S390_VXRS_HIGH, &cpu->vxrs_high,
|
|
||||||
sizeof(cpu->vxrs_high), "LINUX");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize prpsinfo note
|
|
||||||
*/
|
|
||||||
static void *nt_prpsinfo(void *ptr)
|
|
||||||
{
|
|
||||||
struct nt_prpsinfo_64 prpsinfo;
|
|
||||||
|
|
||||||
memset(&prpsinfo, 0, sizeof(prpsinfo));
|
|
||||||
prpsinfo.pr_state = 0;
|
|
||||||
prpsinfo.pr_sname = 'R';
|
|
||||||
prpsinfo.pr_zomb = 0;
|
|
||||||
strcpy(prpsinfo.pr_fname, "vmlinux");
|
|
||||||
|
|
||||||
return nt_init(ptr, NT_PRPSINFO, &prpsinfo, sizeof(prpsinfo), "CORE");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize vmcoreinfo note
|
|
||||||
*/
|
|
||||||
static void *nt_vmcoreinfo(void *ptr)
|
|
||||||
{
|
|
||||||
char *vmcoreinfo = dfi_vmcoreinfo_get();
|
|
||||||
|
|
||||||
if (!vmcoreinfo)
|
|
||||||
return ptr;
|
|
||||||
return nt_init(ptr, 0, vmcoreinfo, strlen(vmcoreinfo), "VMCOREINFO");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize notes
|
|
||||||
*/
|
|
||||||
static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset)
|
|
||||||
{
|
|
||||||
void *ptr_start = ptr;
|
|
||||||
struct dfi_cpu *cpu;
|
struct dfi_cpu *cpu;
|
||||||
|
|
||||||
ptr = nt_prpsinfo(ptr);
|
ptr = nt_prpsinfo(ptr);
|
||||||
@@ -262,24 +83,24 @@ static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
ptr = nt_vmcoreinfo(ptr);
|
ptr = nt_vmcoreinfo(ptr, dfi_vmcoreinfo_get());
|
||||||
memset(phdr, 0, sizeof(*phdr));
|
memset(phdr, 0, sizeof(*phdr));
|
||||||
phdr->p_type = PT_NOTE;
|
phdr->p_type = PT_NOTE;
|
||||||
phdr->p_offset = notes_offset;
|
phdr->p_offset = elf_offset;
|
||||||
phdr->p_filesz = (unsigned long) PTR_SUB(ptr, ptr_start);
|
phdr->p_filesz = PTR_DIFF(ptr, segment_start);
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup dump chunks
|
* Setup dump chunks
|
||||||
*/
|
*/
|
||||||
static void dump_chunks_init(void)
|
static void dump_chunks_init(void *hdr, u64 hdr_size)
|
||||||
{
|
{
|
||||||
struct dfi_mem_chunk *mem_chunk;
|
struct dfi_mem_chunk *mem_chunk;
|
||||||
u64 off = 0;
|
u64 off = 0;
|
||||||
|
|
||||||
dfo_chunk_add(0, l.hdr_size, l.hdr, dfo_chunk_buf_fn);
|
dfo_chunk_add(off, hdr_size, hdr, dfo_chunk_buf_fn);
|
||||||
off = l.hdr_size;
|
off += hdr_size;
|
||||||
dfi_mem_chunk_iterate(mem_chunk) {
|
dfi_mem_chunk_iterate(mem_chunk) {
|
||||||
if (mem_chunk->read_fn == dfi_mem_chunk_read_zero)
|
if (mem_chunk->read_fn == dfi_mem_chunk_read_zero)
|
||||||
/* Zero memory chunk */
|
/* Zero memory chunk */
|
||||||
@@ -308,31 +129,29 @@ static void dfo_elf_init(void)
|
|||||||
{
|
{
|
||||||
Elf64_Phdr *phdr_notes, *phdr_loads;
|
Elf64_Phdr *phdr_notes, *phdr_loads;
|
||||||
u32 alloc_size;
|
u32 alloc_size;
|
||||||
|
void *buf, *ptr;
|
||||||
u64 hdr_off;
|
u64 hdr_off;
|
||||||
void *ptr;
|
|
||||||
|
|
||||||
ensure_s390x();
|
ensure_s390x();
|
||||||
alloc_size = HDR_BASE_SIZE +
|
alloc_size = HDR_BASE_SIZE +
|
||||||
dfi_cpu_cnt() * HDR_PER_CPU_SIZE +
|
dfi_cpu_cnt() * HDR_PER_CPU_SIZE +
|
||||||
dfi_mem_chunk_cnt() * HDR_PER_MEMC_SIZE;
|
dfi_mem_chunk_cnt() * HDR_PER_MEMC_SIZE;
|
||||||
l.hdr = zg_alloc(alloc_size);
|
buf = zg_alloc(alloc_size);
|
||||||
/* Init elf header */
|
/* Init elf header */
|
||||||
ptr = ehdr_init(l.hdr);
|
ptr = ehdr_init(buf, dfi_mem_chunk_cnt() + 1);
|
||||||
/* Init program headers */
|
/* Init program headers */
|
||||||
phdr_notes = ptr;
|
phdr_notes = ptr;
|
||||||
ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr));
|
ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr));
|
||||||
phdr_loads = ptr;
|
phdr_loads = ptr;
|
||||||
ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr) * dfi_mem_chunk_cnt());
|
ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr) * dfi_mem_chunk_cnt());
|
||||||
/* Init notes */
|
/* Init notes */
|
||||||
hdr_off = PTR_DIFF(ptr, l.hdr);
|
hdr_off = PTR_DIFF(ptr, buf);
|
||||||
ptr = notes_init(phdr_notes, ptr, hdr_off);
|
ptr = notes_init(phdr_notes, ptr, hdr_off);
|
||||||
/* Init loads */
|
hdr_off = PTR_DIFF(ptr, buf);
|
||||||
hdr_off = PTR_DIFF(ptr, l.hdr);
|
load_phdrs_init(phdr_loads, hdr_off);
|
||||||
loads_init(phdr_loads, hdr_off);
|
if (hdr_off > alloc_size)
|
||||||
l.hdr_size = hdr_off;
|
ABORT("hdr_size=%llu alloc_size=%u", hdr_off, alloc_size);
|
||||||
if (l.hdr_size > alloc_size)
|
dump_chunks_init(buf, hdr_off);
|
||||||
ABORT("hdr_size=%u alloc_size=%u", l.hdr_size, alloc_size);
|
|
||||||
dump_chunks_init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Copyright IBM Corp. 2001, 2017, 2021
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "zg.h"
|
||||||
|
#include "dfi_mem_chunk.h"
|
||||||
|
#include "dfo_mem_chunk.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* File local static data
|
||||||
|
*/
|
||||||
|
static struct {
|
||||||
|
u64 size; /* Size of dump in bytes */
|
||||||
|
unsigned int chunk_cnt; /* Number of dump chunks */
|
||||||
|
struct util_list chunk_list; /* DFO chunk list */
|
||||||
|
} l;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add dump chunk
|
||||||
|
*/
|
||||||
|
void dfo_chunk_add(u64 start, u64 size, void *data, dfo_chunk_read_fn read_fn)
|
||||||
|
{
|
||||||
|
struct dfo_chunk *dfo_chunk;
|
||||||
|
|
||||||
|
dfo_chunk = zg_alloc(sizeof(*dfo_chunk));
|
||||||
|
dfo_chunk->start = start;
|
||||||
|
dfo_chunk->end = start + size - 1;
|
||||||
|
dfo_chunk->data = data;
|
||||||
|
dfo_chunk->read_fn = read_fn;
|
||||||
|
util_list_add_head(&l.chunk_list, dfo_chunk);
|
||||||
|
l.chunk_cnt++;
|
||||||
|
l.size = MAX(l.size, dfo_chunk->end + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dump chunk function: Copy zero pages for chunk
|
||||||
|
*/
|
||||||
|
void dfo_chunk_zero_fn(struct dfo_chunk *dfo_chunk, u64 off, void *buf, u64 cnt)
|
||||||
|
{
|
||||||
|
(void) dfo_chunk;
|
||||||
|
(void) off;
|
||||||
|
|
||||||
|
memset(buf, 0, cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dump chunk function: Copy given buffer for chunk
|
||||||
|
*/
|
||||||
|
void dfo_chunk_buf_fn(struct dfo_chunk *dfo_chunk, u64 off, void *buf, u64 cnt)
|
||||||
|
{
|
||||||
|
memcpy(buf, dfo_chunk->data + off, cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dump chunk function: Copy given memory range for chunk
|
||||||
|
*/
|
||||||
|
void dfo_chunk_mem_fn(struct dfo_chunk *dfo_chunk, u64 off, void *buf, u64 cnt)
|
||||||
|
{
|
||||||
|
struct dfi_mem_chunk *mem_chunk = dfo_chunk->data;
|
||||||
|
|
||||||
|
mem_chunk->read_fn(mem_chunk, off, buf, cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find dump chunk for offset "off"
|
||||||
|
*
|
||||||
|
* This function is a bit hacky. DFO chunks can overlap. If two DFO chunks
|
||||||
|
* overlap, the last registered chunk wins. The dfo_chunk_find() function
|
||||||
|
* reflects that by returning the first memory chunk that is found in
|
||||||
|
* the dfo chunk list.
|
||||||
|
*
|
||||||
|
* In addition to that it calculates the "virtual end" of that chunk. An
|
||||||
|
* overlapping chunk can limit the "virtual end" of an underlying chunk so
|
||||||
|
* that the "virtual end" of that chunk is lower than the "real end".
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* chunk 1.: |------|
|
||||||
|
* chunk 2.: |---------------------|
|
||||||
|
* off.....: ^
|
||||||
|
* virt end: ^
|
||||||
|
* real end: ^
|
||||||
|
*
|
||||||
|
* In this case chunk 2 will be returned and "end" is set to the start of
|
||||||
|
* chunk 1.
|
||||||
|
*/
|
||||||
|
struct dfo_chunk *dfo_chunk_find(u64 off, u64 *end)
|
||||||
|
{
|
||||||
|
struct dfo_chunk *dfo_chunk;
|
||||||
|
|
||||||
|
*end = U64_MAX;
|
||||||
|
dfo_chunk_iterate(dfo_chunk) {
|
||||||
|
if (dfo_chunk->start <= off && dfo_chunk->end >= off) {
|
||||||
|
*end = MIN(*end, dfo_chunk->end);
|
||||||
|
return dfo_chunk;
|
||||||
|
} else if (dfo_chunk->start > off) {
|
||||||
|
*end = MIN(*end, dfo_chunk->start - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct util_list *dfo_chunk_list(void)
|
||||||
|
{
|
||||||
|
return &l.chunk_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 dfo_chunk_dump_size(void)
|
||||||
|
{
|
||||||
|
return l.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dfo_chunk_init(void)
|
||||||
|
{
|
||||||
|
util_list_init(&l.chunk_list, struct dfo_chunk, list);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dfo_chunk_deinit(void)
|
||||||
|
{
|
||||||
|
memset(&l, 0, sizeof(l));
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright IBM Corp. 2001, 2017, 2021
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DFO_MEM_CHUNK_H
|
||||||
|
#define DFO_MEM_CHUNK_H
|
||||||
|
|
||||||
|
#include "lib/zt_common.h"
|
||||||
|
#include "lib/util_list.h"
|
||||||
|
|
||||||
|
struct dfo_chunk;
|
||||||
|
|
||||||
|
typedef void (*dfo_chunk_read_fn)(struct dfo_chunk *chunk, u64 off,
|
||||||
|
void *buf, u64 cnt);
|
||||||
|
|
||||||
|
struct dfo_chunk {
|
||||||
|
struct util_list_node list;
|
||||||
|
u64 start;
|
||||||
|
u64 end;
|
||||||
|
dfo_chunk_read_fn read_fn;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
void dfo_chunk_zero_fn(struct dfo_chunk *chunk, u64 off, void *buf, u64 cnt);
|
||||||
|
void dfo_chunk_buf_fn(struct dfo_chunk *chunk, u64 off, void *buf, u64 cnt);
|
||||||
|
void dfo_chunk_mem_fn(struct dfo_chunk *chunk, u64 off, void *buf, u64 cnt);
|
||||||
|
void dfo_chunk_add(u64 start, u64 size, void *data, dfo_chunk_read_fn read_fn);
|
||||||
|
struct dfo_chunk *dfo_chunk_find(u64 off, u64 *end);
|
||||||
|
|
||||||
|
struct util_list *dfo_chunk_list(void);
|
||||||
|
#define dfo_chunk_iterate(dfo_chunk) \
|
||||||
|
util_list_iterate(dfo_chunk_list(), dfo_chunk)
|
||||||
|
|
||||||
|
u64 dfo_chunk_dump_size(void);
|
||||||
|
|
||||||
|
int dfo_chunk_init(void);
|
||||||
|
void dfo_chunk_deinit(void);
|
||||||
|
|
||||||
|
#endif /* DFO_MEM_CHUNK_H */
|
||||||
+10
-5
@@ -17,7 +17,10 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "zgetdump.h"
|
#include "df_s390.h"
|
||||||
|
#include "dfi_mem_chunk.h"
|
||||||
|
#include "dfo_mem_chunk.h"
|
||||||
|
#include "dfo.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* File local static data
|
* File local static data
|
||||||
@@ -98,7 +101,8 @@ static void dfo_s390_dump_chunk_lc_fn(struct dfo_chunk *dump_chunk,
|
|||||||
struct dfi_cpu *cpu = dump_chunk->data;
|
struct dfi_cpu *cpu = dump_chunk->data;
|
||||||
char lc[0x2000];
|
char lc[0x2000];
|
||||||
|
|
||||||
dfi_mem_read(cpu->prefix + off, &lc[off], cnt);
|
if (dfi_mem_virt_read(cpu->prefix + off, &lc[off], cnt))
|
||||||
|
return;
|
||||||
if (dfi_arch() == DFI_ARCH_64)
|
if (dfi_arch() == DFI_ARCH_64)
|
||||||
cpu2lc_64(lc, cpu);
|
cpu2lc_64(lc, cpu);
|
||||||
else
|
else
|
||||||
@@ -142,7 +146,8 @@ static void add_cpu_to_dfo(struct dfi_cpu *cpu)
|
|||||||
return;
|
return;
|
||||||
if (!dfi_cpu_content_fac_check(DFI_CPU_CONTENT_FAC_VX))
|
if (!dfi_cpu_content_fac_check(DFI_CPU_CONTENT_FAC_VX))
|
||||||
return;
|
return;
|
||||||
dfi_mem_read(cpu->prefix, &lc, sizeof(lc));
|
if (dfi_mem_virt_read(cpu->prefix, &lc, sizeof(lc)))
|
||||||
|
return;
|
||||||
if (!dfi_cpu_lc_has_vx_sa(&lc))
|
if (!dfi_cpu_lc_has_vx_sa(&lc))
|
||||||
return;
|
return;
|
||||||
vx_regs = zg_alloc(DFI_VX_SA_SIZE);
|
vx_regs = zg_alloc(DFI_VX_SA_SIZE);
|
||||||
@@ -181,8 +186,8 @@ static void dump_chunks_init(void)
|
|||||||
dfi_cpu_iterate(cpu)
|
dfi_cpu_iterate(cpu)
|
||||||
add_cpu_to_dfo(cpu);
|
add_cpu_to_dfo(cpu);
|
||||||
dfo_chunk_add(dfi_mem_range() + DF_S390_HDR_SIZE,
|
dfo_chunk_add(dfi_mem_range() + DF_S390_HDR_SIZE,
|
||||||
DF_S390_EM_SIZE,
|
DF_S390_EM_SIZE,
|
||||||
&l.em, dfo_chunk_buf_fn);
|
&l.em, dfo_chunk_buf_fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "zgetdump.h"
|
#include "zgetdump.h"
|
||||||
|
#include "zg.h"
|
||||||
|
#include "dt.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Supported dump tools
|
* Supported dump tools
|
||||||
|
|||||||
+18
-8
@@ -12,9 +12,10 @@
|
|||||||
#ifndef DT_H
|
#ifndef DT_H
|
||||||
#define DT_H
|
#define DT_H
|
||||||
|
|
||||||
#include "dfi.h"
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "dfi.h"
|
||||||
|
|
||||||
#define DUMP_EXTENDED true
|
#define DUMP_EXTENDED true
|
||||||
#define DUMP_NON_EXTENDED false
|
#define DUMP_NON_EXTENDED false
|
||||||
|
|
||||||
@@ -24,12 +25,21 @@ struct dt {
|
|||||||
void (*info)(void);
|
void (*info)(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void dt_init(void);
|
void dt_init(void);
|
||||||
extern void dt_info_print(void);
|
void dt_info_print(void);
|
||||||
extern void dt_arch_set(enum dfi_arch arch);
|
void dt_arch_set(enum dfi_arch arch);
|
||||||
extern void dt_version_set(int version);
|
void dt_version_set(int version);
|
||||||
extern void dt_attr_mem_limit_set(u64 mem_limit);
|
void dt_attr_mem_limit_set(u64 mem_limit);
|
||||||
extern void dt_attr_force_set(int value);
|
void dt_attr_force_set(int value);
|
||||||
extern void dt_attr_dasd_type_set(const char *dasd_type);
|
void dt_attr_dasd_type_set(const char *dasd_type);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Supported s390 dumpers
|
||||||
|
*/
|
||||||
|
extern struct dt dt_s390mv;
|
||||||
|
extern struct dt dt_s390mv_ext;
|
||||||
|
extern struct dt dt_s390sv;
|
||||||
|
extern struct dt dt_s390sv_ext;
|
||||||
|
extern struct dt dt_scsi;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+2
-1
@@ -9,7 +9,8 @@
|
|||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "zgetdump.h"
|
#include "dt.h"
|
||||||
|
#include "df_s390.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize s390 multi-volume dump tool (for -d option)
|
* Initialize s390 multi-volume dump tool (for -d option)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user