mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Compare commits
72 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c2db7ce05f | |||
| 0031c762cf | |||
| 7031429d1e | |||
| 73d8597db1 | |||
| 77d0d1d1a1 | |||
| 77a7e11a51 | |||
| 279070fa43 | |||
| 3989e1b741 | |||
| c230b5385a | |||
| 68ecf79b01 | |||
| f2960eb0df | |||
| 4d004cf8b1 | |||
| d8f504f271 | |||
| 7fb3ee4478 | |||
| a95bad6c87 | |||
| 147ff1bf49 | |||
| c91d172c99 | |||
| 0e4992da3a | |||
| 41da0f0809 | |||
| f43789e16a | |||
| 136e5eed8c | |||
| e09753f2a3 | |||
| fe2d240656 | |||
| 6fc450f696 | |||
| 6a55d0c2e5 | |||
| 0e69dc1262 | |||
| 3296d85e35 | |||
| 0eeab96f0d | |||
| 283a61dc2f | |||
| 670bf3e870 | |||
| 9cfaac58ea | |||
| d6b702d579 | |||
| d9a9bd8dcf | |||
| cad4e9e15b | |||
| c0f02d2f68 | |||
| 5218c243f4 | |||
| c364692e7a | |||
| 41eb7d076f | |||
| 1062a7cde6 | |||
| 54e5e99657 | |||
| 4c922b105b | |||
| 4b19b9d950 | |||
| cee4bb4995 | |||
| c98d8e7629 | |||
| 96084339f5 | |||
| f8d5b4b341 | |||
| 5806c4e1f4 | |||
| 9d199e06cb | |||
| f7425a08d1 | |||
| f6a97902c3 | |||
| 962af1a90e | |||
| 46dadc8cc4 | |||
| 9c8d117cc2 | |||
| d7b3196286 | |||
| b6c30404bc | |||
| 6d15850480 | |||
| 858da9af57 | |||
| a7373674bf | |||
| 613353cd33 | |||
| f6e932e0fd | |||
| 7e31c425c9 | |||
| 6c4171b775 | |||
| 0b0960254e | |||
| 4d2c9267c2 | |||
| 7ea0dfdc17 | |||
| 2d3aac1241 | |||
| c7fd515790 | |||
| 7a4ec55d77 | |||
| 63ff07ba38 | |||
| 26d7eed0aa | |||
| e0034eddbf | |||
| 0e3034c0f6 |
@@ -124,9 +124,11 @@ zipl/boot/*.exec
|
|||||||
zipl/boot/.loaders
|
zipl/boot/.loaders
|
||||||
zipl/boot/data.h
|
zipl/boot/data.h
|
||||||
zipl/src/chreipl_helper.device-mapper
|
zipl/src/chreipl_helper.device-mapper
|
||||||
|
zipl/src/chreipl_helper.md
|
||||||
zipl/src/zipl
|
zipl/src/zipl
|
||||||
zipl/src/zipl-editenv
|
zipl/src/zipl-editenv
|
||||||
zipl/src/zipl_helper.device-mapper
|
zipl/src/zipl_helper.device-mapper
|
||||||
|
zipl/src/zipl_helper.md
|
||||||
zkey/check-dep-zkey
|
zkey/check-dep-zkey
|
||||||
zkey/check-dep-zkey-cryptsetup
|
zkey/check-dep-zkey-cryptsetup
|
||||||
zkey/detect-libcryptsetup.dep
|
zkey/detect-libcryptsetup.dep
|
||||||
|
|||||||
+4
-3
@@ -5,8 +5,9 @@ newline_style = "Unix"
|
|||||||
# when they become stable.
|
# when they become stable.
|
||||||
#
|
#
|
||||||
# They are kept here since they are useful to run from time to time.
|
# They are kept here since they are useful to run from time to time.
|
||||||
#format_code_in_doc_comments = true
|
|
||||||
#reorder_impl_items = true
|
|
||||||
#comment_width = 100
|
#comment_width = 100
|
||||||
#wrap_comments = true
|
#format_code_in_doc_comments = true
|
||||||
|
#group_imports = "StdExternalCrate"
|
||||||
#normalize_comments = true
|
#normalize_comments = true
|
||||||
|
#reorder_impl_items = true
|
||||||
|
#wrap_comments = true
|
||||||
|
|||||||
@@ -1,6 +1,46 @@
|
|||||||
Release history for s390-tools (MIT version)
|
Release history for s390-tools (MIT version)
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
|
|
||||||
|
* __v2.35.0 (2024-10-01)__
|
||||||
|
|
||||||
|
For Linux kernel version: 6.11
|
||||||
|
|
||||||
|
Add new tools / libraries:
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- cpacfstats: Add support for FULL XTS (MSA 10) and HMAC (MSA 11) PAI counter
|
||||||
|
- cpuplugd: Make cpuplugd compatible with hiperdispatch
|
||||||
|
- dbginfo.sh: Add network sockstat info
|
||||||
|
- pvapconfig: s390x exclusive build
|
||||||
|
- zdev: Add option to select IPL device
|
||||||
|
- zdump/dfo_s390: Support s390 DFO for vr-kernel dumps
|
||||||
|
- zipl: Add support of mirror devices
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- (genprotimg|zipl)/boot: discard .note.package ELF section to save memory
|
||||||
|
- netboot/mk-s390image: Fix size when argument is a symlink
|
||||||
|
- ziorep_config: Fix warning message when multipath device is not there.
|
||||||
|
- zipl: Fix problems when target parameters are specified by user
|
||||||
|
- zipl: Fix segfault when creating device-based dumps with '--dry-run'
|
||||||
|
|
||||||
|
* __v2.34.0 (2024-08-01)__
|
||||||
|
|
||||||
|
For Linux kernel version: 6.10
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- ap_tools/ap-check: Add support for vfio-ap dynamic configuration
|
||||||
|
- dbginfo.sh: Update/Add additional DASD data collection
|
||||||
|
- dumpconf: Add new parameter 'SCP_DATA' for SCSI/NVMe/ECKD dump devices
|
||||||
|
- libutil: Make formatted meta-data configurable
|
||||||
|
- s390-tools: Replace 'which' with built-in 'command -v'
|
||||||
|
- zdump/dfi_elf: Support core dumps of vr-kernels
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- chzdev: Fix warning about failed ATTR writes by udev
|
||||||
|
- rust/pv: Try again if first CRL-URI is invalid
|
||||||
|
- rust/pvattest: Add short option for --arpk
|
||||||
|
- zdump: Fix 'zgetdump -i' ioctl error on s390 formatted dump file
|
||||||
|
|
||||||
* __v2.33.1 (2024-05-28)__
|
* __v2.33.1 (2024-05-28)__
|
||||||
|
|
||||||
For Linux kernel version: 6.9
|
For Linux kernel version: 6.9
|
||||||
|
|||||||
+280
-21
@@ -15,6 +15,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#include <json-c/json.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -27,21 +28,33 @@
|
|||||||
|
|
||||||
#include "ap-check.h"
|
#include "ap-check.h"
|
||||||
|
|
||||||
|
/* The supported mdevctl callout version */
|
||||||
|
#define MDEVCTL_CAP_VERSION 2
|
||||||
|
|
||||||
static const struct mdevctl_action mdevctl_action_table[NUM_MDEVCTL_ACTIONS] = {
|
static const struct mdevctl_action mdevctl_action_table[NUM_MDEVCTL_ACTIONS] = {
|
||||||
{MDEVCTL_ACTION_DEFINE, "define"},
|
{MDEVCTL_ACTION_DEFINE, "define"},
|
||||||
{MDEVCTL_ACTION_LIST, "list"},
|
|
||||||
{MDEVCTL_ACTION_MODIFY, "modify"},
|
{MDEVCTL_ACTION_MODIFY, "modify"},
|
||||||
{MDEVCTL_ACTION_START, "start"},
|
{MDEVCTL_ACTION_START, "start"},
|
||||||
{MDEVCTL_ACTION_STOP, "stop"},
|
{MDEVCTL_ACTION_STOP, "stop"},
|
||||||
{MDEVCTL_ACTION_TYPES, "types"},
|
|
||||||
{MDEVCTL_ACTION_UNDEFINE, "undefine"},
|
{MDEVCTL_ACTION_UNDEFINE, "undefine"},
|
||||||
{MDEVCTL_ACTION_ATTRIBUTES, "attributes"}
|
{MDEVCTL_ACTION_ATTRIBUTES, "attributes"},
|
||||||
|
{MDEVCTL_ACTION_CAPABILITIES, "capabilities"}
|
||||||
|
/*
|
||||||
|
* Note: the following actions are known to exist but currently ignored:
|
||||||
|
* {MDEVCTL_ACTION_LIST, "list"},
|
||||||
|
* {MDEVCTL_ACTION_TYPES, "types"}
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct mdevctl_event mdevctl_event_table[NUM_MDEVCTL_EVENTS] = {
|
static const struct mdevctl_event mdevctl_event_table[NUM_MDEVCTL_EVENTS] = {
|
||||||
{MDEVCTL_EVENT_PRE, "pre"},
|
{MDEVCTL_EVENT_PRE, "pre"},
|
||||||
{MDEVCTL_EVENT_POST, "post"},
|
{MDEVCTL_EVENT_POST, "post"},
|
||||||
{MDEVCTL_EVENT_GET, "get"}
|
{MDEVCTL_EVENT_GET, "get"},
|
||||||
|
{MDEVCTL_EVENT_LIVE, "live"}
|
||||||
|
/*
|
||||||
|
* Note: the following events are known to exist but currently ignored:
|
||||||
|
* {MDEVCTL_EVENT_NOTIFY, "notify"},
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -596,6 +609,94 @@ out:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ap_check_active(struct ap_check_anchor *anc)
|
||||||
|
{
|
||||||
|
int rc, rc2;
|
||||||
|
|
||||||
|
/* Ensure device with control domains also has usage domains */
|
||||||
|
if (util_list_is_empty(anc->dev->domains) &&
|
||||||
|
!util_list_is_empty(anc->dev->controls)) {
|
||||||
|
fprintf(stderr, "At least one usage domain must be specified\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check against all other active vfio-ap devices */
|
||||||
|
rc = check_other_mdevs_sysfs(anc);
|
||||||
|
/* Check against the system sysfs values for apmask/aqmask */
|
||||||
|
rc2 = check_sysfs_mask_conflicts(anc);
|
||||||
|
/* If either hit an error, reflect this */
|
||||||
|
rc = rc != 0 ? rc : rc2;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ap_do_dynamic_config(struct ap_check_anchor *anc)
|
||||||
|
{
|
||||||
|
char *adapters, *domains, *controls, *path, *attr;
|
||||||
|
int asize, dsize, csize, size;
|
||||||
|
int rc = 0;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
adapters = vfio_ap_device_get_adapter_mask(anc->dev, &asize);
|
||||||
|
domains = vfio_ap_device_get_domain_mask(anc->dev, &dsize);
|
||||||
|
controls = vfio_ap_device_get_control_mask(anc->dev, &csize);
|
||||||
|
|
||||||
|
if (!adapters || !domains || !controls) {
|
||||||
|
fprintf(stderr, "Failed to read device config\n");
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The 'ap_config' command takes a comma-delimited list of the 3 masks
|
||||||
|
* combined. Each mask size includes a terminating character, two of
|
||||||
|
* which will be replaced by commas and the final replaced by a
|
||||||
|
* newline, which ap_config seems to require at the end of the input.
|
||||||
|
* Add one to ensure room for a null termination.
|
||||||
|
*/
|
||||||
|
size = asize + dsize + csize + 1;
|
||||||
|
attr = util_zalloc(size);
|
||||||
|
|
||||||
|
/* Use the 3 masks to generate a 'ap_config' command */
|
||||||
|
rc = snprintf(attr, size, "%s,%s,%s\n", adapters, domains, controls);
|
||||||
|
|
||||||
|
if (rc < size - 1) {
|
||||||
|
fprintf(stderr, "Error creating ap_config command\n");
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Apply the new configuration to the active device */
|
||||||
|
path = path_get_vfio_ap_attr(anc->uuid, "ap_config");
|
||||||
|
f = fopen(path, "w");
|
||||||
|
if (!f) {
|
||||||
|
fprintf(stderr, "Error opening ap_config\n");
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
rc = fputs(attr, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
if (rc == EOF)
|
||||||
|
fprintf(stderr, "Error writing to ap_config\n");
|
||||||
|
else
|
||||||
|
rc = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (!adapters)
|
||||||
|
free(adapters);
|
||||||
|
if (!domains)
|
||||||
|
free(domains);
|
||||||
|
if (!controls)
|
||||||
|
free(controls);
|
||||||
|
if (!path)
|
||||||
|
free(path);
|
||||||
|
if (!attr)
|
||||||
|
free(attr);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Determine if defining the specified device is a valid operation.
|
* Determine if defining the specified device is a valid operation.
|
||||||
* mdevctl can reach us for a DEFINE under the following circumstances:
|
* mdevctl can reach us for a DEFINE under the following circumstances:
|
||||||
@@ -647,6 +748,50 @@ static int ap_check_handle_modify(struct ap_check_anchor *anc)
|
|||||||
return ap_check_changes(anc);
|
return ap_check_changes(anc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine if modifying the active device is a valid operation.
|
||||||
|
* This is similar to STARTing a device, in that the requested modifications
|
||||||
|
* cannot conflict with the active configuration. LIVE MODIFY can only be
|
||||||
|
* handled if the ap_config attribute is available in the vfio-ap driver.
|
||||||
|
*/
|
||||||
|
static int ap_check_handle_live_modify(struct ap_check_anchor *anc)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = ap_get_lock_callout();
|
||||||
|
if (rc) {
|
||||||
|
fprintf(stderr, "Failed to acquire configuration lock %d\n",
|
||||||
|
rc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
anc->cleanup_lock = true;
|
||||||
|
|
||||||
|
if (vfio_ap_read_device_config(NULL, anc->dev) != 0) {
|
||||||
|
fprintf(stderr, "Failed to read device config\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(anc->dev->type, anc->type) != 0) {
|
||||||
|
fprintf(stderr, "Invalid mdev_type: %s\n", anc->dev->type);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vfio_ap_need_dynamic_config(anc->dev)) {
|
||||||
|
fprintf(stderr, "vfio-ap module does not support ap_config for live modification");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the new configuration would cause conflicts */
|
||||||
|
rc = ap_check_active(anc);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Attempt to perform the dynamic configuration */
|
||||||
|
rc = ap_do_dynamic_config(anc);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Determine if starting the specified device is a valid operation.
|
* Determine if starting the specified device is a valid operation.
|
||||||
* mdevctl can reach us for a START under the following circumstances:
|
* mdevctl can reach us for a START under the following circumstances:
|
||||||
@@ -665,7 +810,7 @@ static int ap_check_handle_modify(struct ap_check_anchor *anc)
|
|||||||
*/
|
*/
|
||||||
static int ap_check_handle_start(struct ap_check_anchor *anc)
|
static int ap_check_handle_start(struct ap_check_anchor *anc)
|
||||||
{
|
{
|
||||||
int rc = 0, rc2;
|
int rc = 0;
|
||||||
|
|
||||||
/* Can only start a device if vfio_ap is built-in or loaded */
|
/* Can only start a device if vfio_ap is built-in or loaded */
|
||||||
if (!util_path_is_dir(VFIO_AP_PATH)) {
|
if (!util_path_is_dir(VFIO_AP_PATH)) {
|
||||||
@@ -694,20 +839,7 @@ static int ap_check_handle_start(struct ap_check_anchor *anc)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure device with control domains also has usage domains */
|
rc = ap_check_active(anc);
|
||||||
if (util_list_is_empty(anc->dev->domains) &&
|
|
||||||
!util_list_is_empty(anc->dev->controls)) {
|
|
||||||
fprintf(stderr, "At least one usage domain must be specified\n");
|
|
||||||
rc = -1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check against all other active vfio-ap devices */
|
|
||||||
rc = check_other_mdevs_sysfs(anc);
|
|
||||||
/* Check against the system sysfs values for apmask/aqmask */
|
|
||||||
rc2 = check_sysfs_mask_conflicts(anc);
|
|
||||||
/* If either hit an error, reflect this */
|
|
||||||
rc = rc != 0 ? rc : rc2;
|
|
||||||
|
|
||||||
/* If successful, lock must remain held until post callout */
|
/* If successful, lock must remain held until post callout */
|
||||||
if (rc == 0)
|
if (rc == 0)
|
||||||
@@ -886,6 +1018,122 @@ static int ap_check_handle_get_attributes(struct ap_check_anchor *anc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the target 'attr' is in the 's' array, add it to the 't' array.
|
||||||
|
*/
|
||||||
|
static void json_add_attr(json_object *t, json_object *s, const char *attr)
|
||||||
|
{
|
||||||
|
size_t vlen, alen = strlen(attr);
|
||||||
|
const char *val;
|
||||||
|
json_object *o;
|
||||||
|
int i, num;
|
||||||
|
|
||||||
|
num = json_object_array_length(s);
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
o = json_object_array_get_idx(s, i);
|
||||||
|
val = json_object_get_string(o);
|
||||||
|
vlen = strlen(val);
|
||||||
|
if (alen == vlen && strncasecmp(attr, val, alen) == 0) {
|
||||||
|
json_object_array_add(t, json_object_new_string(val));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate a JSON-formatted list of capability information that this script
|
||||||
|
* supports and return it to the caller via stdout. An example of what the
|
||||||
|
* output should look like (without the newlines):
|
||||||
|
* {
|
||||||
|
* "supports": {
|
||||||
|
* "version": 2,
|
||||||
|
* "actions": ["define",
|
||||||
|
* "modify",
|
||||||
|
* "start",
|
||||||
|
* "stop",
|
||||||
|
* "undefine",
|
||||||
|
* "attributes",
|
||||||
|
* "capabilities"],
|
||||||
|
* "events": ["pre",
|
||||||
|
* "post",
|
||||||
|
* "get",
|
||||||
|
* "live"]
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
static int ap_check_handle_get_capabilities(void)
|
||||||
|
{
|
||||||
|
json_object *root, *csup, *cver, *cact, *cev, *cap, *caps, *o;
|
||||||
|
int i, rc = 0;
|
||||||
|
|
||||||
|
root = json_object_from_fd(STDIN_FILENO);
|
||||||
|
|
||||||
|
if (!root) {
|
||||||
|
fprintf(stderr, "No capabilities provided\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!json_object_object_get_ex(root, "provides", &csup)) {
|
||||||
|
fprintf(stderr, "No supported capabilities provided\n");
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!json_object_object_get_ex(csup, "version", &cver)) {
|
||||||
|
fprintf(stderr, "No version provided in capabilities\n");
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!json_object_object_get_ex(csup, "actions", &cact)) {
|
||||||
|
fprintf(stderr, "No actions provided in capabilities\n");
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!json_object_object_get_ex(csup, "events", &cev)) {
|
||||||
|
fprintf(stderr, "No events provided in capabilities\n");
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Advertise the subset of supported capabilities from the list
|
||||||
|
* provided on stdin.
|
||||||
|
*/
|
||||||
|
|
||||||
|
cap = json_object_new_object();
|
||||||
|
caps = json_object_new_object();
|
||||||
|
json_object_object_add(cap, "supports", caps);
|
||||||
|
/*
|
||||||
|
* Currently we always advertise a fixed version, but we may need to
|
||||||
|
* revisit this if we increase MDEVCTL_CAP_VERSION in the future (e.g.
|
||||||
|
* how to handle ap-check having a greater supported version than
|
||||||
|
* what mdevctl reports)
|
||||||
|
*/
|
||||||
|
o = json_object_new_int(MDEVCTL_CAP_VERSION);
|
||||||
|
json_object_object_add(caps, "version", o);
|
||||||
|
|
||||||
|
o = json_object_new_array();
|
||||||
|
for (i = 0; i < NUM_MDEVCTL_ACTIONS; i++)
|
||||||
|
json_add_attr(o, cact, mdevctl_action_table[i].action);
|
||||||
|
json_object_object_add(caps, "actions", o);
|
||||||
|
|
||||||
|
o = json_object_new_array();
|
||||||
|
for (i = 0; i < NUM_MDEVCTL_EVENTS; i++)
|
||||||
|
json_add_attr(o, cev, mdevctl_event_table[i].event);
|
||||||
|
json_object_object_add(caps, "events", o);
|
||||||
|
|
||||||
|
/* Return supported capabilities JSON on stdout */
|
||||||
|
printf("%s\n", json_object_to_json_string(cap));
|
||||||
|
|
||||||
|
json_object_put(cap);
|
||||||
|
|
||||||
|
out:
|
||||||
|
json_object_put(root);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Determine which mdevctl action is being checked and handle accordingly.
|
* Determine which mdevctl action is being checked and handle accordingly.
|
||||||
*/
|
*/
|
||||||
@@ -911,8 +1159,6 @@ static int ap_check_handle_action(struct ap_check_anchor *anc)
|
|||||||
case MDEVCTL_ACTION_UNDEFINE:
|
case MDEVCTL_ACTION_UNDEFINE:
|
||||||
rc = ap_check_handle_undefine(anc);
|
rc = ap_check_handle_undefine(anc);
|
||||||
break;
|
break;
|
||||||
case MDEVCTL_ACTION_LIST:
|
|
||||||
case MDEVCTL_ACTION_TYPES:
|
|
||||||
default:
|
default:
|
||||||
/* Ignore some actions including unknown ones */
|
/* Ignore some actions including unknown ones */
|
||||||
break;
|
break;
|
||||||
@@ -937,6 +1183,19 @@ static int ap_check_handle_action(struct ap_check_anchor *anc)
|
|||||||
case MDEVCTL_ACTION_ATTRIBUTES:
|
case MDEVCTL_ACTION_ATTRIBUTES:
|
||||||
rc = ap_check_handle_get_attributes(anc);
|
rc = ap_check_handle_get_attributes(anc);
|
||||||
break;
|
break;
|
||||||
|
case MDEVCTL_ACTION_CAPABILITIES:
|
||||||
|
rc = ap_check_handle_get_capabilities();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Ignore some actions including unknown ones */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MDEVCTL_EVENT_LIVE:
|
||||||
|
switch (anc->action) {
|
||||||
|
case MDEVCTL_ACTION_MODIFY:
|
||||||
|
rc = ap_check_handle_live_modify(anc);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* Ignore some actions including unknown ones */
|
/* Ignore some actions including unknown ones */
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ enum mdevctl_action_id {
|
|||||||
MDEVCTL_ACTION_TYPES,
|
MDEVCTL_ACTION_TYPES,
|
||||||
MDEVCTL_ACTION_UNDEFINE,
|
MDEVCTL_ACTION_UNDEFINE,
|
||||||
MDEVCTL_ACTION_ATTRIBUTES,
|
MDEVCTL_ACTION_ATTRIBUTES,
|
||||||
|
MDEVCTL_ACTION_CAPABILITIES,
|
||||||
/* UNKNOWN must always be the last in the list */
|
/* UNKNOWN must always be the last in the list */
|
||||||
MDEVCTL_ACTION_UNKNOWN,
|
MDEVCTL_ACTION_UNKNOWN,
|
||||||
};
|
};
|
||||||
@@ -38,6 +39,7 @@ enum mdevctl_event_id {
|
|||||||
MDEVCTL_EVENT_PRE = 0,
|
MDEVCTL_EVENT_PRE = 0,
|
||||||
MDEVCTL_EVENT_POST,
|
MDEVCTL_EVENT_POST,
|
||||||
MDEVCTL_EVENT_GET,
|
MDEVCTL_EVENT_GET,
|
||||||
|
MDEVCTL_EVENT_LIVE,
|
||||||
MDEVCTL_EVENT_UNKNOWN,
|
MDEVCTL_EVENT_UNKNOWN,
|
||||||
};
|
};
|
||||||
#define NUM_MDEVCTL_EVENTS MDEVCTL_EVENT_UNKNOWN
|
#define NUM_MDEVCTL_EVENTS MDEVCTL_EVENT_UNKNOWN
|
||||||
|
|||||||
@@ -951,7 +951,7 @@ static void set_record_extension(struct file *f, int *record, off_t addr,
|
|||||||
|
|
||||||
if (f->record_scan_state != RSS_DATA_BLOCK_STARTED &&
|
if (f->record_scan_state != RSS_DATA_BLOCK_STARTED &&
|
||||||
f->record_scan_state != RSS_DATA_BLOCK_EXT)
|
f->record_scan_state != RSS_DATA_BLOCK_EXT)
|
||||||
DIE("%s: interal error\n", __func__);
|
DIE("%s: internal error\n", __func__);
|
||||||
|
|
||||||
BUG(*record >= f->fst->nr_records);
|
BUG(*record >= f->fst->nr_records);
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -32,8 +32,8 @@ endif
|
|||||||
# 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 := 33
|
RELEASE := 35
|
||||||
PATCHLEVEL := 1
|
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)
|
||||||
export S390_TOOLS_RELEASE
|
export S390_TOOLS_RELEASE
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
* Number of PAI counters. Contains all counters regardless of kernel or user
|
* Number of PAI counters. Contains all counters regardless of kernel or user
|
||||||
* space
|
* space
|
||||||
*/
|
*/
|
||||||
#define MAX_NUM_PAI 156
|
#define MAX_NUM_PAI 172
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the sysfs directory from which cpacfstatsd daemon application loads
|
* This is the sysfs directory from which cpacfstatsd daemon application loads
|
||||||
|
|||||||
@@ -192,7 +192,27 @@ const struct pai_counter pai[] = {
|
|||||||
[152] = {"PCKMO ECC Ed25519", KERNEL_ONLY_COUNTER},
|
[152] = {"PCKMO ECC Ed25519", KERNEL_ONLY_COUNTER},
|
||||||
[153] = {"PCKMO ECC Ed448", KERNEL_ONLY_COUNTER},
|
[153] = {"PCKMO ECC Ed448", KERNEL_ONLY_COUNTER},
|
||||||
[154] = {"Reserved 1", KERNEL_ONLY_COUNTER},
|
[154] = {"Reserved 1", KERNEL_ONLY_COUNTER},
|
||||||
[155] = {"Reserved 2", KERNEL_ONLY_COUNTER}
|
[155] = {"Reserved 2", KERNEL_ONLY_COUNTER},
|
||||||
|
[156] = {"KM AES-XTS (full) 128bit", KERNEL_AND_USER_COUNTER},
|
||||||
|
[157] = {"KM AES-XTS (full) 256bit", KERNEL_AND_USER_COUNTER},
|
||||||
|
[158] = {"KM AES-XTS (full) 128bit protected key",
|
||||||
|
KERNEL_AND_USER_COUNTER},
|
||||||
|
[159] = {"KM AES-XTS (full) 256bit protected key",
|
||||||
|
KERNEL_AND_USER_COUNTER},
|
||||||
|
[160] = {"KMAC HMAC SHA 224", KERNEL_AND_USER_COUNTER},
|
||||||
|
[161] = {"KMAC HMAC SHA 256", KERNEL_AND_USER_COUNTER},
|
||||||
|
[162] = {"KMAC HMAC SHA 384", KERNEL_AND_USER_COUNTER},
|
||||||
|
[163] = {"KMAC HMAC SHA 512", KERNEL_AND_USER_COUNTER},
|
||||||
|
[164] = {"KMAC HMAC SHA 224 protected key", KERNEL_AND_USER_COUNTER},
|
||||||
|
[165] = {"KMAC HMAC SHA 256 protected key", KERNEL_AND_USER_COUNTER},
|
||||||
|
[166] = {"KMAC HMAC SHA 384 protected key", KERNEL_AND_USER_COUNTER},
|
||||||
|
[167] = {"KMAC HMAC SHA 512 protected key", KERNEL_AND_USER_COUNTER},
|
||||||
|
[168] = {"PCKMO HMAC 512 protected key", KERNEL_ONLY_COUNTER},
|
||||||
|
[169] = {"PCKMO HMAC 1024 protected key", KERNEL_ONLY_COUNTER},
|
||||||
|
[170] = {"PCKMO AES-XTS 128bit double key protected key",
|
||||||
|
KERNEL_ONLY_COUNTER},
|
||||||
|
[171] = {"PCKMO AES-XTS 256bit double key protected key",
|
||||||
|
KERNEL_ONLY_COUNTER}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ static volatile int stopsig;
|
|||||||
*/
|
*/
|
||||||
static const unsigned int pai_idx[] = {
|
static const unsigned int pai_idx[] = {
|
||||||
// KM
|
// KM
|
||||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 156, 157, 158,
|
||||||
|
159,
|
||||||
// KMC
|
// KMC
|
||||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
|
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
|
||||||
// KMA
|
// KMA
|
||||||
@@ -55,7 +56,8 @@ static const unsigned int pai_idx[] = {
|
|||||||
// KLMD
|
// KLMD
|
||||||
81, 82, 83, 84, 85, 86, 87, 88, 89,
|
81, 82, 83, 84, 85, 86, 87, 88, 89,
|
||||||
// KMAC
|
// KMAC
|
||||||
90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101,
|
90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 160, 161, 162, 163,
|
||||||
|
164, 165, 166, 167,
|
||||||
// PCC
|
// PCC
|
||||||
102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
|
102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
|
||||||
114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
|
114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
|
||||||
@@ -65,7 +67,7 @@ static const unsigned int pai_idx[] = {
|
|||||||
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
|
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
|
||||||
140, 141, 142,
|
140, 141, 142,
|
||||||
// PCKMO
|
// PCKMO
|
||||||
143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153,
|
143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 168, 169, 170, 171,
|
||||||
// Reserved
|
// Reserved
|
||||||
154, 155
|
154, 155
|
||||||
};
|
};
|
||||||
@@ -108,7 +110,6 @@ static int recv_query(int s, enum ctr_e *ctr, enum cmd_e *cmd)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int send_answer(int s, int ctr, int state, uint64_t value)
|
static int send_answer(int s, int ctr, int state, uint64_t value)
|
||||||
{
|
{
|
||||||
struct msg m;
|
struct msg m;
|
||||||
@@ -124,7 +125,6 @@ static int send_answer(int s, int ctr, int state, uint64_t value)
|
|||||||
return send_msg(s, &m, DEFAULT_SEND_TIMEOUT);
|
return send_msg(s, &m, DEFAULT_SEND_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print according to protocol for PAI:
|
* Print according to protocol for PAI:
|
||||||
* - first the state and the number of PAI counters that follow
|
* - first the state and the number of PAI counters that follow
|
||||||
@@ -160,7 +160,6 @@ static int do_send_pai(int s, int user, unsigned int *counter)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int do_enable(int s, enum ctr_e ctr, unsigned int *supported_counters)
|
static int do_enable(int s, enum ctr_e ctr, unsigned int *supported_counters)
|
||||||
{
|
{
|
||||||
uint64_t value = 0;
|
uint64_t value = 0;
|
||||||
@@ -201,7 +200,6 @@ static int do_enable(int s, enum ctr_e ctr, unsigned int *supported_counters)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int do_disable(int s, enum ctr_e ctr, unsigned int *supported_counters)
|
static int do_disable(int s, enum ctr_e ctr, unsigned int *supported_counters)
|
||||||
{
|
{
|
||||||
int i, rc = 0;
|
int i, rc = 0;
|
||||||
@@ -228,7 +226,6 @@ static int do_disable(int s, enum ctr_e ctr, unsigned int *supported_counters)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int do_reset(int s, enum ctr_e ctr, unsigned int *supported_counters)
|
static int do_reset(int s, enum ctr_e ctr, unsigned int *supported_counters)
|
||||||
{
|
{
|
||||||
int i, rc = 0, state;
|
int i, rc = 0, state;
|
||||||
@@ -260,7 +257,6 @@ static int do_reset(int s, enum ctr_e ctr, unsigned int *supported_counters)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int do_print(int s, enum ctr_e ctr, unsigned int *supported_counters)
|
static int do_print(int s, enum ctr_e ctr, unsigned int *supported_counters)
|
||||||
{
|
{
|
||||||
int i, rc = 0, state;
|
int i, rc = 0, state;
|
||||||
@@ -292,7 +288,6 @@ static int do_print(int s, enum ctr_e ctr, unsigned int *supported_counters)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int become_daemon(int *startup_pipe)
|
static int become_daemon(int *startup_pipe)
|
||||||
{
|
{
|
||||||
int child_initialized = 0, fd;
|
int child_initialized = 0, fd;
|
||||||
@@ -385,7 +380,6 @@ static int become_daemon(int *startup_pipe)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void remove_sock(void)
|
static void remove_sock(void)
|
||||||
{
|
{
|
||||||
remove(SOCKET_FILE);
|
remove(SOCKET_FILE);
|
||||||
@@ -447,14 +441,12 @@ static void remove_pidfile(void)
|
|||||||
remove(PID_FILE);
|
remove(PID_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void signalhandler(int sig)
|
void signalhandler(int sig)
|
||||||
{
|
{
|
||||||
perf_stop();
|
perf_stop();
|
||||||
stopsig = sig;
|
stopsig = sig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int eprint(const char *format, ...)
|
int eprint(const char *format, ...)
|
||||||
{
|
{
|
||||||
char buf[512];
|
char buf[512];
|
||||||
@@ -476,7 +468,6 @@ int eprint(const char *format, ...)
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* returns -1 on error
|
* returns -1 on error
|
||||||
* returns X where X is the found counters in dir
|
* returns X where X is the found counters in dir
|
||||||
|
|||||||
+3
-1
@@ -4,9 +4,11 @@ all: cpuplugd
|
|||||||
|
|
||||||
LDLIBS += -lm
|
LDLIBS += -lm
|
||||||
|
|
||||||
|
libs = $(rootdir)/libutil/libutil.a
|
||||||
|
|
||||||
OBJECTS = daemon.o cpu.o info.o terms.o config.o main.o getopt.o mem.o
|
OBJECTS = daemon.o cpu.o info.o terms.o config.o main.o getopt.o mem.o
|
||||||
|
|
||||||
cpuplugd: $(OBJECTS)
|
cpuplugd: $(OBJECTS) $(libs)
|
||||||
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
|||||||
+55
-54
@@ -204,6 +204,45 @@ void parse_configfile(char *file)
|
|||||||
fclose(filp);
|
fclose(filp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void apply_cpu_config(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Check that the initial number of cpus is not below the
|
||||||
|
* minimum
|
||||||
|
*/
|
||||||
|
if (num_cpu_start < cfg.cpu_min &&
|
||||||
|
get_numcpus() >= cfg.cpu_min) {
|
||||||
|
cpuplugd_debug("The number of online cpus is below ");
|
||||||
|
cpuplugd_debug("the minimum and will be increased.\n");
|
||||||
|
while (get_num_online_cpus() < cfg.cpu_min) {
|
||||||
|
if (hotplug_one_cpu())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (get_num_online_cpus() > cfg.cpu_max) {
|
||||||
|
cpuplugd_debug("The number of online cpus is above the maximum");
|
||||||
|
cpuplugd_debug(" and will be decreased.\n");
|
||||||
|
while (get_num_online_cpus() > cfg.cpu_max) {
|
||||||
|
if (hotunplug_one_cpu())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cfg.cpu_min > get_numcpus()) {
|
||||||
|
/*
|
||||||
|
* This check only works if nobody used the
|
||||||
|
* additional_cpus in the boot parameter section
|
||||||
|
*/
|
||||||
|
cpuplugd_debug("The minimum amount of cpus is above the ");
|
||||||
|
cpuplugd_debug("number of available cpus.\n");
|
||||||
|
cpuplugd_exit("Detected %d available cpus\n", get_numcpus());
|
||||||
|
}
|
||||||
|
if (get_num_online_cpus() < cfg.cpu_min) {
|
||||||
|
cpuplugd_debug("Failed to set the number of online cpus to ");
|
||||||
|
cpuplugd_debug("the minimum. ");
|
||||||
|
cpuplugd_exit("Aborting.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if the required settings are found in the configuration file.
|
* Check if the required settings are found in the configuration file.
|
||||||
* "Autodetect" if cpu and/or memory hotplug configuration entries
|
* "Autodetect" if cpu and/or memory hotplug configuration entries
|
||||||
@@ -211,7 +250,6 @@ void parse_configfile(char *file)
|
|||||||
*/
|
*/
|
||||||
void check_config()
|
void check_config()
|
||||||
{
|
{
|
||||||
int cpuid;
|
|
||||||
int lpar_status;
|
int lpar_status;
|
||||||
|
|
||||||
lpar_status = check_lpar();
|
lpar_status = check_lpar();
|
||||||
@@ -262,60 +300,23 @@ void check_config()
|
|||||||
/*
|
/*
|
||||||
* Save the number of online cpus and the cmm_pagesize at startup,
|
* Save the number of online cpus and the cmm_pagesize at startup,
|
||||||
* so that we can enable exactly the same amount when the daemon ends
|
* so that we can enable exactly the same amount when the daemon ends
|
||||||
|
*
|
||||||
|
* Don't adjust cpus if system is on vertical polarization
|
||||||
*/
|
*/
|
||||||
if (cpu) {
|
saved_polarization = get_polarization();
|
||||||
num_cpu_start = get_num_online_cpus();
|
num_cpu_start = get_num_online_cpus();
|
||||||
cpuplugd_debug("Daemon started with %d active cpus.\n",
|
cpuplugd_debug("Daemon started with %d active cpus.\n",
|
||||||
num_cpu_start);
|
num_cpu_start);
|
||||||
/*
|
if (saved_polarization < 0) {
|
||||||
* Check that the initial number of cpus is not below the
|
cpuplugd_debug("Daemon couldn't determine system polarization\n");
|
||||||
* minimum
|
cpuplugd_debug("Starting without evaluating cpu rules\n");
|
||||||
*/
|
} else if (saved_polarization == PLR_VERTICAL) {
|
||||||
if (num_cpu_start < cfg.cpu_min &&
|
cpuplugd_debug("Daemon started with vertical polarization.\n");
|
||||||
get_numcpus() >= cfg.cpu_min) {
|
cpuplugd_debug("Cpu adjustments won't be made until system ");
|
||||||
cpuplugd_debug("The number of online cpus is below "
|
cpuplugd_debug("is in horizontal polarization\n");
|
||||||
"the minimum and will be increased.\n");
|
} else if (saved_polarization == PLR_HORIZONTAL &&
|
||||||
cpuid = 0;
|
cpu == 1) {
|
||||||
while (get_num_online_cpus() < cfg.cpu_min &&
|
apply_cpu_config();
|
||||||
cpuid < get_numcpus()) {
|
|
||||||
if (is_online(cpuid) == 1) {
|
|
||||||
cpuid++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
cpuplugd_debug("cpu with id %d is currently offline "
|
|
||||||
"and will be enabled\n", cpuid);
|
|
||||||
hotplug(cpuid);
|
|
||||||
cpuid++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (get_num_online_cpus() > cfg.cpu_max) {
|
|
||||||
cpuplugd_debug("The number of online cpus is above the maximum"
|
|
||||||
" and will be decreased.\n");
|
|
||||||
cpuid = 0;
|
|
||||||
while (get_num_online_cpus() > cfg.cpu_max &&
|
|
||||||
cpuid < get_numcpus()) {
|
|
||||||
if (is_online(cpuid) != 1) {
|
|
||||||
cpuid++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
cpuplugd_debug("cpu with id %d is currently online "
|
|
||||||
"and will be disabled\n", cpuid);
|
|
||||||
hotunplug(cpuid);
|
|
||||||
cpuid++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (cfg.cpu_min > get_numcpus())
|
|
||||||
/*
|
|
||||||
* This check only works if nobody used the
|
|
||||||
* additional_cpus in the boot parameter section
|
|
||||||
*/
|
|
||||||
cpuplugd_exit("The minimum amount of cpus is above "
|
|
||||||
"the number of available cpus.\n"
|
|
||||||
"Detected %d available cpus\n",
|
|
||||||
get_numcpus());
|
|
||||||
if (get_num_online_cpus() < cfg.cpu_min)
|
|
||||||
cpuplugd_exit("Failed to set the number of online "
|
|
||||||
"cpus to the minimum. Aborting.\n");
|
|
||||||
}
|
}
|
||||||
if (memory == 1) {
|
if (memory == 1) {
|
||||||
/*
|
/*
|
||||||
|
|||||||
+193
-169
@@ -12,217 +12,241 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include "cpuplugd.h"
|
#include "cpuplugd.h"
|
||||||
|
|
||||||
|
#define NUM_BASE (10)
|
||||||
|
#define CPU_OFFLINE (0)
|
||||||
|
#define CPU_ONLINE (1)
|
||||||
|
#define CPU_DECONFIGURED (0)
|
||||||
|
#define CPU_CONFIGURED (1)
|
||||||
|
#define CPU_LIST_LEN (4096)
|
||||||
|
|
||||||
/*
|
static int get_sysfs_attribute_cpu_count(char *path)
|
||||||
* Return overall number of available cpus. This does not necessarily
|
|
||||||
* mean that those are currently online
|
|
||||||
*/
|
|
||||||
int get_numcpus()
|
|
||||||
{
|
{
|
||||||
int i;
|
char cpu_list[CPU_LIST_LEN];
|
||||||
char path[PATH_MAX];
|
int number, start, end;
|
||||||
int number = 0;
|
char *sub_list;
|
||||||
|
|
||||||
for (i = 0; ; i++) {
|
if (util_file_read_line(cpu_list, sizeof(cpu_list), path))
|
||||||
/* check whether file exists and is readable */
|
cpuplugd_exit("Cannot open %s file: %s\n", path, strerror(errno));
|
||||||
sprintf(path, "/sys/devices/system/cpu/cpu%d", i);
|
number = 0;
|
||||||
if (access(path, R_OK) == 0)
|
sub_list = strtok(cpu_list, ",");
|
||||||
|
while (sub_list) {
|
||||||
|
if (strchr(sub_list, '-')) {
|
||||||
|
if (sscanf(sub_list, "%d-%d", &start, &end) != 2)
|
||||||
|
cpuplugd_exit("Malformed content of %s: %s\n", path, sub_list);
|
||||||
|
number += (end - start) + 1;
|
||||||
|
} else {
|
||||||
number++;
|
number++;
|
||||||
else
|
}
|
||||||
break;
|
sub_list = strtok(NULL, ",");
|
||||||
}
|
}
|
||||||
return number;
|
return number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return number of online cpus
|
* get_numcpus() - return number of present cpus by sysfs'
|
||||||
|
* cpu/present attribute.
|
||||||
|
* This number represents the total number of usable cpus,
|
||||||
|
* this includes offline or deconfigured cpus as well.
|
||||||
*/
|
*/
|
||||||
int get_num_online_cpus()
|
int get_numcpus(void)
|
||||||
{
|
{
|
||||||
FILE *filp;
|
int number;
|
||||||
int i;
|
char *path;
|
||||||
char path[PATH_MAX];
|
|
||||||
int status = 0;
|
|
||||||
int value_of_onlinefile, rc;
|
|
||||||
|
|
||||||
for (i = 0; i < get_numcpus(); i++) {
|
path = util_path_sysfs("devices/system/cpu/present");
|
||||||
/* check wether file exists and is readable */
|
number = get_sysfs_attribute_cpu_count(path);
|
||||||
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", i);
|
free(path);
|
||||||
if (access(path, R_OK) != 0) {
|
if (number <= 0)
|
||||||
status++;
|
cpuplugd_exit("number of present cpus (%d) <= 0\n", number);
|
||||||
continue;
|
return number;
|
||||||
}
|
}
|
||||||
filp = fopen(path, "r");
|
|
||||||
if (!filp)
|
/*
|
||||||
cpuplugd_exit("Cannot open cpu online file: "
|
* get_num_online_cpus() - return number of online cpus
|
||||||
"%s\n", strerror(errno));
|
* by parsing sysfs cpu/online attribute
|
||||||
else {
|
*/
|
||||||
rc = fscanf(filp, "%d", &value_of_onlinefile);
|
int get_num_online_cpus(void)
|
||||||
if (rc != 1)
|
{
|
||||||
cpuplugd_exit("Cannot read cpu online file: "
|
int number;
|
||||||
"%s\n", strerror(errno));
|
char *path;
|
||||||
if (value_of_onlinefile == 1)
|
|
||||||
status++;
|
path = util_path_sysfs("devices/system/cpu/online");
|
||||||
}
|
number = get_sysfs_attribute_cpu_count(path);
|
||||||
fclose(filp);
|
free(path);
|
||||||
|
if (number <= 0)
|
||||||
|
cpuplugd_exit("number of online cpus (%d) <= 0\n", number);
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get_polarization() - return system polarization
|
||||||
|
*/
|
||||||
|
int get_polarization(void)
|
||||||
|
{
|
||||||
|
int polarization;
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
path = util_path_sysfs("devices/system/cpu/dispatching");
|
||||||
|
if (util_file_read_i(&polarization, NUM_BASE, path) < 0) {
|
||||||
|
polarization = -1;
|
||||||
|
cpuplugd_debug("failed to read system polarization\n");
|
||||||
}
|
}
|
||||||
|
free(path);
|
||||||
|
return polarization;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* is_cpu_hotpluggable() - check if cpuhotplug operations are supported
|
||||||
|
* for the given cpu.
|
||||||
|
*/
|
||||||
|
static int is_cpu_hotpluggable(int cpuid)
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
path = util_path_sysfs("devices/system/cpu/cpu%d/online", cpuid);
|
||||||
|
rc = util_path_exists(path);
|
||||||
|
free(path);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hotplug() - perform cpu hotplug on given cpuid
|
||||||
|
*/
|
||||||
|
static int hotplug(int cpuid)
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
path = util_path_sysfs("devices/system/cpu/cpu%d/online", cpuid);
|
||||||
|
rc = util_file_write_l(CPU_ONLINE, NUM_BASE, path);
|
||||||
|
if (rc < 0)
|
||||||
|
cpuplugd_debug("failed to enable cpu with id %d\n", cpuid);
|
||||||
|
free(path);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hotunplug() - perform cpu hotunplug on given cpuid
|
||||||
|
*/
|
||||||
|
static int hotunplug(int cpuid)
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
path = util_path_sysfs("devices/system/cpu/cpu%d/online", cpuid);
|
||||||
|
rc = util_file_write_l(CPU_OFFLINE, NUM_BASE, path);
|
||||||
|
if (rc < 0)
|
||||||
|
cpuplugd_debug("failed to disable cpu with id %d\n", cpuid);
|
||||||
|
free(path);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get_cpu_attribute() - get a certain cpu's selected attribute
|
||||||
|
*/
|
||||||
|
static int get_cpu_attribute(int cpuid, char *attribute)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
path = util_path_sysfs("devices/system/cpu/cpu%d/%s", cpuid, attribute);
|
||||||
|
if (util_file_read_i(&status, NUM_BASE, path) < 0) {
|
||||||
|
status = -1;
|
||||||
|
cpuplugd_debug("failed to read %s status of cpu with id %d\n", attribute, cpuid);
|
||||||
|
}
|
||||||
|
free(path);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enable a certain cpu
|
* hotplug_one_cpu() - perform hotplugging on the first available cpu
|
||||||
*/
|
*/
|
||||||
int hotplug(int cpuid)
|
int hotplug_one_cpu(void)
|
||||||
{
|
{
|
||||||
FILE *filp;
|
struct dirent **cpu_dir;
|
||||||
char path[PATH_MAX];
|
int cpuid, count, i, rc;
|
||||||
int status, rc;
|
char *path;
|
||||||
|
|
||||||
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpuid);
|
rc = -1;
|
||||||
if (access(path, W_OK) == 0) {
|
path = util_path_sysfs("devices/system/cpu/");
|
||||||
filp = fopen(path, "w");
|
count = util_scandir(&cpu_dir, alphasort, path, "cpu[0-9]*");
|
||||||
if (!filp)
|
for (i = 0; (i < count) && (rc != 0); i++) {
|
||||||
cpuplugd_exit("Cannot open cpu online file: %s\n",
|
if (sscanf(cpu_dir[i]->d_name, "cpu%d", &cpuid) != 1)
|
||||||
strerror(errno));
|
cpuplugd_exit("Malformed content of %s: %s\n", path, cpu_dir[i]->d_name);
|
||||||
fprintf(filp, "1");
|
if (!is_cpu_hotpluggable(cpuid))
|
||||||
fclose(filp);
|
continue;
|
||||||
/*
|
if (get_cpu_attribute(cpuid, "configure") == CPU_CONFIGURED &&
|
||||||
* check if the attempt to enable the cpus really worked
|
get_cpu_attribute(cpuid, "online") == CPU_OFFLINE) {
|
||||||
*/
|
cpuplugd_debug("cpu%d will be enabled", cpuid);
|
||||||
filp = fopen(path, "r");
|
rc = hotplug(cpuid);
|
||||||
rc = fscanf(filp, "%d", &status);
|
|
||||||
if (rc != 1)
|
|
||||||
cpuplugd_exit("Cannot open cpu online file: %s\n",
|
|
||||||
strerror(errno));
|
|
||||||
fclose(filp);
|
|
||||||
if (status == 1) {
|
|
||||||
cpuplugd_debug("cpu with id %d enabled\n", cpuid);
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
cpuplugd_debug("failed to enable cpu with id %d\n",
|
|
||||||
cpuid);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cpuplugd_debug("cpu with id %d cannot be hotplugged\n", cpuid);
|
util_scandir_free(cpu_dir, count);
|
||||||
return -1;
|
free(path);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disable a certain cpu
|
* hotunplug_one_cpu() - perform hotunplugging on the first available cpu
|
||||||
*/
|
*/
|
||||||
int hotunplug(int cpuid)
|
int hotunplug_one_cpu(void)
|
||||||
{
|
{
|
||||||
FILE *filp;
|
struct dirent **cpu_dir;
|
||||||
int state, rc;
|
int cpuid, count, i, rc;
|
||||||
int retval = -1;
|
char *path;
|
||||||
char path[PATH_MAX];
|
|
||||||
|
|
||||||
state = -1;
|
rc = -1;
|
||||||
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpuid);
|
path = util_path_sysfs("devices/system/cpu/");
|
||||||
if (access(path, W_OK) == 0) {
|
count = util_scandir(&cpu_dir, alphasort, path, "cpu[0-9]*");
|
||||||
filp = fopen(path, "w");
|
for (i = 0; (i < count) && (rc != 0); i++) {
|
||||||
fprintf(filp, "0");
|
if (sscanf(cpu_dir[i]->d_name, "cpu%d", &cpuid) != 1)
|
||||||
fclose(filp);
|
cpuplugd_exit("Malformed content of %s: %s\n", path, cpu_dir[i]->d_name);
|
||||||
/*
|
if (!is_cpu_hotpluggable(cpuid))
|
||||||
* Check if the attempt to enable the cpus really worked
|
continue;
|
||||||
*/
|
if (get_cpu_attribute(cpuid, "online") == CPU_ONLINE) {
|
||||||
filp = fopen(path, "r");
|
cpuplugd_debug("cpu%d will be disabled\n", cpuid);
|
||||||
rc = fscanf(filp, "%d", &state);
|
rc = hotunplug(cpuid);
|
||||||
if (rc != 1)
|
|
||||||
cpuplugd_error("Failed to disable cpu with id %d\n",
|
|
||||||
cpuid);
|
|
||||||
fclose(filp);
|
|
||||||
if (state == 0)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
cpuplugd_debug("cpu with id %d cannot be hotunplugged\n", cpuid);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if a certain cpu is currently online
|
|
||||||
*/
|
|
||||||
int is_online(int cpuid)
|
|
||||||
{
|
|
||||||
FILE *filp;
|
|
||||||
int state;
|
|
||||||
int retval, rc;
|
|
||||||
char path[PATH_MAX];
|
|
||||||
|
|
||||||
retval = -1;
|
|
||||||
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpuid);
|
|
||||||
if (access(path, R_OK) == 0) {
|
|
||||||
filp = fopen(path, "r");
|
|
||||||
rc = fscanf(filp, "%d", &state);
|
|
||||||
if (rc == 1) {
|
|
||||||
if (state == 1)
|
|
||||||
retval = 1;
|
|
||||||
if (state == 0)
|
|
||||||
retval = 0;
|
|
||||||
}
|
}
|
||||||
fclose(filp);
|
|
||||||
} else {
|
|
||||||
retval = 1;
|
|
||||||
}
|
}
|
||||||
return retval;
|
util_scandir_free(cpu_dir, count);
|
||||||
|
free(path);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cleanup method. If the daemon is stopped, we (re)activate all cpus
|
* Cleanup method. If the daemon is stopped, we (re)activate all cpus
|
||||||
*/
|
*/
|
||||||
void reactivate_cpus()
|
void reactivate_cpus(void)
|
||||||
{
|
{
|
||||||
/*
|
struct dirent **cpu_dir;
|
||||||
* Only enable the number of cpus which where
|
int cpuid, nc, count, i;
|
||||||
* available at daemon startup time
|
char *path;
|
||||||
*/
|
|
||||||
int cpuid, nc;
|
|
||||||
|
|
||||||
cpuid = 0;
|
/*
|
||||||
/* suppress verbose messages on exit */
|
* Only enable the number of cpus which where available at
|
||||||
debug = 0;
|
* daemon startup time by checking num_cpu_start.
|
||||||
/*
|
* We check for num_cpu_start != 0 because we might want to
|
||||||
* We check for num_cpu_start != 0 because we might want to
|
* clean up, before we queried for the number on cpus at
|
||||||
* clean up, before we queried for the number on cpus at
|
* startup
|
||||||
* startup
|
*/
|
||||||
*/
|
|
||||||
if (num_cpu_start == 0)
|
if (num_cpu_start == 0)
|
||||||
return;
|
return;
|
||||||
while (get_num_online_cpus() != num_cpu_start && cpuid < get_numcpus()) {
|
nc = 0;
|
||||||
|
path = util_path_sysfs("devices/system/cpu/");
|
||||||
|
count = util_scandir(&cpu_dir, alphasort, path, "cpu[0-9]*");
|
||||||
|
for (i = 0; (i < count) && (nc != num_cpu_start); i++) {
|
||||||
nc = get_num_online_cpus();
|
nc = get_num_online_cpus();
|
||||||
if (nc == num_cpu_start)
|
if (sscanf(cpu_dir[i]->d_name, "cpu%d", &cpuid) != 1)
|
||||||
return;
|
cpuplugd_exit("Malformed content of %s: %s\n", path, cpu_dir[i]->d_name);
|
||||||
if (nc > num_cpu_start && is_online(cpuid) == 1)
|
if (nc > num_cpu_start &&
|
||||||
|
get_cpu_attribute(cpuid, "online") == CPU_ONLINE)
|
||||||
hotunplug(cpuid);
|
hotunplug(cpuid);
|
||||||
if (nc < num_cpu_start && is_online(cpuid) == 0)
|
if (nc < num_cpu_start &&
|
||||||
|
get_cpu_attribute(cpuid, "online") == CPU_OFFLINE)
|
||||||
hotplug(cpuid);
|
hotplug(cpuid);
|
||||||
cpuid++;
|
|
||||||
}
|
}
|
||||||
|
util_scandir_free(cpu_dir, count);
|
||||||
|
free(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* In kernels > 2.6.24 cpus can be deconfigured. The following functions is used
|
|
||||||
* to check if a certain cpus is in a deconfigured state.
|
|
||||||
*/
|
|
||||||
int cpu_is_configured(int cpuid)
|
|
||||||
{
|
|
||||||
FILE *filp;
|
|
||||||
int retval, state, rc;
|
|
||||||
char path[4096];
|
|
||||||
|
|
||||||
retval = -1;
|
|
||||||
sprintf(path, "/sys/devices/system/cpu/cpu%d/configure", cpuid);
|
|
||||||
if (access(path, R_OK) == 0) {
|
|
||||||
filp = fopen(path, "r");
|
|
||||||
rc = fscanf(filp, "%d", &state);
|
|
||||||
if (rc == 1) {
|
|
||||||
if (state == 1)
|
|
||||||
retval = 1;
|
|
||||||
if (state == 0)
|
|
||||||
retval = 0;
|
|
||||||
}
|
|
||||||
fclose(filp);
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|||||||
+10
-4
@@ -23,6 +23,9 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "lib/util_base.h"
|
#include "lib/util_base.h"
|
||||||
|
#include "lib/util_path.h"
|
||||||
|
#include "lib/util_file.h"
|
||||||
|
#include "lib/util_scandir.h"
|
||||||
#include "lib/zt_common.h"
|
#include "lib/zt_common.h"
|
||||||
|
|
||||||
#define NAME "cpuplugd"
|
#define NAME "cpuplugd"
|
||||||
@@ -35,6 +38,8 @@
|
|||||||
#define MAX_VARNAME 128
|
#define MAX_VARNAME 128
|
||||||
#define MAX_LINESIZE 2048
|
#define MAX_LINESIZE 2048
|
||||||
#define CPUSTATS 10
|
#define CPUSTATS 10
|
||||||
|
#define PLR_HORIZONTAL 0
|
||||||
|
#define PLR_VERTICAL 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Precedence of C operators
|
* Precedence of C operators
|
||||||
@@ -173,9 +178,11 @@ extern unsigned int history_max;
|
|||||||
extern unsigned int history_current;
|
extern unsigned int history_current;
|
||||||
extern struct symbol_names sym_names[];
|
extern struct symbol_names sym_names[];
|
||||||
extern unsigned int sym_names_count;
|
extern unsigned int sym_names_count;
|
||||||
|
extern int saved_polarization;
|
||||||
|
|
||||||
int get_numcpus();
|
int get_numcpus();
|
||||||
int get_num_online_cpus();
|
int get_num_online_cpus();
|
||||||
|
int get_polarization(void);
|
||||||
void get_loadavg_runnable(double *loadavg, double *runnable);
|
void get_loadavg_runnable(double *loadavg, double *runnable);
|
||||||
void clean_up();
|
void clean_up();
|
||||||
void reactivate_cpus();
|
void reactivate_cpus();
|
||||||
@@ -190,9 +197,8 @@ void proc_cpu_read(char *procinfo);
|
|||||||
unsigned long proc_read_size(char *path);
|
unsigned long proc_read_size(char *path);
|
||||||
char *get_var_rvalue(char *var_name);
|
char *get_var_rvalue(char *var_name);
|
||||||
void cleanup_cmm(void);
|
void cleanup_cmm(void);
|
||||||
int hotplug(int cpuid);
|
int hotplug_one_cpu(void);
|
||||||
int hotunplug(int cpuid);
|
int hotunplug_one_cpu(void);
|
||||||
int is_online(int cpuid);
|
|
||||||
long get_cmmpages_size();
|
long get_cmmpages_size();
|
||||||
void parse_options(int argc, char **argv);
|
void parse_options(int argc, char **argv);
|
||||||
void check_if_started_twice();
|
void check_if_started_twice();
|
||||||
@@ -202,9 +208,9 @@ void reload_daemon(void);
|
|||||||
int daemonize(void);
|
int daemonize(void);
|
||||||
int check_cmmfiles(void);
|
int check_cmmfiles(void);
|
||||||
void check_config();
|
void check_config();
|
||||||
|
void apply_cpu_config(void);
|
||||||
void set_cmm_pages(long size);
|
void set_cmm_pages(long size);
|
||||||
int check_lpar();
|
int check_lpar();
|
||||||
int cpu_is_configured(int cpuid);
|
|
||||||
void setup_history(void);
|
void setup_history(void);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -149,6 +149,8 @@ void clean_up()
|
|||||||
cpuplugd_info("terminated\n");
|
cpuplugd_info("terminated\n");
|
||||||
remove(pid_file);
|
remove(pid_file);
|
||||||
remove(LOCKFILE);
|
remove(LOCKFILE);
|
||||||
|
/* suppress verbose messages on exit */
|
||||||
|
debug = 0;
|
||||||
reactivate_cpus();
|
reactivate_cpus();
|
||||||
if (memory)
|
if (memory)
|
||||||
cleanup_cmm();
|
cleanup_cmm();
|
||||||
@@ -163,6 +165,8 @@ void kill_daemon(int UNUSED(a))
|
|||||||
cpuplugd_info("shutting down\n");
|
cpuplugd_info("shutting down\n");
|
||||||
remove(pid_file);
|
remove(pid_file);
|
||||||
remove(LOCKFILE);
|
remove(LOCKFILE);
|
||||||
|
/* suppress verbose messages on exit */
|
||||||
|
debug = 0;
|
||||||
reactivate_cpus();
|
reactivate_cpus();
|
||||||
if (memory)
|
if (memory)
|
||||||
cleanup_cmm();
|
cleanup_cmm();
|
||||||
|
|||||||
+31
-35
@@ -54,12 +54,12 @@ struct config cfg = {
|
|||||||
.hotunplug = NULL,
|
.hotunplug = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
int num_cpu_start, memory, cpu, reload_pending;
|
|
||||||
long cmm_pagesize_start;
|
|
||||||
unsigned long meminfo_size, vmstat_size, cpustat_size, varinfo_size;
|
|
||||||
char *meminfo, *vmstat, *cpustat, *varinfo;
|
|
||||||
double *timestamps;
|
|
||||||
unsigned int history_max, history_current, history_prev, sym_names_count;
|
unsigned int history_max, history_current, history_prev, sym_names_count;
|
||||||
|
unsigned long meminfo_size, vmstat_size, cpustat_size, varinfo_size;
|
||||||
|
int num_cpu_start, memory, cpu, reload_pending, saved_polarization;
|
||||||
|
char *meminfo, *vmstat, *cpustat, *varinfo;
|
||||||
|
long cmm_pagesize_start;
|
||||||
|
double *timestamps;
|
||||||
|
|
||||||
static struct symbols symbols;
|
static struct symbols symbols;
|
||||||
static jmp_buf jmpenv;
|
static jmp_buf jmpenv;
|
||||||
@@ -77,8 +77,29 @@ static void eval_cpu_rules(void)
|
|||||||
{
|
{
|
||||||
double diffs[CPUSTATS], diffs_total, percent_factor;
|
double diffs[CPUSTATS], diffs_total, percent_factor;
|
||||||
char *procinfo_current, *procinfo_prev;
|
char *procinfo_current, *procinfo_prev;
|
||||||
int cpu, nr_cpus, on_off;
|
int nr_cpus, on_off, polarization;
|
||||||
|
|
||||||
|
polarization = get_polarization();
|
||||||
|
if (polarization < 0) {
|
||||||
|
cpuplugd_debug("couldn't determine system polarization\n");
|
||||||
|
cpuplugd_debug("skipping cpu rule evaluation\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (saved_polarization != polarization) {
|
||||||
|
saved_polarization = polarization;
|
||||||
|
if (polarization == PLR_VERTICAL) {
|
||||||
|
/* revert cpu hotplug adjustments after switching from horizontal */
|
||||||
|
reactivate_cpus();
|
||||||
|
} else if (polarization == PLR_HORIZONTAL) {
|
||||||
|
/* reapply cpu config after switching from vertical */
|
||||||
|
apply_cpu_config();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (polarization == PLR_VERTICAL) {
|
||||||
|
cpuplugd_debug("system is running vertical polarization\n");
|
||||||
|
cpuplugd_debug("cpuplugd won't make cpu adjustments\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
nr_cpus = get_numcpus();
|
nr_cpus = get_numcpus();
|
||||||
procinfo_current = cpustat + history_current * cpustat_size;
|
procinfo_current = cpustat + history_current * cpustat_size;
|
||||||
procinfo_prev = cpustat + history_prev * cpustat_size;
|
procinfo_prev = cpustat + history_prev * cpustat_size;
|
||||||
@@ -157,7 +178,6 @@ static void eval_cpu_rules(void)
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
printf("---------------------------------------------\n");
|
printf("---------------------------------------------\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
on_off = 0;
|
on_off = 0;
|
||||||
/* Evaluate the hotplug rule */
|
/* Evaluate the hotplug rule */
|
||||||
if (eval_term(cfg.hotplug, &symbols))
|
if (eval_term(cfg.hotplug, &symbols))
|
||||||
@@ -172,40 +192,16 @@ static void eval_cpu_rules(void)
|
|||||||
cpuplugd_debug("maximum cpu limit is reached\n");
|
cpuplugd_debug("maximum cpu limit is reached\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* try to find a offline cpu */
|
if (hotplug_one_cpu())
|
||||||
for (cpu = 0; cpu < nr_cpus; cpu++)
|
cpuplugd_debug("unable to find a cpu which can be enabled\n");
|
||||||
if (is_online(cpu) == 0 && cpu_is_configured(cpu) != 0)
|
|
||||||
break;
|
|
||||||
if (cpu < nr_cpus) {
|
|
||||||
cpuplugd_debug("cpu with id %d is currently offline "
|
|
||||||
"and will be enabled\n", cpu);
|
|
||||||
if (hotplug(cpu) == -1)
|
|
||||||
cpuplugd_debug("unable to find a cpu which "
|
|
||||||
"can be enabled\n");
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* In case we tried to enable a cpu but this failed.
|
|
||||||
* This is the case if a cpu is deconfigured
|
|
||||||
*/
|
|
||||||
cpuplugd_debug("unable to find a cpu which can "
|
|
||||||
"be enabled\n");
|
|
||||||
}
|
|
||||||
} else if (on_off < 0) {
|
} else if (on_off < 0) {
|
||||||
/* check cpu nr limit */
|
/* check cpu nr limit */
|
||||||
if (symbols.onumcpus <= cfg.cpu_min) {
|
if (symbols.onumcpus <= cfg.cpu_min) {
|
||||||
cpuplugd_debug("minimum cpu limit is reached\n");
|
cpuplugd_debug("minimum cpu limit is reached\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* try to find a online cpu */
|
if (hotunplug_one_cpu())
|
||||||
for (cpu = get_numcpus() - 1; cpu >= 0; cpu--) {
|
cpuplugd_debug("unable to find a cpu which can be disabled\n");
|
||||||
if (is_online(cpu) != 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (cpu > 0) {
|
|
||||||
cpuplugd_debug("cpu with id %d is currently online "
|
|
||||||
"and will be disabled\n", cpu);
|
|
||||||
hotunplug(cpu);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ of active CPUs are reset to the values they had before the cpuplugd was started.
|
|||||||
This program can be used to control the number of CPUs for Linux on z/VM
|
This program can be used to control the number of CPUs for Linux on z/VM
|
||||||
and for Linux in LPAR mode. The memory hotplug feature (CMM page pool) applies
|
and for Linux in LPAR mode. The memory hotplug feature (CMM page pool) applies
|
||||||
to Linux on z/VM only.
|
to Linux on z/VM only.
|
||||||
|
|
||||||
|
The cpuplugd daemon stops any CPU hot-plug operations when the system switches
|
||||||
|
to vertical polarization, thus avoiding possible performance penalties.
|
||||||
.
|
.
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
@@ -31,11 +31,11 @@
|
|||||||
#
|
#
|
||||||
# Dump on ECKD device (DASD)
|
# Dump on ECKD device (DASD)
|
||||||
#
|
#
|
||||||
#ON_PANIC=dump
|
# ON_PANIC=dump
|
||||||
#DUMP_TYPE=eckd
|
# DUMP_TYPE=eckd
|
||||||
#DEVICE=0.0.1004
|
# DEVICE=0.0.1004
|
||||||
#BOOTPROG=0
|
# BOOTPROG=0
|
||||||
#BR_CHR=auto
|
# BR_CHR=auto
|
||||||
|
|
||||||
#
|
#
|
||||||
# Dump on fcp device (SCSI Disk)
|
# Dump on fcp device (SCSI Disk)
|
||||||
|
|||||||
@@ -93,5 +93,6 @@ SECTIONS
|
|||||||
*(.eh_frame)
|
*(.eh_frame)
|
||||||
*(.interp)
|
*(.interp)
|
||||||
*(.note.GNU-stack)
|
*(.note.GNU-stack)
|
||||||
|
*(.note.package)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,5 +79,6 @@ SECTIONS
|
|||||||
*(.eh_frame)
|
*(.eh_frame)
|
||||||
*(.interp)
|
*(.interp)
|
||||||
*(.note.GNU-stack)
|
*(.note.GNU-stack)
|
||||||
|
*(.note.package)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,5 +15,6 @@ SECTIONS
|
|||||||
*(.eh_frame)
|
*(.eh_frame)
|
||||||
*(.interp)
|
*(.interp)
|
||||||
*(.note.GNU-stack)
|
*(.note.GNU-stack)
|
||||||
|
*(.note.package)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ struct os_info {
|
|||||||
uint8_t reserved[3804];
|
uint8_t reserved[3804];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
STATIC_ASSERT(sizeof(struct os_info) == 4096)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return 0 in case of valid os_info
|
* Return 0 in case of valid os_info
|
||||||
* Return -EOS_INFO_MISSING if os_info address is not page aligned or page is
|
* Return -EOS_INFO_MISSING if os_info address is not page aligned or page is
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ char *path_get_ap_udev(void);
|
|||||||
void vfio_ap_parse_matrix(struct vfio_ap_device *dev, char *matrix);
|
void vfio_ap_parse_matrix(struct vfio_ap_device *dev, char *matrix);
|
||||||
void vfio_ap_sort_matrix_results(struct vfio_ap_device *dev);
|
void vfio_ap_sort_matrix_results(struct vfio_ap_device *dev);
|
||||||
void vfio_ap_parse_control(struct vfio_ap_device *dev, char *control);
|
void vfio_ap_parse_control(struct vfio_ap_device *dev, char *control);
|
||||||
|
bool vfio_ap_need_dynamic_config(struct vfio_ap_device *dev);
|
||||||
|
|
||||||
/* Functions for reading JSON device config */
|
/* Functions for reading JSON device config */
|
||||||
int vfio_ap_read_device_config(const char *path, struct vfio_ap_device *dev);
|
int vfio_ap_read_device_config(const char *path, struct vfio_ap_device *dev);
|
||||||
@@ -87,6 +88,9 @@ bool ap_read_udev_masks(char *path, char *ap, char *aq, bool *read_ap,
|
|||||||
bool *read_aq);
|
bool *read_aq);
|
||||||
void ap_mask_to_list(char *mask, struct util_list *list);
|
void ap_mask_to_list(char *mask, struct util_list *list);
|
||||||
void ap_list_remove_all(struct util_list *list);
|
void ap_list_remove_all(struct util_list *list);
|
||||||
|
char *vfio_ap_device_get_adapter_mask(struct vfio_ap_device *dev, int *size);
|
||||||
|
char *vfio_ap_device_get_domain_mask(struct vfio_ap_device *dev, int *size);
|
||||||
|
char *vfio_ap_device_get_control_mask(struct vfio_ap_device *dev, int *size);
|
||||||
|
|
||||||
/* Lock Functions */
|
/* Lock Functions */
|
||||||
int ap_get_lock(void);
|
int ap_get_lock(void);
|
||||||
|
|||||||
@@ -723,14 +723,14 @@ static void check_exists(const char *path, const char *attr)
|
|||||||
|
|
||||||
snprintf(fpath, sizeof(fpath), "/sys/firmware/%s", path);
|
snprintf(fpath, sizeof(fpath), "/sys/firmware/%s", path);
|
||||||
if (access(fpath, F_OK) != 0)
|
if (access(fpath, F_OK) != 0)
|
||||||
ERR_EXIT("System does not allow to set %s", attr);
|
ERR_EXIT("System does not allow one to set %s", attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_str_optional(char *string, char *file, int exit_on_fail,
|
static void write_str_optional(char *string, char *file, int exit_on_fail,
|
||||||
const char *attr)
|
const char *attr)
|
||||||
{
|
{
|
||||||
if (write_str_errno(string, file) && exit_on_fail)
|
if (write_str_errno(string, file) && exit_on_fail)
|
||||||
ERR_EXIT("System does not allow to set %s", attr);
|
ERR_EXIT("System does not allow one to set %s", attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
prog_name=`basename $0`
|
prog_name=`basename $0`
|
||||||
guest_name=${USER:-`whoami 2>/dev/null`}
|
guest_name=${USER:-`whoami 2>/dev/null`}
|
||||||
terminal=lnxhvc0
|
terminal=lnxhvc0
|
||||||
iucvconn=`which iucvconn 2>/dev/null`
|
iucvconn=`command -v iucvconn 2>/dev/null`
|
||||||
|
|
||||||
__error() {
|
__error() {
|
||||||
printf "$prog_name: $@\n" >&2
|
printf "$prog_name: $@\n" >&2
|
||||||
|
|||||||
+143
-1
@@ -33,6 +33,9 @@
|
|||||||
#include "lib/util_path.h"
|
#include "lib/util_path.h"
|
||||||
#include "lib/util_udev.h"
|
#include "lib/util_udev.h"
|
||||||
|
|
||||||
|
static const char default_mask[AP_MASK_SIZE] =
|
||||||
|
"0x0000000000000000000000000000000000000000000000000000000000000000";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return sysfs path to a bus attribute
|
* Return sysfs path to a bus attribute
|
||||||
* Note: caller is responsible for freeing the returned string
|
* Note: caller is responsible for freeing the returned string
|
||||||
@@ -118,6 +121,37 @@ static void modify_device_attr(struct util_list *list, char *value)
|
|||||||
vfio_ap_node_remove_dupes(list);
|
vfio_ap_node_remove_dupes(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pass a comma-delimited string of masks (adapters,domains,controls) and
|
||||||
|
* for each ON bit in these masks add the associated ID to the device
|
||||||
|
* lists.
|
||||||
|
*/
|
||||||
|
static void modify_device_ap_config(struct vfio_ap_device *dev,
|
||||||
|
char *value)
|
||||||
|
{
|
||||||
|
char *mask, *adapters, *domains, *controls;
|
||||||
|
|
||||||
|
mask = util_strdup(value);
|
||||||
|
|
||||||
|
adapters = strtok(mask, ",");
|
||||||
|
domains = strtok(NULL, ",");
|
||||||
|
controls = strtok(NULL, ",");
|
||||||
|
util_assert((!strtok(NULL, ",")) && adapters && domains && controls,
|
||||||
|
"Invalid ap_config attribute encountered %s", value);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ap_config overwrites the current list of adapters, domains and
|
||||||
|
* control domains. Clear the current lists before generating new ones
|
||||||
|
* based upon the input mask values.
|
||||||
|
*/
|
||||||
|
ap_list_remove_all(dev->adapters);
|
||||||
|
ap_list_remove_all(dev->domains);
|
||||||
|
ap_list_remove_all(dev->controls);
|
||||||
|
ap_mask_to_list(adapters, dev->adapters);
|
||||||
|
ap_mask_to_list(domains, dev->domains);
|
||||||
|
ap_mask_to_list(controls, dev->controls);
|
||||||
|
}
|
||||||
|
|
||||||
static void load_attr_to_device(struct vfio_ap_device *dev, char *attr,
|
static void load_attr_to_device(struct vfio_ap_device *dev, char *attr,
|
||||||
const char *value)
|
const char *value)
|
||||||
{
|
{
|
||||||
@@ -129,6 +163,8 @@ static void load_attr_to_device(struct vfio_ap_device *dev, char *attr,
|
|||||||
modify_device_attr(dev->domains, v);
|
modify_device_attr(dev->domains, v);
|
||||||
else if (strcmp(attr, "assign_control_domain") == 0)
|
else if (strcmp(attr, "assign_control_domain") == 0)
|
||||||
modify_device_attr(dev->controls, v);
|
modify_device_attr(dev->controls, v);
|
||||||
|
else if (strcmp(attr, "ap_config") == 0)
|
||||||
|
modify_device_ap_config(dev, v);
|
||||||
|
|
||||||
free(v);
|
free(v);
|
||||||
}
|
}
|
||||||
@@ -416,6 +452,28 @@ void vfio_ap_parse_control(struct vfio_ap_device *dev, char *control)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the specified device is currently active. If so, see if
|
||||||
|
* it is enabled for dynamic configuration support.
|
||||||
|
*
|
||||||
|
* @param[in] dev Vfio-ap struct
|
||||||
|
*
|
||||||
|
* @retval True Device is active and enabled for dynamic config
|
||||||
|
* @retval False Device is not active OR no dynamic config support
|
||||||
|
*/
|
||||||
|
bool vfio_ap_need_dynamic_config(struct vfio_ap_device *dev)
|
||||||
|
{
|
||||||
|
char *attr = path_get_vfio_ap_attr(dev->uuid, "ap_config");
|
||||||
|
|
||||||
|
if (!attr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!util_path_is_readable(attr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_JSONC
|
#ifdef HAVE_JSONC
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -692,7 +750,7 @@ void ap_mask_to_list(char *mask, struct util_list *list)
|
|||||||
*/
|
*/
|
||||||
void ap_list_remove_all(struct util_list *list)
|
void ap_list_remove_all(struct util_list *list)
|
||||||
{
|
{
|
||||||
struct ap_node *node;
|
struct vfio_ap_node *node;
|
||||||
|
|
||||||
while (!util_list_is_empty(list)) {
|
while (!util_list_is_empty(list)) {
|
||||||
node = util_list_start(list);
|
node = util_list_start(list);
|
||||||
@@ -715,6 +773,90 @@ static unsigned int random_delay(void)
|
|||||||
return AP_LOCK_DELAY_US + (rand() % AP_LOCK_VARIANCE_US);
|
return AP_LOCK_DELAY_US + (rand() % AP_LOCK_VARIANCE_US);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a mask of assigned adapters for the specified vfio_ap device.
|
||||||
|
* Note: caller is responsible for freeing the returned string
|
||||||
|
*
|
||||||
|
* @param[in] dev Vfio-ap struct to get adapter mask from
|
||||||
|
* @param[in, out] size Size of mask buffer returned
|
||||||
|
*
|
||||||
|
* @retval != 0 Adapter mask (hex string)
|
||||||
|
* @retval 0 Failed to generate a mask
|
||||||
|
*/
|
||||||
|
char *vfio_ap_device_get_adapter_mask(struct vfio_ap_device *dev, int *size)
|
||||||
|
{
|
||||||
|
struct vfio_ap_node *node;
|
||||||
|
char *mask;
|
||||||
|
|
||||||
|
if (!dev || !size)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
mask = util_strdup(default_mask);
|
||||||
|
*size = AP_MASK_SIZE;
|
||||||
|
|
||||||
|
util_list_iterate(dev->adapters, node) {
|
||||||
|
ap_set_bit(node->id, mask, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a mask of assigned domains for the specified vfio_ap device.
|
||||||
|
* Note: caller is responsible for freeing the returned string
|
||||||
|
*
|
||||||
|
* @param[in] dev Vfio-ap struct to get domain mask from
|
||||||
|
* @param[in, out] size Size of mask buffer returned
|
||||||
|
*
|
||||||
|
* @retval != 0 Domain mask (hex string)
|
||||||
|
* @retval 0 Failed to generate a mask
|
||||||
|
*/
|
||||||
|
char *vfio_ap_device_get_domain_mask(struct vfio_ap_device *dev, int *size)
|
||||||
|
{
|
||||||
|
struct vfio_ap_node *node;
|
||||||
|
char *mask;
|
||||||
|
|
||||||
|
if (!dev || !size)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
mask = util_strdup(default_mask);
|
||||||
|
*size = AP_MASK_SIZE;
|
||||||
|
|
||||||
|
util_list_iterate(dev->domains, node) {
|
||||||
|
ap_set_bit(node->id, mask, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a mask of assigned control domains for the specified vfio_ap device.
|
||||||
|
* Note: caller is responsible for freeing the returned string
|
||||||
|
*
|
||||||
|
* @param[in] dev Vfio-ap struct to get control domain mask from
|
||||||
|
* @param[in, out] size Size of mask buffer returned
|
||||||
|
*
|
||||||
|
* @retval != 0 Control domain mask (hex string)
|
||||||
|
* @retval 0 Failed to generate a mask
|
||||||
|
*/
|
||||||
|
char *vfio_ap_device_get_control_mask(struct vfio_ap_device *dev, int *size)
|
||||||
|
{
|
||||||
|
struct vfio_ap_node *node;
|
||||||
|
char *mask;
|
||||||
|
|
||||||
|
if (!dev || !size)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
mask = util_strdup(default_mask);
|
||||||
|
*size = AP_MASK_SIZE;
|
||||||
|
|
||||||
|
util_list_iterate(dev->controls, node) {
|
||||||
|
ap_set_bit(node->id, mask, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Acquire the ap config lock using this Process ID
|
* Acquire the ap config lock using this Process ID
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1084,8 +1084,6 @@ int kmip_connection_new(const struct kmip_conn_config *config,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
kmip_debug(debug, "Invalid encoding: %d", config->encoding);
|
kmip_debug(debug, "Invalid encoding: %d", config->encoding);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|||||||
+2
-2
@@ -89,7 +89,7 @@ int kmip_decode_xml(const xmlNode *xml, struct kmip_node *parent,
|
|||||||
} else {
|
} else {
|
||||||
n->type = kmip_type_by_name_or_hex(type_attr);
|
n->type = kmip_type_by_name_or_hex(type_attr);
|
||||||
if (n->type == 0) {
|
if (n->type == 0) {
|
||||||
kmip_debug(debug, "Unknown 'type' in JSON object: '%s'",
|
kmip_debug(debug, "Unknown 'type' in XML object: '%s'",
|
||||||
type_attr);
|
type_attr);
|
||||||
rc = -EBADMSG;
|
rc = -EBADMSG;
|
||||||
goto out;
|
goto out;
|
||||||
@@ -361,7 +361,7 @@ int kmip_encode_xml(const struct kmip_node *node, xmlNode **xml, bool debug)
|
|||||||
while (element != NULL) {
|
while (element != NULL) {
|
||||||
rc = kmip_encode_xml(element, &elem_xml, debug);
|
rc = kmip_encode_xml(element, &elem_xml, debug);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
kmip_debug(debug, "kmip_encode_json failed");
|
kmip_debug(debug, "kmip_encode_xml failed");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (xmlAddChild(ret_xml, elem_xml) == NULL) {
|
if (xmlAddChild(ret_xml, elem_xml) == NULL) {
|
||||||
|
|||||||
+9
-1
@@ -710,6 +710,14 @@ static void csv_map(struct obj_t *UNUSED(obj), unsigned int mflags,
|
|||||||
free(qval);
|
free(qval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool hide_meta_env(void)
|
||||||
|
{
|
||||||
|
char *v;
|
||||||
|
|
||||||
|
v = secure_getenv("FMT_NOMETA");
|
||||||
|
return (v && strcmp(v, "1") == 0);
|
||||||
|
}
|
||||||
|
|
||||||
void util_fmt_init(FILE *fd, enum util_fmt_t type, unsigned int flags,
|
void util_fmt_init(FILE *fd, enum util_fmt_t type, unsigned int flags,
|
||||||
int api_level)
|
int api_level)
|
||||||
{
|
{
|
||||||
@@ -719,7 +727,7 @@ void util_fmt_init(FILE *fd, enum util_fmt_t type, unsigned int flags,
|
|||||||
f.fileno = fileno(fd);
|
f.fileno = fileno(fd);
|
||||||
f.hide_prefix = (flags & FMT_NOPREFIX);
|
f.hide_prefix = (flags & FMT_NOPREFIX);
|
||||||
f.hide_inval = !(flags & FMT_KEEPINVAL);
|
f.hide_inval = !(flags & FMT_KEEPINVAL);
|
||||||
f.hide_meta = (flags & FMT_NOMETA);
|
f.hide_meta = (flags & FMT_NOMETA) || hide_meta_env();
|
||||||
f.quote_all = (flags & FMT_QUOTEALL);
|
f.quote_all = (flags & FMT_QUOTEALL);
|
||||||
f.do_filter = (flags & FMT_FILTER);
|
f.do_filter = (flags & FMT_FILTER);
|
||||||
f.do_warn = (flags & FMT_WARN);
|
f.do_warn = (flags & FMT_WARN);
|
||||||
|
|||||||
@@ -80,6 +80,10 @@ Cylinder, Head and Record) or "auto".
|
|||||||
\fB - BR_LBA:\fR
|
\fB - BR_LBA:\fR
|
||||||
Boot record logical block address.
|
Boot record logical block address.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB - SCP_DATA:\fR
|
||||||
|
SCP data for SCSI, NVMe and ECKD dump devices.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB - VMCMD_1, VMCMD_2 ... VMCMD_8:\fR
|
\fB - VMCMD_1, VMCMD_2 ... VMCMD_8:\fR
|
||||||
Up to eight CP commands, which are executed in case of a kernel panic
|
Up to eight CP commands, which are executed in case of a kernel panic
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ echo "$cmd: Copying kexec"
|
|||||||
# Install both binary and required shared libraries
|
# Install both binary and required shared libraries
|
||||||
OLDPATH=$PATH
|
OLDPATH=$PATH
|
||||||
PATH=$OLDPATH:/sbin:/usr/sbin
|
PATH=$OLDPATH:/sbin:/usr/sbin
|
||||||
kexec_bin=$(which kexec)
|
kexec_bin=$(command -v kexec)
|
||||||
kexec_sos=$(sharedobjs $kexec_bin)
|
kexec_sos=$(sharedobjs $kexec_bin)
|
||||||
PATH=$OLDPATH
|
PATH=$OLDPATH
|
||||||
|
|
||||||
|
|||||||
@@ -119,9 +119,9 @@ dobuild()
|
|||||||
# append ramdisk if specified
|
# append ramdisk if specified
|
||||||
if [ "$ramdisk" != "" ]
|
if [ "$ramdisk" != "" ]
|
||||||
then
|
then
|
||||||
ramdisk_size=$(du -b $ramdisk | cut -f1)
|
ramdisk_size=$(du -b -L $ramdisk | cut -f1)
|
||||||
kernel_size=$(du -b $kernel | cut -f1)
|
kernel_size=$(du -b -L $kernel | cut -f1)
|
||||||
ramdisk_offset=$(du -b $image | cut -f1)
|
ramdisk_offset=$(du -b -L $image | cut -f1)
|
||||||
cat $ramdisk >> $image
|
cat $ramdisk >> $image
|
||||||
binval=$(mktemp)
|
binval=$(mktemp)
|
||||||
dec2be64 $ramdisk_offset > $binval
|
dec2be64 $ramdisk_offset > $binval
|
||||||
@@ -135,7 +135,7 @@ dobuild()
|
|||||||
# set cmdline
|
# set cmdline
|
||||||
if [ "$parmfile" != "" ]
|
if [ "$parmfile" != "" ]
|
||||||
then
|
then
|
||||||
parmfile_size=$(du -b $parmfile | cut -f1)
|
parmfile_size=$(du -b -L $parmfile | cut -f1)
|
||||||
if [ $parmfile_size -le $MAX_PARMFILE_SIZE ]
|
if [ $parmfile_size -le $MAX_PARMFILE_SIZE ]
|
||||||
then
|
then
|
||||||
# Clear any previous parameters
|
# Clear any previous parameters
|
||||||
|
|||||||
+12
-1
@@ -19,7 +19,13 @@ ifneq (${HAVE_CARGO},0)
|
|||||||
|
|
||||||
ifneq (${HAVE_OPENSSL},0)
|
ifneq (${HAVE_OPENSSL},0)
|
||||||
ifneq (${HAVE_LIBCURL},0)
|
ifneq (${HAVE_LIBCURL},0)
|
||||||
PV_TARGETS := pvsecret pvapconfig pvattest
|
PV_TARGETS := pvsecret pvattest
|
||||||
|
|
||||||
|
ifeq ($(HOST_ARCH),s390x)
|
||||||
|
PV_TARGETS += pvapconfig
|
||||||
|
else
|
||||||
|
BUILD_TARGETS += skip-pvapconfig
|
||||||
|
endif #HOSTARCH
|
||||||
|
|
||||||
PV_BUILD_TARGETS := $(PV_TARGETS)
|
PV_BUILD_TARGETS := $(PV_TARGETS)
|
||||||
CARGO_TEST_TARGETS += $(addsuffix .test,pv $(PV_TARGETS))
|
CARGO_TEST_TARGETS += $(addsuffix .test,pv $(PV_TARGETS))
|
||||||
@@ -56,6 +62,9 @@ skip-build:
|
|||||||
skip-pv-build:
|
skip-pv-build:
|
||||||
echo " SKIP rust-pv-tools due to unresolved dependencies"
|
echo " SKIP rust-pv-tools due to unresolved dependencies"
|
||||||
|
|
||||||
|
skip-pvapconfig:
|
||||||
|
echo " SKIP pvapconfig due to unsupported architecture (s390x only)"
|
||||||
|
|
||||||
all: $(BUILD_TARGETS)
|
all: $(BUILD_TARGETS)
|
||||||
install: $(INSTALL_TARGETS)
|
install: $(INSTALL_TARGETS)
|
||||||
$(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR)
|
$(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR)
|
||||||
@@ -65,7 +74,9 @@ print-rust-targets:
|
|||||||
echo $(BUILD_TARGETS)
|
echo $(BUILD_TARGETS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
ifneq (${HAVE_CARGO},0)
|
||||||
$(CARGO_CLEAN) ${ALL_CARGOFLAGS}
|
$(CARGO_CLEAN) ${ALL_CARGOFLAGS}
|
||||||
|
endif # CARGO
|
||||||
$(RM) -- .check-dep-pvtools .detect-openssl.dep.c .check-cargo
|
$(RM) -- .check-dep-pvtools .detect-openssl.dep.c .check-cargo
|
||||||
|
|
||||||
rust-test: $(CARGO_TEST_TARGETS)
|
rust-test: $(CARGO_TEST_TARGETS)
|
||||||
|
|||||||
+2
-2
@@ -2,8 +2,8 @@
|
|||||||
//
|
//
|
||||||
// Copyright IBM Corp. 2023, 2024
|
// Copyright IBM Corp. 2023, 2024
|
||||||
|
|
||||||
#![deny(
|
#![deny(missing_docs)]
|
||||||
missing_docs,
|
#![warn(
|
||||||
missing_debug_implementations,
|
missing_debug_implementations,
|
||||||
trivial_numeric_casts,
|
trivial_numeric_casts,
|
||||||
unstable_features,
|
unstable_features,
|
||||||
|
|||||||
@@ -302,8 +302,8 @@ pub fn x509_dist_points(cert: &X509Ref) -> Vec<String> {
|
|||||||
/// Searches for CRL Distribution points and downloads the CRL. Stops after the first successful
|
/// Searches for CRL Distribution points and downloads the CRL. Stops after the first successful
|
||||||
/// download.
|
/// download.
|
||||||
///
|
///
|
||||||
/// Error if something bad(=unexpected) happens (not bad: CRL not available at link, unexpected
|
/// Error if something bad(=unexpected) happens
|
||||||
/// format) Other issues are mapped to Ok(None)
|
/// CRL not available at all URIs and unexpected format at all URIs are mapped to Ok(None)
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
pub fn download_first_crl_from_x509(cert: &X509Ref) -> Result<Option<Vec<openssl::x509::X509Crl>>> {
|
pub fn download_first_crl_from_x509(cert: &X509Ref) -> Result<Option<Vec<openssl::x509::X509Crl>>> {
|
||||||
use crate::utils::read_crls;
|
use crate::utils::read_crls;
|
||||||
@@ -333,6 +333,7 @@ pub fn download_first_crl_from_x509(cert: &X509Ref) -> Result<Option<Vec<openssl
|
|||||||
}
|
}
|
||||||
match read_crls(&handle.get_ref().0) {
|
match read_crls(&handle.get_ref().0) {
|
||||||
Err(_) => continue,
|
Err(_) => continue,
|
||||||
|
Ok(crl) if crl.is_empty() => continue,
|
||||||
Ok(crl) => return Ok(Some(crl)),
|
Ok(crl) => return Ok(Some(crl)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
//
|
//
|
||||||
// Copyright IBM Corp. 2023, 2024
|
// Copyright IBM Corp. 2023, 2024
|
||||||
#![deny(
|
#![deny(missing_docs)]
|
||||||
missing_docs,
|
#![warn(
|
||||||
missing_debug_implementations,
|
missing_debug_implementations,
|
||||||
trivial_numeric_casts,
|
trivial_numeric_casts,
|
||||||
unstable_features,
|
unstable_features,
|
||||||
|
|||||||
@@ -72,9 +72,9 @@ fn rc_fmt<C: UvCmd>(rc: u16, rrc: u16, cmd: &mut C) -> &'static str {
|
|||||||
(0x0000, _) => Some("invalid rc"),
|
(0x0000, _) => Some("invalid rc"),
|
||||||
(0x0002, _) => Some("invalid UV command"),
|
(0x0002, _) => Some("invalid UV command"),
|
||||||
(0x0005, _) => Some("request has an invalid size"),
|
(0x0005, _) => Some("request has an invalid size"),
|
||||||
(0x0030, _) => Some("home address space control bit has R-bit set to one"),
|
(0x0030, _) => Some("home address space control bit has R-bit set to one. This may be due to a corrupted host or a guest kernel bug. STOP using this guest"),
|
||||||
(0x0031, _) => Some("access exception"),
|
(0x0031, _) => Some("adress translation exception. This may be due to a corrupted host or a guest kernel bug. STOP using this guest"),
|
||||||
(0x0032, _) => Some("request contains virtual address translating to an invalid address"),
|
(0x0032, _) => Some("request contains virtual address translating to an invalid address. This may be due to a corrupted host or a guest kernel bug. STOP using this guest"),
|
||||||
(UvDevice::RC_MORE_DATA, _) => unreachable!("This is no Error!!!!"),
|
(UvDevice::RC_MORE_DATA, _) => unreachable!("This is no Error!!!!"),
|
||||||
(UvDevice::RC_SUCCESS, _) => unreachable!("This is no Error!!!!"),
|
(UvDevice::RC_SUCCESS, _) => unreachable!("This is no Error!!!!"),
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
//
|
//
|
||||||
// Copyright IBM Corp. 2023
|
// Copyright IBM Corp. 2023
|
||||||
|
|
||||||
|
use std::mem::size_of;
|
||||||
|
|
||||||
use crate::{assert_size, static_assert};
|
use crate::{assert_size, static_assert};
|
||||||
use zerocopy::{AsBytes, FromBytes, FromZeroes};
|
use zerocopy::{AsBytes, FromBytes, FromZeroes};
|
||||||
|
|
||||||
@@ -103,7 +105,7 @@ assert_size!(uvio_attest, 0x138);
|
|||||||
|
|
||||||
/// corresponds to the UV_IOCTL macro
|
/// corresponds to the UV_IOCTL macro
|
||||||
pub(crate) const fn uv_ioctl(nr: u8) -> u64 {
|
pub(crate) const fn uv_ioctl(nr: u8) -> u64 {
|
||||||
iowr(UVIO_TYPE_UVC, nr, std::mem::size_of::<uvio_ioctl_cb>())
|
iowr(UVIO_TYPE_UVC, nr, size_of::<uvio_ioctl_cb>())
|
||||||
}
|
}
|
||||||
static_assert!(uv_ioctl(UVIO_IOCTL_ATT_NR) == 0xc0407501);
|
static_assert!(uv_ioctl(UVIO_IOCTL_ATT_NR) == 0xc0407501);
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
ffi::{c_int, c_ulong},
|
ffi::{c_int, c_ulong},
|
||||||
os::unix::prelude::FromRawFd,
|
|
||||||
sync::{Mutex, MutexGuard},
|
sync::{Mutex, MutexGuard},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -65,13 +64,12 @@ impl IoctlCtx {
|
|||||||
pub mod mock_libc {
|
pub mod mock_libc {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub unsafe fn ioctl(fd: c_int, cmd: c_ulong, data: *mut ffi::uvio_ioctl_cb) -> c_int {
|
pub unsafe fn ioctl(_fd: c_int, cmd: c_ulong, data: *mut ffi::uvio_ioctl_cb) -> c_int {
|
||||||
let mut ctx = get_lock(&IOCTL_MTX);
|
let mut ctx = get_lock(&IOCTL_MTX);
|
||||||
assert!(!ctx.called, "IOCTL called more than once");
|
assert!(!ctx.called, "IOCTL called more than once");
|
||||||
ctx.called = true;
|
ctx.called = true;
|
||||||
|
|
||||||
assert_eq!(cmd, ctx.exp_cmd, "IOCTL cmd mismatch");
|
assert_eq!(cmd, ctx.exp_cmd, "IOCTL cmd mismatch");
|
||||||
assert_eq!(fd, 17, "IOCTL fd mismatch");
|
|
||||||
|
|
||||||
let data_ref: &mut ffi::uvio_ioctl_cb = &mut *data;
|
let data_ref: &mut ffi::uvio_ioctl_cb = &mut *data;
|
||||||
|
|
||||||
@@ -131,10 +129,10 @@ impl UvCmd for TestCmd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl UvDevice {
|
impl UvDevice {
|
||||||
/// use some random fd for `uvdevice` its OK, as the ioctl is mocked and never touches the
|
/// Use this file as backing file for `uvdevice`. This is OK, as the ioctl is mocked and never touches the
|
||||||
/// passed file
|
/// passed file
|
||||||
fn test_dev() -> Self {
|
fn test_dev() -> Self {
|
||||||
UvDevice(unsafe { File::from_raw_fd(17) })
|
Self(File::open(".").unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ pub struct ApqnInfoEp11 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct ApqnInfoCca {
|
pub struct ApqnInfoCca {
|
||||||
pub serialnr: String,
|
pub serialnr: String,
|
||||||
pub mkvp_aes: String, // may be an empty string if no MK set
|
pub mkvp_aes: String, // may be an empty string if no MK set
|
||||||
@@ -129,6 +130,7 @@ pub struct ApqnInfoCca {
|
|||||||
pub enum ApqnInfo {
|
pub enum ApqnInfo {
|
||||||
Accel(ApqnInfoAccel),
|
Accel(ApqnInfoAccel),
|
||||||
Ep11(ApqnInfoEp11),
|
Ep11(ApqnInfoEp11),
|
||||||
|
#[allow(dead_code)]
|
||||||
Cca(ApqnInfoCca),
|
Cca(ApqnInfoCca),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,6 +264,7 @@ impl ApqnInfo {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Apqn {
|
pub struct Apqn {
|
||||||
|
#[allow(dead_code)]
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub card: u32,
|
pub card: u32,
|
||||||
pub domain: u32,
|
pub domain: u32,
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ Write the generated request to FILE.
|
|||||||
.RE
|
.RE
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
\-\-arpk <FILE>
|
\-a, \-\-arpk <FILE>
|
||||||
.RS 4
|
.RS 4
|
||||||
Save the protection key as unencrypted GCM-AES256 key in FILE Do not publish
|
Save the protection key as unencrypted GCM-AES256 key in FILE Do not publish
|
||||||
this key, otherwise your attestation is compromised.
|
this key, otherwise your attestation is compromised.
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ must start at a page boundary.
|
|||||||
.RE
|
.RE
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
\-\-arpk <FILE>
|
\-a, \-\-arpk <FILE>
|
||||||
.RS 4
|
.RS 4
|
||||||
Use FILE as the protection key to decrypt the request Do not publish this key,
|
Use FILE as the protection key to decrypt the request Do not publish this key,
|
||||||
otherwise your attestation is compromised. Delete this key after verification.
|
otherwise your attestation is compromised. Delete this key after verification.
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ pub struct CreateAttOpt {
|
|||||||
/// Save the protection key as unencrypted GCM-AES256 key in FILE
|
/// Save the protection key as unencrypted GCM-AES256 key in FILE
|
||||||
///
|
///
|
||||||
/// Do not publish this key, otherwise your attestation is compromised.
|
/// Do not publish this key, otherwise your attestation is compromised.
|
||||||
#[arg(long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
|
#[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
|
||||||
pub arpk: String,
|
pub arpk: String,
|
||||||
|
|
||||||
/// Specify-additional data for the request.
|
/// Specify-additional data for the request.
|
||||||
@@ -222,7 +222,7 @@ pub struct VerifyOpt {
|
|||||||
///
|
///
|
||||||
/// Do not publish this key, otherwise your attestation is compromised.
|
/// Do not publish this key, otherwise your attestation is compromised.
|
||||||
/// Delete this key after verification.
|
/// Delete this key after verification.
|
||||||
#[arg(long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
|
#[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
|
||||||
pub arpk: String,
|
pub arpk: String,
|
||||||
|
|
||||||
/// Define the output format.
|
/// Define the output format.
|
||||||
|
|||||||
+25
-1
@@ -259,6 +259,7 @@ readonly LOGFILE="${WORKPATH}dbginfo.log"
|
|||||||
readonly OUTPUT_FILE_BRIDGE="${WORKPATH}network.out"
|
readonly OUTPUT_FILE_BRIDGE="${WORKPATH}network.out"
|
||||||
readonly OUTPUT_FILE_CMD="${WORKPATH}runtime.out"
|
readonly OUTPUT_FILE_CMD="${WORKPATH}runtime.out"
|
||||||
readonly OUTPUT_FILE_COREDUMPCTL="${WORKPATH}coredump.out" # separate file needed
|
readonly OUTPUT_FILE_COREDUMPCTL="${WORKPATH}coredump.out" # separate file needed
|
||||||
|
readonly OUTPUT_FILE_DASD="${WORKPATH}dasd.out"
|
||||||
readonly OUTPUT_FILE_DOCKER="${WORKPATH}docker_runtime.out"
|
readonly OUTPUT_FILE_DOCKER="${WORKPATH}docker_runtime.out"
|
||||||
readonly OUTPUT_FILE_ETHTOOL="${WORKPATH}network.out"
|
readonly OUTPUT_FILE_ETHTOOL="${WORKPATH}network.out"
|
||||||
readonly OUTPUT_FILE_HYPTOP="${WORKPATH}runtime.out"
|
readonly OUTPUT_FILE_HYPTOP="${WORKPATH}runtime.out"
|
||||||
@@ -296,6 +297,7 @@ ALL_STEPS="\
|
|||||||
collect_kvm\
|
collect_kvm\
|
||||||
collect_container\
|
collect_container\
|
||||||
collect_nvme\
|
collect_nvme\
|
||||||
|
collect_dasd\
|
||||||
collect_logfiles\
|
collect_logfiles\
|
||||||
post_processing\
|
post_processing\
|
||||||
create_package\
|
create_package\
|
||||||
@@ -326,6 +328,8 @@ PROCFILES="\
|
|||||||
/proc/mounts\
|
/proc/mounts\
|
||||||
/proc/net/vlan\
|
/proc/net/vlan\
|
||||||
/proc/net/bonding\
|
/proc/net/bonding\
|
||||||
|
/proc/net/sockstat\
|
||||||
|
/proc/net/sockstat6\
|
||||||
/proc/net/softnet_stat\
|
/proc/net/softnet_stat\
|
||||||
/proc/partitions\
|
/proc/partitions\
|
||||||
/proc/qeth\
|
/proc/qeth\
|
||||||
@@ -491,7 +495,7 @@ CMDS="uname -a\
|
|||||||
# Z device subsystem commands (first commands in non alphabetical order)
|
# Z device subsystem commands (first commands in non alphabetical order)
|
||||||
CMDS="${CMDS}\
|
CMDS="${CMDS}\
|
||||||
:lschp\
|
:lschp\
|
||||||
:lscss\
|
:lscss --vpm\
|
||||||
:lszdev\
|
:lszdev\
|
||||||
:find /dev -print0 | sort -z | xargs -0 -n 10 ls -ld\
|
:find /dev -print0 | sort -z | xargs -0 -n 10 ls -ld\
|
||||||
:lspci -t\
|
:lspci -t\
|
||||||
@@ -1233,6 +1237,26 @@ collect_nvme() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
########################################
|
||||||
|
collect_dasd() {
|
||||||
|
local device
|
||||||
|
|
||||||
|
if type dasdview >/dev/null; then
|
||||||
|
pr_collect_output "DASD storage"
|
||||||
|
call_run_command "lsdasd" "${OUTPUT_FILE_DASD}" # duplicate as file header
|
||||||
|
for device in /dev/dasd*; do
|
||||||
|
if [ -b $device ]; then
|
||||||
|
call_run_command "dasdview -i $device" "${OUTPUT_FILE_DASD}"
|
||||||
|
call_run_command "dasdview -t info $device" "${OUTPUT_FILE_DASD}"
|
||||||
|
else
|
||||||
|
echo "$device is no block device" >> ${OUTPUT_FILE_DASD}
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
pr_skip "dasdview: not available"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
collect_kvm() {
|
collect_kvm() {
|
||||||
local cmd
|
local cmd
|
||||||
|
|||||||
+26
-24
@@ -1,4 +1,4 @@
|
|||||||
.TH DBGINFO.SH 8 "01 2024" "s390-tools"
|
.TH DBGINFO.SH 8 "07 2024" "s390-tools"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
dbginfo.sh \- collect runtime, configuration and trace information
|
dbginfo.sh \- collect runtime, configuration and trace information
|
||||||
@@ -65,57 +65,59 @@ Hardware platform = s390x
|
|||||||
.br
|
.br
|
||||||
Runtime environment = z/VM - DPM: NO
|
Runtime environment = z/VM - DPM: NO
|
||||||
.br
|
.br
|
||||||
Kernel version = 5.14.0 (5.14.0-162.6.1.el9_1.s390x)
|
Kernel version = 5.14.0 (5.14.0-427.13.1.el9_4.s390x)
|
||||||
.br
|
.br
|
||||||
OS version / distro = Red Hat Enterprise Linux 9.1 (Plow)
|
OS version / distro = Red Hat Enterprise Linux 9.4 (Plow)
|
||||||
.br
|
.br
|
||||||
Date and time of info = 2023-12-22-11-43-08
|
Date and time of info = 2024-07-11-11-11-11
|
||||||
.PP
|
.PP
|
||||||
1 of 19: Collecting sysfs
|
1 of 20: Collecting sysfs
|
||||||
.PP
|
.PP
|
||||||
2 of 19: Collecting procfs
|
2 of 20: Collecting procfs
|
||||||
.PP
|
.PP
|
||||||
3 of 19: Collecting config files
|
3 of 20: Collecting config files
|
||||||
.PP
|
.PP
|
||||||
4 of 19: Collecting initrd config files
|
4 of 20: Collecting initrd config files
|
||||||
.PP
|
.PP
|
||||||
5 of 19: Collecting command output
|
5 of 20: Collecting command output
|
||||||
.PP
|
.PP
|
||||||
6 of 19: Collecting hyptop for z/VM - 5s output
|
6 of 20: Collecting hyptop for z/VM - 5s output
|
||||||
.PP
|
.PP
|
||||||
7 of 19: Collecting z/VM output
|
7 of 20: Collecting z/VM output
|
||||||
.PP
|
.PP
|
||||||
8 of 19: Collecting network output
|
8 of 20: Collecting network output
|
||||||
.PP
|
.PP
|
||||||
9 of 19: Collecting osa oat output
|
9 of 20: Collecting osa oat output
|
||||||
.PP
|
.PP
|
||||||
10 of 19: Collecting ethtool output
|
10 of 20: Collecting ethtool output
|
||||||
.PP
|
.PP
|
||||||
11 of 19: Collecting Trafic Control output
|
11 of 20: Collecting Trafic Control output
|
||||||
.PP
|
.PP
|
||||||
12 of 19: Collecting bridge output
|
12 of 20: Collecting bridge output
|
||||||
.PP
|
.PP
|
||||||
13 of 19: Skip OpenVSwitch: ovs-vsctl not available
|
13 of 20: Skip OpenVSwitch: ovs-vsctl not available
|
||||||
.PP
|
.PP
|
||||||
14 of 19: Skip KVM: no virsh command
|
14 of 20: Skip KVM: no virsh command
|
||||||
.PP
|
.PP
|
||||||
15 of 19: Collecting container host output
|
15 of 20: Collecting container host output
|
||||||
.PP
|
.PP
|
||||||
Kubernetes ...
|
Kubernetes ...
|
||||||
.br
|
.br
|
||||||
16 of 19: Collecting NVME storage output
|
16 of 20: Collecting NVME storage output
|
||||||
.PP
|
.PP
|
||||||
17 of 19: Collecting log files
|
17 of 20: Collecting DASD storage output
|
||||||
|
.PP
|
||||||
|
18 of 20: Collecting log files
|
||||||
.PP
|
.PP
|
||||||
0 logfiles over 50 MB
|
0 logfiles over 50 MB
|
||||||
.PP
|
.PP
|
||||||
18 of 19: Postprocessing
|
19 of 20: Postprocessing
|
||||||
.PP
|
.PP
|
||||||
19 of 19: Finalizing: Creating archive with collected data
|
20 of 20: Finalizing: Creating archive with collected data
|
||||||
.PP
|
.PP
|
||||||
Collected data was saved to:
|
Collected data was saved to:
|
||||||
.br
|
.br
|
||||||
>> /data\-collection/DBGINFO\-2023\-12\-22\-11\-43\-08\-host\-012345.tgz <<
|
>> /data\-collection/DBGINFO\-2024\-07\-11\-11\-11\-11\-host\-012345.tgz <<
|
||||||
.br
|
.br
|
||||||
Please review all collected data before sending to your service organization.
|
Please review all collected data before sending to your service organization.
|
||||||
.SH HINTS
|
.SH HINTS
|
||||||
|
|||||||
+39
-5
@@ -50,7 +50,7 @@ check_environment()
|
|||||||
|
|
||||||
if [ "$(cat /proc/filesystems|grep sysfs)" = "" ]; then
|
if [ "$(cat /proc/filesystems|grep sysfs)" = "" ]; then
|
||||||
pr_error "no sysfs found"
|
pr_error "no sysfs found"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
SYSFSDIR=$(cat /proc/mounts|awk '$3=="sysfs"{print $2; exit}')
|
SYSFSDIR=$(cat /proc/mounts|awk '$3=="sysfs"{print $2; exit}')
|
||||||
@@ -184,7 +184,8 @@ verify_ccw_dump_device()
|
|||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
# Helper function to check a device string.
|
# Helper function to check a device string.
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
function CheckDeviceString() {
|
check_device_string()
|
||||||
|
{
|
||||||
local X
|
local X
|
||||||
|
|
||||||
X=$(
|
X=$(
|
||||||
@@ -222,7 +223,7 @@ function CheckDeviceString() {
|
|||||||
|
|
||||||
setup_ccw_device()
|
setup_ccw_device()
|
||||||
{
|
{
|
||||||
DEV="$(CheckDeviceString $DEVICE)"
|
DEV="$(check_device_string $DEVICE)"
|
||||||
if [ "$DEV" != "" ]; then
|
if [ "$DEV" != "" ]; then
|
||||||
echo $DEV > $1/ccw/device
|
echo $DEV > $1/ccw/device
|
||||||
else
|
else
|
||||||
@@ -234,7 +235,7 @@ setup_ccw_device()
|
|||||||
|
|
||||||
setup_eckd_device()
|
setup_eckd_device()
|
||||||
{
|
{
|
||||||
DEV="$(CheckDeviceString $DEVICE)"
|
DEV="$(check_device_string $DEVICE)"
|
||||||
if [ "$DEV" != "" ]; then
|
if [ "$DEV" != "" ]; then
|
||||||
echo $DEV > $1/eckd/device
|
echo $DEV > $1/eckd/device
|
||||||
else
|
else
|
||||||
@@ -252,11 +253,18 @@ setup_eckd_device()
|
|||||||
pr_error "ERROR: Invalid BR_CHR '$BR_CHR'." $ERRMSG
|
pr_error "ERROR: Invalid BR_CHR '$BR_CHR'." $ERRMSG
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
if [ -e $1/eckd/scp_data ]; then
|
||||||
|
echo -n "$SCP_DATA" > $1/eckd/scp_data 2>/dev/null || RETVAL=1
|
||||||
|
if [ $RETVAL -eq 1 ]; then
|
||||||
|
pr_error "ERROR: Invalid SCP_DATA '$SCP_DATA'." $ERRMSG
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_fcp_device()
|
setup_fcp_device()
|
||||||
{
|
{
|
||||||
DEV="$(CheckDeviceString $DEVICE)"
|
DEV="$(check_device_string $DEVICE)"
|
||||||
if [ "$DEV" != "" ]; then
|
if [ "$DEV" != "" ]; then
|
||||||
echo $DEV > $1/fcp/device
|
echo $DEV > $1/fcp/device
|
||||||
else
|
else
|
||||||
@@ -284,6 +292,13 @@ setup_fcp_device()
|
|||||||
pr_error "ERROR: Invalid BR_LBA '$BR_LBA'." $ERRMSG
|
pr_error "ERROR: Invalid BR_LBA '$BR_LBA'." $ERRMSG
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
if [ -e $1/fcp/scp_data ]; then
|
||||||
|
echo -n "$SCP_DATA" > $1/fcp/scp_data 2>/dev/null || RETVAL=1
|
||||||
|
if [ $RETVAL -eq 1 ]; then
|
||||||
|
pr_error "ERROR: Invalid SCP_DATA '$SCP_DATA'." $ERRMSG
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_nss_device()
|
setup_nss_device()
|
||||||
@@ -313,6 +328,13 @@ setup_nvme_device()
|
|||||||
pr_error "ERROR: Invalid BR_LBA '$BR_LBA'." $ERRMSG
|
pr_error "ERROR: Invalid BR_LBA '$BR_LBA'." $ERRMSG
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
if [ -e $1/nvme/scp_data ]; then
|
||||||
|
echo -n "$SCP_DATA" > $1/nvme/scp_data 2>/dev/null || RETVAL=1
|
||||||
|
if [ $RETVAL -eq 1 ]; then
|
||||||
|
pr_error "ERROR: Invalid SCP_DATA '$SCP_DATA'." $ERRMSG
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_reipl()
|
setup_reipl()
|
||||||
@@ -428,6 +450,10 @@ print_fcp_device()
|
|||||||
pr_info "bootprog: $BOOTPROG"
|
pr_info "bootprog: $BOOTPROG"
|
||||||
BR_LBA=$(cat $1/fcp/br_lba) || RETVAL=1
|
BR_LBA=$(cat $1/fcp/br_lba) || RETVAL=1
|
||||||
pr_info "br_lba..: $BR_LBA"
|
pr_info "br_lba..: $BR_LBA"
|
||||||
|
if [ -e $1/fcp/scp_data ]; then
|
||||||
|
SCP_DATA=$(cat $1/fcp/scp_data) || RETVAL=1
|
||||||
|
pr_info "scp_data: $SCP_DATA"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
print_ccw_device()
|
print_ccw_device()
|
||||||
@@ -444,6 +470,10 @@ print_eckd_device()
|
|||||||
pr_info "br_chr..: $BR_CHR"
|
pr_info "br_chr..: $BR_CHR"
|
||||||
BOOTPROG=$(cat $1/eckd/bootprog) || RETVAL=1
|
BOOTPROG=$(cat $1/eckd/bootprog) || RETVAL=1
|
||||||
pr_info "bootprog: $BOOTPROG"
|
pr_info "bootprog: $BOOTPROG"
|
||||||
|
if [ -e $1/eckd/scp_data ]; then
|
||||||
|
SCP_DATA=$(cat $1/eckd/scp_data) || RETVAL=1
|
||||||
|
pr_info "scp_data: $SCP_DATA"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
print_nvme_device()
|
print_nvme_device()
|
||||||
@@ -456,6 +486,10 @@ print_nvme_device()
|
|||||||
pr_info "bootprog: $BOOTPROG"
|
pr_info "bootprog: $BOOTPROG"
|
||||||
BR_LBA=$(cat $1/nvme/br_lba) || RETVAL=1
|
BR_LBA=$(cat $1/nvme/br_lba) || RETVAL=1
|
||||||
pr_info "br_lba..: $BR_LBA"
|
pr_info "br_lba..: $BR_LBA"
|
||||||
|
if [ -e $1/nvme/scp_data ]; then
|
||||||
|
SCP_DATA=$(cat $1/nvme/scp_data) || RETVAL=1
|
||||||
|
pr_info "scp_data: $SCP_DATA"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
print_nss_name()
|
print_nss_name()
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ static void tape390_crypt_parse_opts(struct tape390_crypt *info, int argc,
|
|||||||
"%s: No device specified.\n",prog_name);
|
"%s: No device specified.\n",prog_name);
|
||||||
if (optind + 1 < argc)
|
if (optind + 1 < argc)
|
||||||
ERRMSG_EXIT(EXIT_MISUSE,
|
ERRMSG_EXIT(EXIT_MISUSE,
|
||||||
"%s: More than one device speficied.\n",prog_name);
|
"%s: More than one device specified.\n",prog_name);
|
||||||
strcpy(info->devname, argv[optind]);
|
strcpy(info->devname, argv[optind]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,11 +24,6 @@ extern struct devtype ap_devtype;
|
|||||||
extern struct subtype ap_subtype;
|
extern struct subtype ap_subtype;
|
||||||
extern struct namespace ap_namespace;
|
extern struct namespace ap_namespace;
|
||||||
|
|
||||||
struct ap_node {
|
|
||||||
struct util_list_node node;
|
|
||||||
unsigned int id;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct mdev_cb_data {
|
struct mdev_cb_data {
|
||||||
struct util_list *adapters;
|
struct util_list *adapters;
|
||||||
struct util_list *domains;
|
struct util_list *domains;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#define PATH_MODPROBE "/sbin/modprobe"
|
#define PATH_MODPROBE "/sbin/modprobe"
|
||||||
#define PATH_CCW_BUS "/sys/bus/ccw"
|
#define PATH_CCW_BUS "/sys/bus/ccw"
|
||||||
#define PATH_CCWGROUP_BUS "/sys/bus/ccwgroup"
|
#define PATH_CCWGROUP_BUS "/sys/bus/ccwgroup"
|
||||||
|
#define PATH_IPL "/sys/firmware/ipl"
|
||||||
#define PATH_UDEV_RULES "/etc/udev/rules.d"
|
#define PATH_UDEV_RULES "/etc/udev/rules.d"
|
||||||
#define PATH_UDEV_RULES_VOLATILE "/run/udev/rules.d"
|
#define PATH_UDEV_RULES_VOLATILE "/run/udev/rules.d"
|
||||||
#define PATH_PROC "/proc"
|
#define PATH_PROC "/proc"
|
||||||
@@ -65,6 +66,7 @@ char *path_get_zfcp_lun_dev(struct zfcp_lun_devid *);
|
|||||||
char *path_get_zfcp_port_dev(struct zfcp_lun_devid *);
|
char *path_get_zfcp_port_dev(struct zfcp_lun_devid *);
|
||||||
char *path_get_scsi_hctl_dev(const char *);
|
char *path_get_scsi_hctl_dev(const char *);
|
||||||
char *path_get_bus_attr(const char *, const char *);
|
char *path_get_bus_attr(const char *, const char *);
|
||||||
|
char *path_read_text_file(int chomp, err_t err, char *fmt, ...);
|
||||||
|
|
||||||
exit_code_t path_for_each(const char *,
|
exit_code_t path_for_each(const char *,
|
||||||
exit_code_t (*callback)(const char *, const char *,
|
exit_code_t (*callback)(const char *, const char *,
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ struct select_opts {
|
|||||||
unsigned int online:1;
|
unsigned int online:1;
|
||||||
unsigned int offline:1;
|
unsigned int offline:1;
|
||||||
unsigned int failed:1;
|
unsigned int failed:1;
|
||||||
|
unsigned int ipldev:1;
|
||||||
struct util_list devids; /* List of struct strlist_node */
|
struct util_list devids; /* List of struct strlist_node */
|
||||||
struct util_list by_path; /* List of struct strlist_node */
|
struct util_list by_path; /* List of struct strlist_node */
|
||||||
struct util_list by_node; /* List of struct strlist_node */
|
struct util_list by_node; /* List of struct strlist_node */
|
||||||
|
|||||||
@@ -127,6 +127,7 @@ typedef exit_code_t (*subtype_cb_t)(struct subtype *st, const char *id,
|
|||||||
* @device_undefine: Optional: Undefine a device
|
* @device_undefine: Optional: Undefine a device
|
||||||
* @add_definable_ids: Optional: Add IDs of all devices that can be defined to
|
* @add_definable_ids: Optional: Add IDs of all devices that can be defined to
|
||||||
* specified strlist
|
* specified strlist
|
||||||
|
* @get_ipldev_id: Optional: If subtype provides IPL device, return its ID
|
||||||
*/
|
*/
|
||||||
struct subtype {
|
struct subtype {
|
||||||
/* Static data. */
|
/* Static data. */
|
||||||
@@ -222,6 +223,7 @@ struct subtype {
|
|||||||
exit_code_t (*device_undefine)(struct subtype *, struct device *);
|
exit_code_t (*device_undefine)(struct subtype *, struct device *);
|
||||||
void (*add_definable_ids)(struct subtype *,
|
void (*add_definable_ids)(struct subtype *,
|
||||||
struct util_list *);
|
struct util_list *);
|
||||||
|
char *(*get_ipldev_id)(struct subtype *);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Subtype method accessor functions. */
|
/* Subtype method accessor functions. */
|
||||||
@@ -287,6 +289,7 @@ exit_code_t subtype_detect_definable(struct subtype *, struct device *);
|
|||||||
exit_code_t subtype_device_define(struct subtype *, struct device *);
|
exit_code_t subtype_device_define(struct subtype *, struct device *);
|
||||||
exit_code_t subtype_device_undefine(struct subtype *, struct device *);
|
exit_code_t subtype_device_undefine(struct subtype *, struct device *);
|
||||||
void subtype_add_definable_ids(struct subtype *, struct util_list *);
|
void subtype_add_definable_ids(struct subtype *, struct util_list *);
|
||||||
|
char *subtype_get_ipldev_id(struct subtype *);
|
||||||
|
|
||||||
/* Subtype helper functions. */
|
/* Subtype helper functions. */
|
||||||
bool subtype_device_exists(struct subtype *st, const char *id,
|
bool subtype_device_exists(struct subtype *st, const char *id,
|
||||||
@@ -308,6 +311,7 @@ struct subtype *subtype_find(const char *name);
|
|||||||
struct attrib *subtype_find_dev_attrib(struct subtype *st, const char *str);
|
struct attrib *subtype_find_dev_attrib(struct subtype *st, const char *str);
|
||||||
exit_code_t subtype_read_all_devices(struct subtype *st, config_t config,
|
exit_code_t subtype_read_all_devices(struct subtype *st, config_t config,
|
||||||
read_scope_t);
|
read_scope_t);
|
||||||
|
bool subtypes_find_ipldev(struct subtype **st_ptr, char **id_ptr);
|
||||||
bool subtypes_find_by_devnode(struct devnode *devnode,
|
bool subtypes_find_by_devnode(struct devnode *devnode,
|
||||||
struct subtype **st_ptr, char **id_ptr);
|
struct subtype **st_ptr, char **id_ptr);
|
||||||
void subtype_devices_print_all(void);
|
void subtype_devices_print_all(void);
|
||||||
|
|||||||
@@ -345,6 +345,12 @@ errors.
|
|||||||
.CL lszdev \-\-failed \-\-info
|
.CL lszdev \-\-failed \-\-info
|
||||||
.PP
|
.PP
|
||||||
.
|
.
|
||||||
|
.OD ipldev "" ""
|
||||||
|
Select IPL device
|
||||||
|
|
||||||
|
Select the device used for the most recent IPL operation.
|
||||||
|
.PP
|
||||||
|
.
|
||||||
.
|
.
|
||||||
.SH SETTINGS
|
.SH SETTINGS
|
||||||
A
|
A
|
||||||
|
|||||||
+6
-1
@@ -86,7 +86,7 @@ By default lszdev displays information from both the active and the persistent
|
|||||||
configuration, and, if available, from the auto-configuration.
|
configuration, and, if available, from the auto-configuration.
|
||||||
.PP
|
.PP
|
||||||
.SS Output Format
|
.SS Output Format
|
||||||
In list format, lszdev uses values with the following meaning for the persistent colums (PERS):
|
In list format, lszdev uses values with the following meaning for the persistent columns (PERS):
|
||||||
|
|
||||||
.B yes
|
.B yes
|
||||||
.CL A persistent, non-site specific configuration exists; No site specific configurations available.
|
.CL A persistent, non-site specific configuration exists; No site specific configurations available.
|
||||||
@@ -313,7 +313,12 @@ errors.
|
|||||||
.B Example:
|
.B Example:
|
||||||
.CL lszdev \-\-failed \-\-info
|
.CL lszdev \-\-failed \-\-info
|
||||||
.PP
|
.PP
|
||||||
|
.
|
||||||
|
.OD ipldev "" ""
|
||||||
|
Select IPL device
|
||||||
|
|
||||||
|
Select the device used for the most recent IPL operation.
|
||||||
|
.PP
|
||||||
.
|
.
|
||||||
.
|
.
|
||||||
.SH ACTIONS
|
.SH ACTIONS
|
||||||
|
|||||||
+14
-14
@@ -53,18 +53,18 @@ static void ap_mask_list_changes(const char *source, const char *target,
|
|||||||
struct util_list *adds, struct util_list *subs)
|
struct util_list *adds, struct util_list *subs)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct ap_node *node;
|
struct vfio_ap_node *node;
|
||||||
|
|
||||||
for (i = 0; i <= AP_MAX_MASK_VALUE; i++) {
|
for (i = 0; i <= AP_MAX_MASK_VALUE; i++) {
|
||||||
if (ap_test_bit(i, source)) {
|
if (ap_test_bit(i, source)) {
|
||||||
if (!ap_test_bit(i, target)) {
|
if (!ap_test_bit(i, target)) {
|
||||||
node = misc_malloc(sizeof(struct ap_node));
|
node = misc_malloc(sizeof(struct vfio_ap_node));
|
||||||
node->id = i;
|
node->id = i;
|
||||||
util_list_add_tail(subs, node);
|
util_list_add_tail(subs, node);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ap_test_bit(i, target)) {
|
if (ap_test_bit(i, target)) {
|
||||||
node = misc_malloc(sizeof(struct ap_node));
|
node = misc_malloc(sizeof(struct vfio_ap_node));
|
||||||
node->id = i;
|
node->id = i;
|
||||||
util_list_add_tail(adds, node);
|
util_list_add_tail(adds, node);
|
||||||
}
|
}
|
||||||
@@ -210,7 +210,7 @@ static bool ap_validate_mask_input(char *mask, const char *input,
|
|||||||
* Translate the mask value into a list of additions/removals for later
|
* Translate the mask value into a list of additions/removals for later
|
||||||
* conflict analysis.
|
* conflict analysis.
|
||||||
*/
|
*/
|
||||||
util_list_init(adds, struct ap_node, node);
|
util_list_init(adds, struct vfio_ap_node, node);
|
||||||
ap_mask_list_changes(mask, newmask, adds, subs);
|
ap_mask_list_changes(mask, newmask, adds, subs);
|
||||||
strcpy(mask, newmask);
|
strcpy(mask, newmask);
|
||||||
goto out;
|
goto out;
|
||||||
@@ -948,8 +948,8 @@ static exit_code_t ap_check_mask_changes(config_t config,
|
|||||||
struct util_list all_ap;
|
struct util_list all_ap;
|
||||||
struct util_list all_aq;
|
struct util_list all_aq;
|
||||||
|
|
||||||
util_list_init(&all_ap, struct ap_node, node);
|
util_list_init(&all_ap, struct vfio_ap_node, node);
|
||||||
util_list_init(&all_aq, struct ap_node, node);
|
util_list_init(&all_aq, struct vfio_ap_node, node);
|
||||||
|
|
||||||
/* Validate the mask changes against existing vfio-ap devices */
|
/* Validate the mask changes against existing vfio-ap devices */
|
||||||
if (SCOPE_ACTIVE(config) && (!util_list_is_empty(add_ap) ||
|
if (SCOPE_ACTIVE(config) && (!util_list_is_empty(add_ap) ||
|
||||||
@@ -996,14 +996,14 @@ static exit_code_t ap_devtype_write_settings(struct devtype *dt,
|
|||||||
exit_code_t rc = EXIT_OK;
|
exit_code_t rc = EXIT_OK;
|
||||||
/* No kernel or module parameters exist for AP device driver. */
|
/* No kernel or module parameters exist for AP device driver. */
|
||||||
|
|
||||||
util_list_init(&add_ap, struct ap_node, node);
|
util_list_init(&add_ap, struct vfio_ap_node, node);
|
||||||
util_list_init(&add_aq, struct ap_node, node);
|
util_list_init(&add_aq, struct vfio_ap_node, node);
|
||||||
util_list_init(&sub_ap, struct ap_node, node);
|
util_list_init(&sub_ap, struct vfio_ap_node, node);
|
||||||
util_list_init(&sub_aq, struct ap_node, node);
|
util_list_init(&sub_aq, struct vfio_ap_node, node);
|
||||||
util_list_init(&add_p_ap, struct ap_node, node);
|
util_list_init(&add_p_ap, struct vfio_ap_node, node);
|
||||||
util_list_init(&add_p_aq, struct ap_node, node);
|
util_list_init(&add_p_aq, struct vfio_ap_node, node);
|
||||||
util_list_init(&sub_p_ap, struct ap_node, node);
|
util_list_init(&sub_p_ap, struct vfio_ap_node, node);
|
||||||
util_list_init(&sub_p_aq, struct ap_node, node);
|
util_list_init(&sub_p_aq, struct vfio_ap_node, node);
|
||||||
write_ap = write_aq = write_udev = false;
|
write_ap = write_aq = write_udev = false;
|
||||||
|
|
||||||
rc = ap_get_lock();
|
rc = ap_get_lock();
|
||||||
|
|||||||
@@ -1827,6 +1827,27 @@ static char *ccw_st_get_active_attrib_path(struct subtype *st,
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return a newly allocated character string containing the IPL device ID in
|
||||||
|
* case of CCW IPL. */
|
||||||
|
static char *ccw_st_get_ipldev_id(struct subtype *st)
|
||||||
|
{
|
||||||
|
char *type, *id = NULL;
|
||||||
|
|
||||||
|
type = path_read_text_file(1, err_ignore, PATH_IPL "/ipl_type");
|
||||||
|
if (strcmp(type, "ccw") != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
id = path_read_text_file(1, err_ignore, PATH_IPL "/device");
|
||||||
|
if (!ccw_st_exists_active(st, id)) {
|
||||||
|
free(id);
|
||||||
|
id = NULL;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
free(type);
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
/* The methods of this subtype assume that @data points to a
|
/* The methods of this subtype assume that @data points to a
|
||||||
* struct ccw_subtype_data. */
|
* struct ccw_subtype_data. */
|
||||||
struct subtype ccw_subtype = {
|
struct subtype ccw_subtype = {
|
||||||
@@ -1864,4 +1885,6 @@ struct subtype ccw_subtype = {
|
|||||||
.add_devnodes = &ccw_st_add_devnodes,
|
.add_devnodes = &ccw_st_add_devnodes,
|
||||||
.resolve_devnode = &ccw_st_resolve_devnode,
|
.resolve_devnode = &ccw_st_resolve_devnode,
|
||||||
.get_active_attrib_path = &ccw_st_get_active_attrib_path,
|
.get_active_attrib_path = &ccw_st_get_active_attrib_path,
|
||||||
|
|
||||||
|
.get_ipldev_id = &ccw_st_get_ipldev_id,
|
||||||
};
|
};
|
||||||
|
|||||||
+10
-3
@@ -124,6 +124,7 @@ enum {
|
|||||||
OPT_ONLINE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
OPT_ONLINE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||||
OPT_OFFLINE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
OPT_OFFLINE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||||
OPT_FAILED = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
OPT_FAILED = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||||
|
OPT_IPLDEV = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||||
OPT_BY_PATH = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
OPT_BY_PATH = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||||
OPT_BY_NODE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
OPT_BY_NODE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||||
OPT_BY_INTERFACE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
OPT_BY_INTERFACE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||||
@@ -173,14 +174,14 @@ static struct opts_conflict conflict_list[] = {
|
|||||||
OPT_REMOVE_ALL, OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE,
|
OPT_REMOVE_ALL, OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE,
|
||||||
OPT_OFFLINE, OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE,
|
OPT_OFFLINE, OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE,
|
||||||
OPT_BY_ATTRIB, OPT_ACTIVE, OPT_PERSISTENT, OPT_FAILED,
|
OPT_BY_ATTRIB, OPT_ACTIVE, OPT_PERSISTENT, OPT_FAILED,
|
||||||
OPT_DECONFIGURE_ALL, 0),
|
OPT_IPLDEV, OPT_DECONFIGURE_ALL, 0),
|
||||||
OPTS_CONFLICT(OPT_LIST_TYPES,
|
OPTS_CONFLICT(OPT_LIST_TYPES,
|
||||||
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
|
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
|
||||||
OPT_EXPORT, OPT_IMPORT, OPT_APPLY, OPT_REMOVE,
|
OPT_EXPORT, OPT_IMPORT, OPT_APPLY, OPT_REMOVE,
|
||||||
OPT_REMOVE_ALL, OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE,
|
OPT_REMOVE_ALL, OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE,
|
||||||
OPT_OFFLINE, OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE,
|
OPT_OFFLINE, OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE,
|
||||||
OPT_BY_ATTRIB, OPT_ACTIVE, OPT_PERSISTENT, OPT_FAILED,
|
OPT_BY_ATTRIB, OPT_ACTIVE, OPT_PERSISTENT, OPT_FAILED,
|
||||||
OPT_DECONFIGURE_ALL, 0),
|
OPT_IPLDEV, OPT_DECONFIGURE_ALL, 0),
|
||||||
OPTS_CONFLICT(OPT_EXPORT,
|
OPTS_CONFLICT(OPT_EXPORT,
|
||||||
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
|
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
|
||||||
OPT_LIST_TYPES, OPT_IMPORT, OPT_APPLY, OPT_REMOVE,
|
OPT_LIST_TYPES, OPT_IMPORT, OPT_APPLY, OPT_REMOVE,
|
||||||
@@ -197,7 +198,7 @@ static struct opts_conflict conflict_list[] = {
|
|||||||
OPT_REMOVE_ALL, OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE,
|
OPT_REMOVE_ALL, OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE,
|
||||||
OPT_OFFLINE, OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE,
|
OPT_OFFLINE, OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE,
|
||||||
OPT_BY_ATTRIB, OPT_ACTIVE, OPT_PERSISTENT, OPT_FAILED,
|
OPT_BY_ATTRIB, OPT_ACTIVE, OPT_PERSISTENT, OPT_FAILED,
|
||||||
OPT_DECONFIGURE_ALL, 0),
|
OPT_IPLDEV, OPT_DECONFIGURE_ALL, 0),
|
||||||
OPTS_CONFLICT(OPT_APPLY,
|
OPTS_CONFLICT(OPT_APPLY,
|
||||||
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
|
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
|
||||||
OPT_LIST_TYPES, OPT_EXPORT, OPT_IMPORT, OPT_REMOVE,
|
OPT_LIST_TYPES, OPT_EXPORT, OPT_IMPORT, OPT_REMOVE,
|
||||||
@@ -223,6 +224,7 @@ static const struct option opt_list[] = {
|
|||||||
{ "online", no_argument, NULL, OPT_ONLINE },
|
{ "online", no_argument, NULL, OPT_ONLINE },
|
||||||
{ "offline", no_argument, NULL, OPT_OFFLINE },
|
{ "offline", no_argument, NULL, OPT_OFFLINE },
|
||||||
{ "failed", no_argument, NULL, OPT_FAILED },
|
{ "failed", no_argument, NULL, OPT_FAILED },
|
||||||
|
{ "ipldev", no_argument, NULL, OPT_IPLDEV },
|
||||||
{ "by-path", required_argument, NULL, OPT_BY_PATH },
|
{ "by-path", required_argument, NULL, OPT_BY_PATH },
|
||||||
{ "by-node", required_argument, NULL, OPT_BY_NODE },
|
{ "by-node", required_argument, NULL, OPT_BY_NODE },
|
||||||
{ "by-interface", required_argument, NULL, OPT_BY_INTERFACE },
|
{ "by-interface", required_argument, NULL, OPT_BY_INTERFACE },
|
||||||
@@ -837,6 +839,11 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
|
|||||||
opts->select->failed = 1;
|
opts->select->failed = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OPT_IPLDEV:
|
||||||
|
/* --ipldev */
|
||||||
|
opts->select->ipldev = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
case OPT_BY_PATH:
|
case OPT_BY_PATH:
|
||||||
/* --by-path MOUNTPOINT */
|
/* --by-path MOUNTPOINT */
|
||||||
strlist_add(&opts->select->by_path, "%s", optarg);
|
strlist_add(&opts->select->by_path, "%s", optarg);
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ SELECTION
|
|||||||
--existing Select devices found in the active configuration
|
--existing Select devices found in the active configuration
|
||||||
--online/--offline Select devices that are online/offline
|
--online/--offline Select devices that are online/offline
|
||||||
--failed Select devices that are not functioning correctly
|
--failed Select devices that are not functioning correctly
|
||||||
|
--ipldev Select device used for IPL/boot
|
||||||
--by-path PATH Select device providing file system path, e.g. /usr
|
--by-path PATH Select device providing file system path, e.g. /usr
|
||||||
--by-node NODE Select device providing device node, e.g. /dev/sda
|
--by-node NODE Select device providing device node, e.g. /dev/sda
|
||||||
--by-interface NAME Select device providing network interface, e.g. eth0
|
--by-interface NAME Select device providing network interface, e.g. eth0
|
||||||
|
|||||||
@@ -477,6 +477,26 @@ static void dasd_st_add_modules(struct subtype *st, struct device *dev,
|
|||||||
strlist_add_unique(modules, DASD_DIAG_MOD_NAME);
|
strlist_add_unique(modules, DASD_DIAG_MOD_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *dasd_eckd_st_get_ipldev_id(struct subtype *st)
|
||||||
|
{
|
||||||
|
char *id, *type;
|
||||||
|
|
||||||
|
/* Handle CCW-type IPL first. */
|
||||||
|
id = st->super->get_ipldev_id(st);
|
||||||
|
if (id)
|
||||||
|
return id;
|
||||||
|
|
||||||
|
/* Extra-handling for eckd LD-IPL. */
|
||||||
|
type = path_read_text_file(1, err_ignore, PATH_IPL "/ipl_type");
|
||||||
|
if (strcmp(type, "eckd") != 0)
|
||||||
|
goto out;
|
||||||
|
id = path_read_text_file(1, err_ignore, PATH_IPL "/ipl/device");
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(type);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DASD methods.
|
* DASD methods.
|
||||||
*/
|
*/
|
||||||
@@ -798,6 +818,7 @@ struct subtype dasd_subtype_eckd = {
|
|||||||
.configure_persistent = &dasd_st_configure_persistent,
|
.configure_persistent = &dasd_st_configure_persistent,
|
||||||
.check_pre_configure = &dasd_st_check_pre_configure,
|
.check_pre_configure = &dasd_st_check_pre_configure,
|
||||||
.add_modules = &dasd_st_add_modules,
|
.add_modules = &dasd_st_add_modules,
|
||||||
|
.get_ipldev_id = &dasd_eckd_st_get_ipldev_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ccw_subtype_data dasd_fba_data = {
|
static struct ccw_subtype_data dasd_fba_data = {
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ enum {
|
|||||||
OPT_ONLINE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
OPT_ONLINE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||||
OPT_OFFLINE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
OPT_OFFLINE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||||
OPT_FAILED = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
OPT_FAILED = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||||
|
OPT_IPLDEV = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||||
OPT_BY_PATH = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
OPT_BY_PATH = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||||
OPT_BY_NODE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
OPT_BY_NODE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||||
OPT_BY_INTERFACE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
OPT_BY_INTERFACE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||||
@@ -129,6 +130,7 @@ static struct opts_conflict conflict_list[] = {
|
|||||||
OPTS_CONFLICT(OPT_TYPE,
|
OPTS_CONFLICT(OPT_TYPE,
|
||||||
OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE, OPT_OFFLINE,
|
OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE, OPT_OFFLINE,
|
||||||
OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE, OPT_FAILED,
|
OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE, OPT_FAILED,
|
||||||
|
OPT_IPLDEV,
|
||||||
0),
|
0),
|
||||||
OPTS_CONFLICT(OPT_SITE,
|
OPTS_CONFLICT(OPT_SITE,
|
||||||
OPT_TYPE),
|
OPT_TYPE),
|
||||||
@@ -148,6 +150,7 @@ static const struct option opt_list[] = {
|
|||||||
{ "online", no_argument, NULL, OPT_ONLINE },
|
{ "online", no_argument, NULL, OPT_ONLINE },
|
||||||
{ "offline", no_argument, NULL, OPT_OFFLINE },
|
{ "offline", no_argument, NULL, OPT_OFFLINE },
|
||||||
{ "failed", no_argument, NULL, OPT_FAILED },
|
{ "failed", no_argument, NULL, OPT_FAILED },
|
||||||
|
{ "ipldev", no_argument, NULL, OPT_IPLDEV },
|
||||||
{ "by-path", required_argument, NULL, OPT_BY_PATH },
|
{ "by-path", required_argument, NULL, OPT_BY_PATH },
|
||||||
{ "by-node", required_argument, NULL, OPT_BY_NODE },
|
{ "by-node", required_argument, NULL, OPT_BY_NODE },
|
||||||
{ "by-interface", required_argument, NULL, OPT_BY_INTERFACE },
|
{ "by-interface", required_argument, NULL, OPT_BY_INTERFACE },
|
||||||
@@ -609,6 +612,11 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
|
|||||||
opts->select->failed = 1;
|
opts->select->failed = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OPT_IPLDEV:
|
||||||
|
/* --ipldev */
|
||||||
|
opts->select->ipldev = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
case OPT_BY_PATH:
|
case OPT_BY_PATH:
|
||||||
/* --by-path MOUNTPOINT */
|
/* --by-path MOUNTPOINT */
|
||||||
strlist_add(&opts->select->by_path, "%s", optarg);
|
strlist_add(&opts->select->by_path, "%s", optarg);
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ SELECTION
|
|||||||
--existing Select devices found in the active configuration
|
--existing Select devices found in the active configuration
|
||||||
--online/--offline Select devices that are online/offline
|
--online/--offline Select devices that are online/offline
|
||||||
--failed Select devices that are not functioning correctly
|
--failed Select devices that are not functioning correctly
|
||||||
|
--ipldev Select device used for IPL/boot
|
||||||
--by-path PATH Select device providing file system path, e.g. /usr
|
--by-path PATH Select device providing file system path, e.g. /usr
|
||||||
--by-node NODE Select device providing device node, e.g. /dev/sda
|
--by-node NODE Select device providing device node, e.g. /dev/sda
|
||||||
--by-interface NAME Select device providing network interface, e.g. eth0
|
--by-interface NAME Select device providing network interface, e.g. eth0
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "devtype.h"
|
#include "devtype.h"
|
||||||
|
#include "lib/util_libc.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
#include "zfcp.h"
|
#include "zfcp.h"
|
||||||
@@ -404,3 +405,20 @@ char *path_get_bus_attr(const char *bus, const char *attr)
|
|||||||
{
|
{
|
||||||
return path_get("/sys/bus/%s/%s", bus, attr);
|
return path_get("/sys/bus/%s/%s", bus, attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read text file from adjusted path. */
|
||||||
|
char *path_read_text_file(int chomp, err_t err, char *fmt, ...)
|
||||||
|
{
|
||||||
|
char *path, *path2, *text;
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
util_vasprintf(&path, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
path2 = path_get(path);
|
||||||
|
text = misc_read_text_file(path2, chomp, err);
|
||||||
|
free(path2);
|
||||||
|
free(path);
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|||||||
+19
-2
@@ -69,7 +69,8 @@ bool select_opts_dev_specified(struct select_opts *select)
|
|||||||
!util_list_is_empty(&select->by_if) ||
|
!util_list_is_empty(&select->by_if) ||
|
||||||
!util_list_is_empty(&select->by_attr) ||
|
!util_list_is_empty(&select->by_attr) ||
|
||||||
select->all || select->configured || select->existing ||
|
select->all || select->configured || select->existing ||
|
||||||
select->online || select->offline || select->failed)
|
select->online || select->offline || select->failed ||
|
||||||
|
select->ipldev)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -1207,6 +1208,19 @@ out:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Select device that was used for IPL. */
|
||||||
|
static void select_ipldev(struct util_list *selected)
|
||||||
|
{
|
||||||
|
struct subtype *st;
|
||||||
|
char *id;
|
||||||
|
|
||||||
|
if (!subtypes_find_ipldev(&st, &id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
selected_dev_list_add(selected, st->devtype, st, id, NULL, 0);
|
||||||
|
free(id);
|
||||||
|
}
|
||||||
|
|
||||||
/* Determine list of IDs of selected devices based on selection options.
|
/* Determine list of IDs of selected devices based on selection options.
|
||||||
* Results are stored as list of struct selected_dev_node in SELECTED.
|
* Results are stored as list of struct selected_dev_node in SELECTED.
|
||||||
* If @existing is set, only return nodes for existing devices.
|
* If @existing is set, only return nodes for existing devices.
|
||||||
@@ -1235,7 +1249,7 @@ exit_code_t select_devices(struct select_opts *select,
|
|||||||
!(util_list_is_empty(&select->by_path) &&
|
!(util_list_is_empty(&select->by_path) &&
|
||||||
util_list_is_empty(&select->by_node) &&
|
util_list_is_empty(&select->by_node) &&
|
||||||
util_list_is_empty(&select->by_if) &&
|
util_list_is_empty(&select->by_if) &&
|
||||||
util_list_is_empty(&select->by_attr)))
|
util_list_is_empty(&select->by_attr) && !select->ipldev))
|
||||||
goto by_function;
|
goto by_function;
|
||||||
|
|
||||||
/* Convert device ID specifications to enable tracking of specifications
|
/* Convert device ID specifications to enable tracking of specifications
|
||||||
@@ -1291,6 +1305,9 @@ by_function:
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (select->ipldev)
|
||||||
|
select_ipldev(selected);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
/* Release device ID specifications tracking list. */
|
/* Release device ID specifications tracking list. */
|
||||||
ptrlist_free(specs, 1);
|
ptrlist_free(specs, 1);
|
||||||
|
|||||||
@@ -96,6 +96,30 @@ static exit_code_t devnode_cb(struct subtype *st, const char *id,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find device which was used for IPL. Note that id_ptr will point to a newly
|
||||||
|
* allocated string on success. */
|
||||||
|
bool subtypes_find_ipldev(struct subtype **st_ptr, char **id_ptr)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
struct devtype *dt;
|
||||||
|
struct subtype *st;
|
||||||
|
char *id;
|
||||||
|
|
||||||
|
for (i = 0; (dt = devtypes[i]); i++) {
|
||||||
|
for (j = 0; (st = dt->subtypes[j]); j++) {
|
||||||
|
id = subtype_get_ipldev_id(st);
|
||||||
|
if (id) {
|
||||||
|
*st_ptr = st;
|
||||||
|
*id_ptr = id;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Find a device which provides the specified devnode. Note that id_ptr will
|
/* Find a device which provides the specified devnode. Note that id_ptr will
|
||||||
* point to a newly allocated string on success. */
|
* point to a newly allocated string on success. */
|
||||||
bool subtypes_find_by_devnode(struct devnode *devnode, struct subtype **st_ptr,
|
bool subtypes_find_by_devnode(struct devnode *devnode, struct subtype **st_ptr,
|
||||||
@@ -520,6 +544,16 @@ void subtype_add_definable_ids(struct subtype *st, struct util_list *ids)
|
|||||||
super->add_definable_ids(st, ids);
|
super->add_definable_ids(st, ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *subtype_get_ipldev_id(struct subtype *st)
|
||||||
|
{
|
||||||
|
struct subtype *super = super_get(st, get_ipldev_id, 0);
|
||||||
|
|
||||||
|
if (super)
|
||||||
|
return super->get_ipldev_id(st);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Subtype helpers. These functions combine some of the subtype methods
|
* Subtype helpers. These functions combine some of the subtype methods
|
||||||
* to implement more complex functions.
|
* to implement more complex functions.
|
||||||
|
|||||||
@@ -251,11 +251,12 @@ exit_code_t udev_ccwgroup_write_device(struct device *dev, bool autoconf)
|
|||||||
fprintf(fd, "# Generated by chzdev\n");
|
fprintf(fd, "# Generated by chzdev\n");
|
||||||
|
|
||||||
/* Triggers. */
|
/* Triggers. */
|
||||||
fprintf(fd, "ACTION==\"add\", SUBSYSTEM==\"drivers\", "
|
fprintf(fd, "ACTION!=\"add|change\", GOTO=\"%s\"\n", end_label);
|
||||||
|
fprintf(fd, "SUBSYSTEM==\"drivers\", "
|
||||||
"KERNEL==\"%s\", GOTO=\"%s\"\n", drv, group_label);
|
"KERNEL==\"%s\", GOTO=\"%s\"\n", drv, group_label);
|
||||||
for (i = 0; i < devid.num; i++) {
|
for (i = 0; i < devid.num; i++) {
|
||||||
chan_id = ccw_devid_to_str(&devid.devid[i]);
|
chan_id = ccw_devid_to_str(&devid.devid[i]);
|
||||||
fprintf(fd, "ACTION==\"add\", SUBSYSTEM==\"ccw\", "
|
fprintf(fd, "SUBSYSTEM==\"ccw\", "
|
||||||
"KERNEL==\"%s\", DRIVER==\"%s\", "
|
"KERNEL==\"%s\", DRIVER==\"%s\", "
|
||||||
"GOTO=\"%s\"\n", chan_id, drv, group_label);
|
"GOTO=\"%s\"\n", chan_id, drv, group_label);
|
||||||
free(chan_id);
|
free(chan_id);
|
||||||
@@ -275,7 +276,19 @@ exit_code_t udev_ccwgroup_write_device(struct device *dev, bool autoconf)
|
|||||||
end_label);
|
end_label);
|
||||||
free(chan_id);
|
free(chan_id);
|
||||||
}
|
}
|
||||||
fprintf(fd, "ATTR{[drivers/ccwgroup:%s]group}=\"", drv);
|
|
||||||
|
/* Parallel execution of the ccwgroup devices udev rule can lead to
|
||||||
|
* udevadm warnings. To prevent this, serialize the execution.
|
||||||
|
*/
|
||||||
|
fprintf(fd, "\n# Note: Serialize add events on different devices to"
|
||||||
|
" change event on single\n# base device to prevent duplicate"
|
||||||
|
" concurrent grouping attempts\n");
|
||||||
|
|
||||||
|
/* The new change uevent should be generated to the base-device only */
|
||||||
|
chan_id = ccw_devid_to_str(&devid.devid[0]);
|
||||||
|
fprintf(fd, "ACTION==\"add\", ATTR{[ccw/%s]uevent}=\"change\"\n", chan_id);
|
||||||
|
fprintf(fd, "ACTION==\"change\", ATTR{[drivers/ccwgroup:%s]group}=\"", drv);
|
||||||
|
free(chan_id);
|
||||||
for (i = 0; i < devid.num; i++) {
|
for (i = 0; i < devid.num; i++) {
|
||||||
chan_id = ccw_devid_to_str(&devid.devid[i]);
|
chan_id = ccw_devid_to_str(&devid.devid[i]);
|
||||||
fprintf(fd, "%s%s", i > 0 ? "," : "", chan_id);
|
fprintf(fd, "%s%s", i > 0 ? "," : "", chan_id);
|
||||||
|
|||||||
@@ -1105,6 +1105,28 @@ static exit_code_t zfcp_lun_st_detect_definable(struct subtype *st,
|
|||||||
return EXIT_OK;
|
return EXIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *zfcp_lun_st_get_ipldev_id(struct subtype *st)
|
||||||
|
{
|
||||||
|
char *type, *fcp_dev, *wwpn, *lun, *id = NULL;
|
||||||
|
|
||||||
|
type = path_read_text_file(1, err_ignore, PATH_IPL "/ipl_type");
|
||||||
|
if (strcmp(type, "fcp") != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
fcp_dev = path_read_text_file(1, err_ignore, PATH_IPL "/device");
|
||||||
|
wwpn = path_read_text_file(1, err_ignore, PATH_IPL "/wwpn");
|
||||||
|
lun = path_read_text_file(1, err_ignore, PATH_IPL "/lun");
|
||||||
|
if (fcp_dev && wwpn && lun)
|
||||||
|
id = misc_asprintf("%s:%s:%s", fcp_dev, wwpn, lun);
|
||||||
|
free(lun);
|
||||||
|
free(wwpn);
|
||||||
|
free(fcp_dev);
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(type);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* zfcp lun subtype.
|
* zfcp lun subtype.
|
||||||
*/
|
*/
|
||||||
@@ -1168,4 +1190,6 @@ struct subtype zfcp_lun_subtype = {
|
|||||||
.detect_definable = &zfcp_lun_st_detect_definable,
|
.detect_definable = &zfcp_lun_st_detect_definable,
|
||||||
.device_define = &zfcp_lun_st_device_define,
|
.device_define = &zfcp_lun_st_device_define,
|
||||||
.device_undefine = &zfcp_lun_st_device_undefine,
|
.device_undefine = &zfcp_lun_st_device_undefine,
|
||||||
|
|
||||||
|
.get_ipldev_id = &zfcp_lun_st_get_ipldev_id,
|
||||||
};
|
};
|
||||||
|
|||||||
+7
-2
@@ -695,6 +695,8 @@ static void kdump_select_prod_init(void)
|
|||||||
unsigned long prefix, ptr, count, tv_sec, i;
|
unsigned long prefix, ptr, count, tv_sec, i;
|
||||||
struct timeval timeval;
|
struct timeval timeval;
|
||||||
|
|
||||||
|
util_log_print(UTIL_LOG_TRACE, "DFI kdump production system dump initialization\n");
|
||||||
|
|
||||||
if (g.opts.select_specified && !l.kdump_base)
|
if (g.opts.select_specified && !l.kdump_base)
|
||||||
ERR_EXIT("The \"--select\" option is not possible with this "
|
ERR_EXIT("The \"--select\" option is not possible with this "
|
||||||
"dump");
|
"dump");
|
||||||
@@ -712,9 +714,10 @@ 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_virt_read(ptr + i * sizeof(long), &prefix,
|
if (dfi_mem_virt_read(dfi_vm_vtop(ptr) + i * sizeof(long), &prefix,
|
||||||
sizeof(prefix)))
|
sizeof(prefix)))
|
||||||
continue;
|
continue;
|
||||||
|
prefix = dfi_vm_vtop(prefix);
|
||||||
if (prefix == 0)
|
if (prefix == 0)
|
||||||
continue;
|
continue;
|
||||||
if (prefix % 0x1000)
|
if (prefix % 0x1000)
|
||||||
@@ -736,7 +739,7 @@ static void utsname_init(void)
|
|||||||
|
|
||||||
if (dfi_vmcoreinfo_symbol(&ptr, "init_uts_ns"))
|
if (dfi_vmcoreinfo_symbol(&ptr, "init_uts_ns"))
|
||||||
return;
|
return;
|
||||||
if (dfi_mem_virt_read(ptr, buf, sizeof(buf)))
|
if (dfi_mem_virt_read(dfi_vm_vtop(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)
|
||||||
@@ -806,6 +809,8 @@ int dfi_init(void)
|
|||||||
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();
|
||||||
|
if (rc == 0)
|
||||||
|
dfi_mem_chunk_sort();
|
||||||
if (rc == 0 && dfi_feat_seek()) {
|
if (rc == 0 && dfi_feat_seek()) {
|
||||||
kdump_init();
|
kdump_init();
|
||||||
dfi_vmcoreinfo_init();
|
dfi_vmcoreinfo_init();
|
||||||
|
|||||||
@@ -30,10 +30,6 @@ int pt_load_add(const struct zg_fh *fh, const Elf64_Phdr *phdr, void **data,
|
|||||||
__func__, phdr->p_paddr, phdr->p_vaddr, phdr->p_offset, phdr->p_filesz,
|
__func__, phdr->p_paddr, phdr->p_vaddr, phdr->p_offset, phdr->p_filesz,
|
||||||
phdr->p_memsz);
|
phdr->p_memsz);
|
||||||
|
|
||||||
if (phdr->p_paddr != phdr->p_vaddr) {
|
|
||||||
STDERR("Dump file \"%s\" is a user space core dump\n", fh->path);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
if (phdr->p_memsz == 0)
|
if (phdr->p_memsz == 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (phdr->p_offset + phdr->p_filesz > zg_size(fh))
|
if (phdr->p_offset + phdr->p_filesz > zg_size(fh))
|
||||||
|
|||||||
@@ -324,6 +324,14 @@ void dfi_mem_chunk_read_zero(struct dfi_mem_chunk *UNUSED(mem_chunk),
|
|||||||
memset(buf, 0, cnt);
|
memset(buf, 0, cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sort memory chunks by start value
|
||||||
|
*/
|
||||||
|
void dfi_mem_chunk_sort(void)
|
||||||
|
{
|
||||||
|
util_list_sort(&l.mem_virt.chunk_list, mem_chunk_cmp_fn, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return mem_chunk list head
|
* Return mem_chunk list head
|
||||||
*/
|
*/
|
||||||
@@ -350,6 +358,14 @@ u64 dfi_mem_range(void)
|
|||||||
return l.mem_virt.end_addr - l.mem_virt.start_addr + 1;
|
return l.mem_virt.end_addr - l.mem_virt.start_addr + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return maximum memory address
|
||||||
|
*/
|
||||||
|
u64 dfi_mem_end(void)
|
||||||
|
{
|
||||||
|
return l.mem_virt.end_addr;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Is memory range valid?
|
* Is memory range valid?
|
||||||
*/
|
*/
|
||||||
@@ -439,6 +455,10 @@ void dfi_mem_unmap(u64 start, u64 size)
|
|||||||
struct dfi_mem_chunk *mem_chunk, *tmp;
|
struct dfi_mem_chunk *mem_chunk, *tmp;
|
||||||
u64 end = start + size - 1;
|
u64 end = start + size - 1;
|
||||||
|
|
||||||
|
util_log_print(UTIL_LOG_TRACE,
|
||||||
|
"DFI mem unmap start 0x%016lx, size 0x%016lx\n",
|
||||||
|
start, size);
|
||||||
|
|
||||||
util_list_iterate_safe(&l.mem_virt.chunk_list, mem_chunk, tmp) {
|
util_list_iterate_safe(&l.mem_virt.chunk_list, mem_chunk, tmp) {
|
||||||
/*
|
/*
|
||||||
* Chunk not hit?
|
* Chunk not hit?
|
||||||
@@ -504,6 +524,10 @@ void dfi_mem_unmap(u64 start, u64 size)
|
|||||||
*/
|
*/
|
||||||
void dfi_mem_map(u64 start, u64 size, u64 start_phys)
|
void dfi_mem_map(u64 start, u64 size, u64 start_phys)
|
||||||
{
|
{
|
||||||
|
util_log_print(UTIL_LOG_TRACE,
|
||||||
|
"DFI mem map start 0x%016lx, size 0x%016lx, base 0x%016lx\n",
|
||||||
|
start, size, start_phys);
|
||||||
|
|
||||||
if (mem_range_mapped(start, size)) {
|
if (mem_range_mapped(start, size)) {
|
||||||
dfi_mem_map_print(false);
|
dfi_mem_map_print(false);
|
||||||
ABORT("Map request for already mapped region (%llx/%llx/%llx)",
|
ABORT("Map request for already mapped region (%llx/%llx/%llx)",
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ void dfi_mem_chunk_add(u64 start, u64 size, void *data,
|
|||||||
dfi_mem_chunk_read_fn read_fn,
|
dfi_mem_chunk_read_fn read_fn,
|
||||||
dfi_mem_chunk_free_fn free_fn);
|
dfi_mem_chunk_free_fn free_fn);
|
||||||
u64 dfi_mem_range(void);
|
u64 dfi_mem_range(void);
|
||||||
|
u64 dfi_mem_end(void);
|
||||||
int dfi_mem_range_valid(u64 addr, u64 len);
|
int dfi_mem_range_valid(u64 addr, u64 len);
|
||||||
unsigned int dfi_mem_chunk_cnt(void);
|
unsigned int dfi_mem_chunk_cnt(void);
|
||||||
struct dfi_mem_chunk *dfi_mem_chunk_first(void);
|
struct dfi_mem_chunk *dfi_mem_chunk_first(void);
|
||||||
@@ -54,6 +55,7 @@ struct dfi_mem_chunk *dfi_mem_chunk_find(u64 addr);
|
|||||||
struct util_list *dfi_mem_chunk_list(void);
|
struct util_list *dfi_mem_chunk_list(void);
|
||||||
#define dfi_mem_chunk_iterate(mem_chunk) \
|
#define dfi_mem_chunk_iterate(mem_chunk) \
|
||||||
util_list_iterate(dfi_mem_chunk_list(), mem_chunk)
|
util_list_iterate(dfi_mem_chunk_list(), mem_chunk)
|
||||||
|
void dfi_mem_chunk_sort(void);
|
||||||
|
|
||||||
int dfi_mem_virt_read(u64 addr, void *buf, size_t cnt);
|
int dfi_mem_virt_read(u64 addr, void *buf, size_t cnt);
|
||||||
int dfi_mem_phys_read(u64 addr, void *buf, size_t cnt);
|
int dfi_mem_phys_read(u64 addr, void *buf, size_t cnt);
|
||||||
|
|||||||
+11
-3
@@ -346,11 +346,19 @@ int dfi_s390_init_gen(bool extended)
|
|||||||
l.extended = extended;
|
l.extended = extended;
|
||||||
if (read_s390_hdr() != 0)
|
if (read_s390_hdr() != 0)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
zg_ioctl(g.fh, BLKSSZGET, &l.blk_size, "BLKSSZGET", ZG_CHECK);
|
if (!extended) {
|
||||||
if (!extended)
|
|
||||||
rc = mem_chunks_add();
|
rc = mem_chunks_add();
|
||||||
else
|
} else {
|
||||||
|
/*
|
||||||
|
* A device block size is required for a decompression of
|
||||||
|
* s390_ext dump with compressed dump segments.
|
||||||
|
* Since dumps in s390_ext format can reside on DASD partition
|
||||||
|
* only, bail out upon ioctl error on BLKSSZGET.
|
||||||
|
*/
|
||||||
|
if (zg_ioctl(g.fh, BLKSSZGET, &l.blk_size, "BLKSSZGET", ZG_CHECK_NONE))
|
||||||
|
return -ENODEV;
|
||||||
rc = mem_chunks_add_ext();
|
rc = mem_chunks_add_ext();
|
||||||
|
}
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
rc = df_s390_cpu_info_add(&l.hdr, l.hdr.mem_size);
|
rc = df_s390_cpu_info_add(&l.hdr, l.hdr.mem_size);
|
||||||
|
|||||||
+54
-22
@@ -20,6 +20,8 @@
|
|||||||
#include "dfi_mem_chunk.h"
|
#include "dfi_mem_chunk.h"
|
||||||
#include "dfi_vmcoreinfo.h"
|
#include "dfi_vmcoreinfo.h"
|
||||||
|
|
||||||
|
#include "boot/os_info.h"
|
||||||
|
|
||||||
#ifdef __s390x__
|
#ifdef __s390x__
|
||||||
#define LC_VMCORE_INFO 0xe0c
|
#define LC_VMCORE_INFO 0xe0c
|
||||||
#else
|
#else
|
||||||
@@ -27,26 +29,14 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LC_OS_INFO 0xe18
|
#define LC_OS_INFO 0xe18
|
||||||
#define OS_INFO_MAGIC 0x4f53494e464f535aULL /* OSINFOSZ */
|
|
||||||
|
|
||||||
struct os_info {
|
struct vm_info {
|
||||||
u64 magic;
|
u64 identity_base;
|
||||||
u32 csum;
|
u64 kaslr_offset;
|
||||||
u16 version_major;
|
u64 kaslr_offset_phys;
|
||||||
u16 version_minor;
|
u64 amode31_start;
|
||||||
u64 crashkernel_addr;
|
u64 amode31_end;
|
||||||
u64 crashkernel_size;
|
};
|
||||||
u64 vmcoreinfo_addr;
|
|
||||||
u64 vmcoreinfo_size;
|
|
||||||
u32 vmcoreinfo_csum;
|
|
||||||
u64 reipl_block_addr;
|
|
||||||
u64 reipl_block_size;
|
|
||||||
u32 reipl_block_csum;
|
|
||||||
u64 init_fn_addr;
|
|
||||||
u64 init_fn_size;
|
|
||||||
u32 init_fn_csum;
|
|
||||||
u8 reserved[4004];
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* File local static data
|
* File local static data
|
||||||
@@ -54,6 +44,7 @@ struct os_info {
|
|||||||
static struct {
|
static struct {
|
||||||
char *vmcoreinfo;
|
char *vmcoreinfo;
|
||||||
struct os_info *os_info;
|
struct os_info *os_info;
|
||||||
|
struct vm_info *vm_info;
|
||||||
} l;
|
} l;
|
||||||
|
|
||||||
static u32 os_info_csum(struct os_info *os_info)
|
static u32 os_info_csum(struct os_info *os_info)
|
||||||
@@ -71,6 +62,7 @@ static struct os_info *os_info_get(void)
|
|||||||
|
|
||||||
if (dfi_mem_virt_read(LC_OS_INFO, &addr, sizeof(addr)))
|
if (dfi_mem_virt_read(LC_OS_INFO, &addr, sizeof(addr)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
util_log_print(UTIL_LOG_DEBUG, "DFI osinfo addr: 0x%016lx\n", addr);
|
||||||
if (addr % 0x1000)
|
if (addr % 0x1000)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (dfi_mem_virt_read(addr, &os_info, sizeof(os_info)))
|
if (dfi_mem_virt_read(addr, &os_info, sizeof(os_info)))
|
||||||
@@ -79,9 +71,46 @@ static struct os_info *os_info_get(void)
|
|||||||
return NULL;
|
return NULL;
|
||||||
if (os_info.csum != os_info_csum(&os_info))
|
if (os_info.csum != os_info_csum(&os_info))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
util_log_print(UTIL_LOG_DEBUG, "DFI found valid osinfo!\n");
|
||||||
return &os_info;
|
return &os_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct vm_info *vm_info_get(void)
|
||||||
|
{
|
||||||
|
static struct vm_info vm_info = { 0 };
|
||||||
|
|
||||||
|
util_log_print(UTIL_LOG_TRACE, "DFI read vm_info\n");
|
||||||
|
|
||||||
|
vm_info.kaslr_offset = l.os_info->entry[OS_INFO_KASLR_OFFSET].val;
|
||||||
|
if (vm_info.kaslr_offset == 0)
|
||||||
|
return NULL;
|
||||||
|
vm_info.kaslr_offset_phys = l.os_info->entry[OS_INFO_KASLR_OFF_PHYS].val;
|
||||||
|
vm_info.identity_base = l.os_info->entry[OS_INFO_IDENTITY_BASE].val;
|
||||||
|
vm_info.amode31_start = l.os_info->entry[OS_INFO_AMODE31_START].val;
|
||||||
|
vm_info.amode31_end = l.os_info->entry[OS_INFO_AMODE31_END].val;
|
||||||
|
|
||||||
|
return &vm_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert virual address in the dump to the physical address using
|
||||||
|
* vm_info data derived from os_info
|
||||||
|
*/
|
||||||
|
u64 dfi_vm_vtop(u64 vaddr)
|
||||||
|
{
|
||||||
|
if (!l.vm_info)
|
||||||
|
return vaddr;
|
||||||
|
if (vaddr < LOWCORE_SIZE)
|
||||||
|
return vaddr;
|
||||||
|
if ((vaddr < l.vm_info->amode31_end) &&
|
||||||
|
(vaddr >= l.vm_info->amode31_start))
|
||||||
|
return vaddr;
|
||||||
|
if (vaddr < l.vm_info->kaslr_offset)
|
||||||
|
return vaddr - l.vm_info->identity_base;
|
||||||
|
return vaddr - l.vm_info->kaslr_offset + l.vm_info->kaslr_offset_phys;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize vmcoreinfo
|
* Initialize vmcoreinfo
|
||||||
*/
|
*/
|
||||||
@@ -94,11 +123,13 @@ void dfi_vmcoreinfo_init(void)
|
|||||||
util_log_print(UTIL_LOG_TRACE, "DFI vmcoreinfo initialization\n");
|
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.vm_info = vm_info_get();
|
||||||
|
|
||||||
if (l.os_info && l.os_info->vmcoreinfo_size) {
|
if (l.os_info && l.os_info->entry[OS_INFO_VMCOREINFO].size) {
|
||||||
util_log_print(UTIL_LOG_DEBUG, "DFI found valid osinfo\n");
|
util_log_print(UTIL_LOG_DEBUG, "DFI found valid osinfo\n");
|
||||||
addr = l.os_info->vmcoreinfo_addr;
|
addr = l.os_info->entry[OS_INFO_VMCOREINFO].addr;
|
||||||
size = l.os_info->vmcoreinfo_size;
|
size = l.os_info->entry[OS_INFO_VMCOREINFO].size;
|
||||||
} else {
|
} else {
|
||||||
if (dfi_mem_virt_read(LC_VMCORE_INFO, &addr, sizeof(addr)))
|
if (dfi_mem_virt_read(LC_VMCORE_INFO, &addr, sizeof(addr)))
|
||||||
return;
|
return;
|
||||||
@@ -175,6 +206,7 @@ static int vmcoreinfo_item_ulong(unsigned long *val, const char *fmt,
|
|||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = vmcoreinfo_item(str, sizeof(str), fmt, sym);
|
rc = vmcoreinfo_item(str, sizeof(str), fmt, sym);
|
||||||
|
util_log_print(UTIL_LOG_DEBUG, "DFI vmcoreinfo symbol %s : %s\n", sym, str);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
*val = strtoul(str, NULL, base);
|
*val = strtoul(str, NULL, base);
|
||||||
|
|||||||
@@ -16,5 +16,6 @@ int dfi_vmcoreinfo_offset(unsigned long *offs, const char *sym);
|
|||||||
int dfi_vmcoreinfo_size(unsigned long *size, const char *sym);
|
int dfi_vmcoreinfo_size(unsigned long *size, const char *sym);
|
||||||
int dfi_vmcoreinfo_length(unsigned long *len, const char *sym);
|
int dfi_vmcoreinfo_length(unsigned long *len, const char *sym);
|
||||||
int dfi_vmcoreinfo_val(unsigned long *val, const char *sym);
|
int dfi_vmcoreinfo_val(unsigned long *val, const char *sym);
|
||||||
|
u64 dfi_vm_vtop(u64 vaddr);
|
||||||
|
|
||||||
#endif /* DFI_VMCOREINFO_H */
|
#endif /* DFI_VMCOREINFO_H */
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "lib/util_log.h"
|
||||||
|
|
||||||
#include "zg.h"
|
#include "zg.h"
|
||||||
#include "dfi_mem_chunk.h"
|
#include "dfi_mem_chunk.h"
|
||||||
@@ -27,6 +28,10 @@ void dfo_chunk_add(u64 start, u64 size, void *data, dfo_chunk_read_fn read_fn)
|
|||||||
{
|
{
|
||||||
struct dfo_chunk *dfo_chunk;
|
struct dfo_chunk *dfo_chunk;
|
||||||
|
|
||||||
|
util_log_print(UTIL_LOG_DEBUG, "DFO add chunk start=0x%lx, size=0x%lx\n", start, size);
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
return;
|
||||||
dfo_chunk = zg_alloc(sizeof(*dfo_chunk));
|
dfo_chunk = zg_alloc(sizeof(*dfo_chunk));
|
||||||
dfo_chunk->start = start;
|
dfo_chunk->start = start;
|
||||||
dfo_chunk->end = start + size - 1;
|
dfo_chunk->end = start + size - 1;
|
||||||
|
|||||||
+38
-7
@@ -30,6 +30,7 @@
|
|||||||
static struct {
|
static struct {
|
||||||
struct df_s390_hdr hdr;
|
struct df_s390_hdr hdr;
|
||||||
struct df_s390_em em;
|
struct df_s390_em em;
|
||||||
|
u64 dfi_max_end; // Max end address among processed DFI memory chunks
|
||||||
} l;
|
} l;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -159,19 +160,48 @@ static void add_cpu_to_dfo(struct dfi_cpu *cpu)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add memory chunk to dump layout
|
* Add memory chunk to DFO dump layout.
|
||||||
|
* The function is supposed to be called in a loop for each DFI mem chunk in the list.
|
||||||
|
* DFI memory chunk list is considered to be sorted by start address, thus the
|
||||||
|
* input memory chunk coming last has a priority for DFO.
|
||||||
*/
|
*/
|
||||||
static void add_mem_chunk_to_dfo(struct dfi_mem_chunk *mem_chunk)
|
static void add_mem_chunk_to_dfo(struct dfi_mem_chunk *mem_chunk)
|
||||||
{
|
{
|
||||||
struct dfi_mem_chunk *mem_chunk_prev = dfi_mem_chunk_prev(mem_chunk);
|
const u64 dfo_current_memsz = dfo_chunk_dump_size() - DF_S390_HDR_SIZE;
|
||||||
|
|
||||||
if (mem_chunk_prev && (mem_chunk_prev->end + 1 != mem_chunk->start))
|
/*
|
||||||
dfo_chunk_add(mem_chunk_prev->end + 1 + DF_S390_HDR_SIZE,
|
* Consider memory holes and filtered memory pages filling the missing
|
||||||
mem_chunk->start - mem_chunk_prev->end - 1,
|
* areas with zeroes for s390 output format. Keep in mind that dfi_mem_chunks
|
||||||
|
* can overlap for VR-kernel dumps.
|
||||||
|
* If no dfi_mem_chunk with zero start address registered, add
|
||||||
|
* zero DFO memory chunk first.
|
||||||
|
*
|
||||||
|
* See the diagram of resulting dfo_s390 for several cases of input memory
|
||||||
|
* chunks layout below:
|
||||||
|
*
|
||||||
|
* DFI DFO(s390)
|
||||||
|
* ---------------------------------
|
||||||
|
* aaaa.... HDR|aa|bb|cc|cc
|
||||||
|
* ..bbbb..
|
||||||
|
* ....cccc
|
||||||
|
* ---------------------------------
|
||||||
|
* ..aa.... HDR|00|aa|00|bb
|
||||||
|
* ......bb
|
||||||
|
* ---------------------------------
|
||||||
|
* aaaaaaaa HDR|aa|bb|aa|cc
|
||||||
|
* ..bb....
|
||||||
|
* ......cc
|
||||||
|
*/
|
||||||
|
if (l.dfi_max_end < mem_chunk->start &&
|
||||||
|
mem_chunk->start - l.dfi_max_end > 1)
|
||||||
|
dfo_chunk_add(dfo_chunk_dump_size(),
|
||||||
|
mem_chunk->start - dfo_current_memsz,
|
||||||
NULL, dfo_chunk_zero_fn);
|
NULL, dfo_chunk_zero_fn);
|
||||||
|
|
||||||
dfo_chunk_add(mem_chunk->start + DF_S390_HDR_SIZE, mem_chunk->size,
|
dfo_chunk_add(mem_chunk->start + DF_S390_HDR_SIZE, mem_chunk->size,
|
||||||
mem_chunk, dfo_chunk_mem_fn);
|
mem_chunk, dfo_chunk_mem_fn);
|
||||||
|
|
||||||
|
l.dfi_max_end = MAX(mem_chunk->end, l.dfi_max_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -187,7 +217,7 @@ static void dump_chunks_init(void)
|
|||||||
add_mem_chunk_to_dfo(mem_chunk);
|
add_mem_chunk_to_dfo(mem_chunk);
|
||||||
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(l.hdr.mem_size + DF_S390_HDR_SIZE,
|
||||||
DF_S390_EM_SIZE,
|
DF_S390_EM_SIZE,
|
||||||
&l.em, dfo_chunk_buf_fn);
|
&l.em, dfo_chunk_buf_fn);
|
||||||
}
|
}
|
||||||
@@ -209,7 +239,8 @@ static void df_s390_dump_init(void)
|
|||||||
else
|
else
|
||||||
dh->version = 5;
|
dh->version = 5;
|
||||||
dh->mem_start = 0;
|
dh->mem_start = 0;
|
||||||
dh->mem_size = dh->mem_end = dfi_mem_range();
|
dh->mem_end = dfi_mem_end();
|
||||||
|
dh->mem_size = dh->mem_end + 1;
|
||||||
dh->num_pages = dh->mem_size / PAGE_SIZE;
|
dh->num_pages = dh->mem_size / PAGE_SIZE;
|
||||||
dh->arch = df_s390_from_dfi_arch(dfi_arch());
|
dh->arch = df_s390_from_dfi_arch(dfi_arch());
|
||||||
if (dfi_attr_build_arch())
|
if (dfi_attr_build_arch())
|
||||||
|
|||||||
@@ -435,6 +435,13 @@ static int ngdump_get_eckd_part_num(struct zg_fh *zg_fh)
|
|||||||
if (!is_vol1(vl.vollbl))
|
if (!is_vol1(vl.vollbl))
|
||||||
return -1;
|
return -1;
|
||||||
/* Read Master Boot Record and check its magic */
|
/* Read Master Boot Record and check its magic */
|
||||||
|
if (vl.br.cc == 0x4040 && vl.br.hh == 0x4040 &&
|
||||||
|
vl.br.b == 0x40) {
|
||||||
|
util_log_print(UTIL_LOG_TRACE,
|
||||||
|
"%s: No boot record pointer found in volume label\n",
|
||||||
|
__func__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
blk = cchhb2blk(&vl.br, &geo);
|
blk = cchhb2blk(&vl.br, &geo);
|
||||||
if (blk == 0)
|
if (blk == 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
+1
-1
@@ -35,7 +35,7 @@ zfcpdump_part: zfcpdump.o zfcpdump_part.o
|
|||||||
|
|
||||||
$(ZFCPDUMP_INITRD): cpioinit zfcpdump_part
|
$(ZFCPDUMP_INITRD): cpioinit zfcpdump_part
|
||||||
$(CPIOINIT) zfcpdump_part > $@.tmp
|
$(CPIOINIT) zfcpdump_part > $@.tmp
|
||||||
$(GZIP) -f $@.tmp
|
$(GZIP) -f -n $@.tmp
|
||||||
$(MV) $@.tmp.gz $(ZFCPDUMP_INITRD)
|
$(MV) $@.tmp.gz $(ZFCPDUMP_INITRD)
|
||||||
|
|
||||||
scripts: $(INSTALL_SCRIPTS)
|
scripts: $(INSTALL_SCRIPTS)
|
||||||
|
|||||||
+23
-18
@@ -24,7 +24,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <sys/reboot.h>
|
#include <sys/reboot.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@@ -294,32 +293,38 @@ static int copy_table_init(int fd, struct copy_table *table)
|
|||||||
*/
|
*/
|
||||||
static int copy_table_entry_write(int fdin, int fdout,
|
static int copy_table_entry_write(int fdin, int fdout,
|
||||||
const struct copy_table_entry *entry,
|
const struct copy_table_entry *entry,
|
||||||
unsigned long offset)
|
unsigned long disk_offset)
|
||||||
{
|
{
|
||||||
unsigned long buf_size, bytes_left, off;
|
static unsigned char buf[COPY_BUF_SIZE];
|
||||||
void *map;
|
unsigned long bytes_left, count;
|
||||||
|
ssize_t bytes_read, bytes_written;
|
||||||
|
|
||||||
if (entry->size == 0)
|
|
||||||
return 0;
|
|
||||||
off = entry->off;
|
|
||||||
bytes_left = entry->size;
|
bytes_left = entry->size;
|
||||||
if (lseek(fdout, entry->off + offset, SEEK_SET) < 0)
|
if (bytes_left == 0)
|
||||||
|
return 0;
|
||||||
|
if (lseek(fdin, entry->off, SEEK_SET) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
if (lseek(fdout, disk_offset + entry->off, SEEK_SET) < 0)
|
||||||
|
return -1;
|
||||||
|
PRINT_TRACE("Write dump: vmcore offset=0x%016lx disk offset=0x%016lx bytes=0x%016lx\n",
|
||||||
|
entry->off, disk_offset + entry->off, bytes_left);
|
||||||
while (bytes_left > 0) {
|
while (bytes_left > 0) {
|
||||||
buf_size = MIN(COPY_BUF_SIZE, bytes_left);
|
count = MIN(COPY_BUF_SIZE, bytes_left);
|
||||||
map = mmap(0, buf_size, PROT_READ, MAP_SHARED, fdin, off);
|
bytes_read = read(fdin, buf, count);
|
||||||
if (map == (void *)-1) {
|
if (bytes_read < 0) {
|
||||||
PRINT_PERR("Mapping failed\n");
|
PRINT_PERR("Read from /proc/vmcore failed: offset=0x%016lx bytes=0x%016lx\n",
|
||||||
|
entry->off + entry->size - bytes_left, count);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (write(fdout, map, buf_size) < 0) {
|
bytes_written = write(fdout, buf, bytes_read);
|
||||||
PRINT_PERR("Write to partition failed\n");
|
if (bytes_written < 0) {
|
||||||
|
PRINT_PERR("Write to partition failed: offset=0x%016lx bytes=0x%016lx\n",
|
||||||
|
disk_offset + entry->off + entry->size - bytes_left,
|
||||||
|
bytes_read);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
munmap(map, buf_size);
|
bytes_left -= bytes_written;
|
||||||
bytes_left -= buf_size;
|
show_progress(bytes_written);
|
||||||
off += buf_size;
|
|
||||||
show_progress(buf_size);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -667,8 +667,7 @@ function check_free_space_mileage() {
|
|||||||
|
|
||||||
|
|
||||||
function check_blktrace() {
|
function check_blktrace() {
|
||||||
which blktrace >/dev/null 2>&1;
|
if ! command -v blktrace >/dev/null 2>&1; then
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "$WRP_TOOLNAME: Could not find blktrace. Please make sure that the blktrace package is installed and matches the level in the documentation.";
|
echo "$WRP_TOOLNAME: Could not find blktrace. Please make sure that the blktrace package is installed and matches the level in the documentation.";
|
||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ int add_to_agg(struct aggr_data *agg_data, struct message *msg,
|
|||||||
else if (msg->type == f_hdr->msgid_zfcpdd)
|
else if (msg->type == f_hdr->msgid_zfcpdd)
|
||||||
aggregate_zfcpdd(agg_data, msg);
|
aggregate_zfcpdd(agg_data, msg);
|
||||||
else {
|
else {
|
||||||
fprintf(stderr, "%s: Unknow msg id: %d,"
|
fprintf(stderr, "%s: Unknown msg id: %d,"
|
||||||
" discarding\n", toolname, msg->type);
|
" discarding\n", toolname, msg->type);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#
|
#
|
||||||
# Script to list the FCP, SCSI and multipath configuration
|
# Script to list the FCP, SCSI and multipath configuration
|
||||||
#
|
#
|
||||||
# Copyright IBM Corp. 2008, 2017
|
# Copyright IBM Corp. 2008, 2024
|
||||||
#
|
#
|
||||||
# s390-tools is free software; you can redistribute it and/or modify
|
# 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.
|
||||||
@@ -130,8 +130,8 @@ sub get_device_data
|
|||||||
unless(!$devices{$hctl}{dev});
|
unless(!$devices{$hctl}{dev});
|
||||||
$devices{$hctl}{mm} = get_line("dev");
|
$devices{$hctl}{mm} = get_line("dev");
|
||||||
$devices{$hctl}{mp_dev} = glob_last("holders", "dm*");
|
$devices{$hctl}{mp_dev} = glob_last("holders", "dm*");
|
||||||
$devices{$hctl}{mp_dev} =~ s/.*\/(.+)\Z/$1/
|
next if !defined $devices{$hctl}{mp_dev};
|
||||||
unless (!$devices{$hctl}{mp_dev});
|
$devices{$hctl}{mp_dev} =~ s/.*\/(.+)\Z/$1/;
|
||||||
$c_src = catdir($base_dir, "sys", "block",
|
$c_src = catdir($base_dir, "sys", "block",
|
||||||
$devices{$hctl}{mp_dev});
|
$devices{$hctl}{mp_dev});
|
||||||
$devices{$hctl}{mp_dev_mm} = get_line("dev");
|
$devices{$hctl}{mp_dev_mm} = get_line("dev");
|
||||||
@@ -297,7 +297,7 @@ sub mapper_report
|
|||||||
"=====================================================\n";
|
"=====================================================\n";
|
||||||
}
|
}
|
||||||
foreach my $hctl (sort keys %devices) {
|
foreach my $hctl (sort keys %devices) {
|
||||||
next if (! $devices{$hctl}{mp_dev});
|
next if (!defined $devices{$hctl}{mp_dev});
|
||||||
next if (@$adapters && "@$adapters" !~ /\b$devices{$hctl}{hba_id}\b/);
|
next if (@$adapters && "@$adapters" !~ /\b$devices{$hctl}{hba_id}\b/);
|
||||||
next if (@$ports && "@$ports" !~ /\b$devices{$hctl}{wwpn}\b/);
|
next if (@$ports && "@$ports" !~ /\b$devices{$hctl}{wwpn}\b/);
|
||||||
next if (@$s_devs && "@$s_devs" !~ /\b$devices{$hctl}{dev}\b/);
|
next if (@$s_devs && "@$s_devs" !~ /\b$devices{$hctl}{dev}\b/);
|
||||||
@@ -391,7 +391,7 @@ MSG
|
|||||||
|
|
||||||
sub version {
|
sub version {
|
||||||
print "$PROGRAM_NAME: version %S390_TOOLS_VERSION%\n";
|
print "$PROGRAM_NAME: version %S390_TOOLS_VERSION%\n";
|
||||||
print "Copyright IBM Corp. 2008, 2017\n";
|
print "Copyright IBM Corp. 2008, 2024\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
sub unpack_config
|
sub unpack_config
|
||||||
|
|||||||
@@ -72,5 +72,6 @@ SECTIONS
|
|||||||
*(.eh_frame)
|
*(.eh_frame)
|
||||||
*(.interp)
|
*(.interp)
|
||||||
*(.note.GNU-stack)
|
*(.note.GNU-stack)
|
||||||
|
*(.note.package)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,5 +14,6 @@ SECTIONS
|
|||||||
*(.eh_frame)
|
*(.eh_frame)
|
||||||
*(.interp)
|
*(.interp)
|
||||||
*(.note.GNU-stack)
|
*(.note.GNU-stack)
|
||||||
|
*(.note.package)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,5 +14,6 @@ SECTIONS
|
|||||||
*(.eh_frame)
|
*(.eh_frame)
|
||||||
*(.interp)
|
*(.interp)
|
||||||
*(.note.GNU-stack)
|
*(.note.GNU-stack)
|
||||||
|
*(.note.package)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,5 +14,6 @@ SECTIONS
|
|||||||
*(.eh_frame)
|
*(.eh_frame)
|
||||||
*(.interp)
|
*(.interp)
|
||||||
*(.note.GNU-stack)
|
*(.note.GNU-stack)
|
||||||
|
*(.note.package)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,5 +93,6 @@ SECTIONS
|
|||||||
*(.eh_frame)
|
*(.eh_frame)
|
||||||
*(.interp)
|
*(.interp)
|
||||||
*(.note.GNU-stack)
|
*(.note.GNU-stack)
|
||||||
|
*(.note.package)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,5 +74,6 @@ SECTIONS
|
|||||||
*(.eh_frame)
|
*(.eh_frame)
|
||||||
*(.interp)
|
*(.interp)
|
||||||
*(.note.GNU-stack)
|
*(.note.GNU-stack)
|
||||||
|
*(.note.package)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-10
@@ -53,16 +53,22 @@ typedef enum {
|
|||||||
disk_type_eckd_cdl,
|
disk_type_eckd_cdl,
|
||||||
} disk_type_t;
|
} disk_type_t;
|
||||||
|
|
||||||
|
struct disk_ext_type {
|
||||||
|
disk_type_t type;
|
||||||
|
bool is_nvme;
|
||||||
|
};
|
||||||
|
|
||||||
/* targetbase definition */
|
/* targetbase definition */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
defined_as_device,
|
defined_as_device,
|
||||||
defined_as_name
|
defined_as_name,
|
||||||
|
undefined
|
||||||
} definition_t;
|
} definition_t;
|
||||||
|
|
||||||
/* Disk information type */
|
/* Disk information type */
|
||||||
struct disk_info {
|
struct disk_info {
|
||||||
disk_type_t type;
|
disk_type_t type;
|
||||||
dev_t device;
|
dev_t device; /* logical device for bootmap creation */
|
||||||
dev_t partition;
|
dev_t partition;
|
||||||
int devno;
|
int devno;
|
||||||
int partnum;
|
int partnum;
|
||||||
@@ -72,8 +78,11 @@ struct disk_info {
|
|||||||
struct hd_geometry geo;
|
struct hd_geometry geo;
|
||||||
char* name;
|
char* name;
|
||||||
char* drv_name;
|
char* drv_name;
|
||||||
definition_t targetbase;
|
definition_t targetbase_def;
|
||||||
int is_nvme;
|
int is_nvme;
|
||||||
|
dev_t basedisks[MAX_TARGETS]; /* array of physical disks for
|
||||||
|
* bootstrap blocks recording
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
struct file_range {
|
struct file_range {
|
||||||
@@ -83,12 +92,15 @@ struct file_range {
|
|||||||
|
|
||||||
struct job_target_data;
|
struct job_target_data;
|
||||||
|
|
||||||
int disk_get_info(const char* device, struct job_target_data* target,
|
int disk_get_info(const char *device, struct job_target_data *target,
|
||||||
struct disk_info** info);
|
struct disk_info **info);
|
||||||
int disk_is_tape(const char* device);
|
int disk_get_ext_type(const char *device, struct disk_ext_type *ext_type);
|
||||||
int disk_is_scsi(const char* device, struct job_target_data* target);
|
int disk_is_tape(const char *device);
|
||||||
int disk_is_eckd_ldl(const char* device, struct job_target_data* target);
|
int disk_type_is_scsi(struct disk_ext_type *ext_type);
|
||||||
int disk_is_nvme(const char* device, struct job_target_data* target);
|
int disk_type_is_eckd_ldl(struct disk_ext_type *ext_type);
|
||||||
|
int disk_type_is_nvme(struct disk_ext_type *ext_type);
|
||||||
|
int disk_type_is_eckd(disk_type_t type);
|
||||||
|
|
||||||
int disk_get_info_from_file(const char* filename,
|
int disk_get_info_from_file(const char* filename,
|
||||||
struct job_target_data* target,
|
struct job_target_data* target,
|
||||||
struct disk_info** info);
|
struct disk_info** info);
|
||||||
@@ -113,6 +125,9 @@ blocknum_t disk_write_block_buffer_align(int fd, int fd_is_basedisk,
|
|||||||
struct disk_info *info, int align,
|
struct disk_info *info, int align,
|
||||||
off_t *offset);
|
off_t *offset);
|
||||||
void disk_print_devt(dev_t d);
|
void disk_print_devt(dev_t d);
|
||||||
|
void disk_print_devname(dev_t d);
|
||||||
|
void prepare_footnote_ptr(int source, char *ptr);
|
||||||
|
void print_footnote_ref(int source, const char *prefix);
|
||||||
void disk_print_info(struct disk_info *info, int source);
|
void disk_print_info(struct disk_info *info, int source);
|
||||||
int disk_is_zero_block(disk_blockptr_t* block, struct disk_info* info);
|
int disk_is_zero_block(disk_blockptr_t* block, struct disk_info* info);
|
||||||
blocknum_t disk_compact_blocklist(disk_blockptr_t* list, blocknum_t count,
|
blocknum_t disk_compact_blocklist(disk_blockptr_t* list, blocknum_t count,
|
||||||
@@ -122,7 +137,6 @@ blocknum_t disk_get_blocklist_from_file(const char* filename,
|
|||||||
disk_blockptr_t** blocklist,
|
disk_blockptr_t** blocklist,
|
||||||
struct disk_info* pinfo);
|
struct disk_info* pinfo);
|
||||||
int disk_check_subchannel_set(int devno, dev_t device, char* dev_name);
|
int disk_check_subchannel_set(int devno, dev_t device, char* dev_name);
|
||||||
void disk_print_geo(struct disk_info *data);
|
|
||||||
int fs_map(int fd, uint64_t offset, blocknum_t *mapped, int fs_block_size);
|
int fs_map(int fd, uint64_t offset, blocknum_t *mapped, int fs_block_size);
|
||||||
|
|
||||||
#endif /* not DISK_H */
|
#endif /* not DISK_H */
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ struct install_set {
|
|||||||
struct program_component *components[NR_PROGRAM_COMPONENTS];
|
struct program_component *components[NR_PROGRAM_COMPONENTS];
|
||||||
int nr_menu_entries;
|
int nr_menu_entries;
|
||||||
int fd;
|
int fd;
|
||||||
char *device;
|
char *basetmp[MAX_TARGETS];
|
||||||
char *filename;
|
char *filename;
|
||||||
unsigned int tmp_filename_created:1;
|
unsigned int tmp_filename_created:1;
|
||||||
unsigned int skip_prepare:1;
|
unsigned int skip_prepare:1;
|
||||||
|
|||||||
+115
-12
@@ -18,7 +18,6 @@
|
|||||||
#include "disk.h"
|
#include "disk.h"
|
||||||
#include "zipl.h"
|
#include "zipl.h"
|
||||||
|
|
||||||
|
|
||||||
enum job_id {
|
enum job_id {
|
||||||
job_print_usage = 1,
|
job_print_usage = 1,
|
||||||
job_print_version = 2,
|
job_print_version = 2,
|
||||||
@@ -30,6 +29,21 @@ enum job_id {
|
|||||||
job_mvdump = 8,
|
job_mvdump = 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set of parameters per physical disk, which are provided
|
||||||
|
* either by user, or by helper script
|
||||||
|
*/
|
||||||
|
struct target {
|
||||||
|
char *targetbase;
|
||||||
|
disk_type_t targettype;
|
||||||
|
int targetcylinders;
|
||||||
|
int targetheads;
|
||||||
|
int targetsectors;
|
||||||
|
int targetblocksize;
|
||||||
|
blocknum_t targetoffset;
|
||||||
|
int check_params;
|
||||||
|
};
|
||||||
|
|
||||||
/* target information source */
|
/* target information source */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
source_unknown = 0,
|
source_unknown = 0,
|
||||||
@@ -39,17 +53,21 @@ typedef enum {
|
|||||||
} source_t;
|
} source_t;
|
||||||
|
|
||||||
struct job_target_data {
|
struct job_target_data {
|
||||||
char* bootmap_dir;
|
char *bootmap_dir;
|
||||||
char* targetbase;
|
int nr_targets;
|
||||||
disk_type_t targettype;
|
struct target targets[MAX_TARGETS];
|
||||||
int targetcylinders;
|
|
||||||
int targetheads;
|
|
||||||
int targetsectors;
|
|
||||||
int targetblocksize;
|
|
||||||
blocknum_t targetoffset;
|
|
||||||
source_t source;
|
source_t source;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum target_params {
|
||||||
|
TARGET_BASE,
|
||||||
|
TARGET_TYPE,
|
||||||
|
TARGET_GEOMETRY,
|
||||||
|
TARGET_BLOCKSIZE,
|
||||||
|
TARGET_OFFSET,
|
||||||
|
LAST_TARGET_PARAM
|
||||||
|
};
|
||||||
|
|
||||||
struct job_common_ipl_data {
|
struct job_common_ipl_data {
|
||||||
char* image;
|
char* image;
|
||||||
char* parmline;
|
char* parmline;
|
||||||
@@ -81,6 +99,7 @@ struct job_dump_data {
|
|||||||
struct job_common_ipl_data common;
|
struct job_common_ipl_data common;
|
||||||
char* device;
|
char* device;
|
||||||
uint64_t mem;
|
uint64_t mem;
|
||||||
|
bool is_ngdump;
|
||||||
bool no_compress;
|
bool no_compress;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -142,12 +161,94 @@ struct job_data {
|
|||||||
int is_ldipl_dump;
|
int is_ldipl_dump;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline struct target *target_at(struct job_target_data *data,
|
||||||
|
int index)
|
||||||
|
{
|
||||||
|
return index >= MAX_TARGETS ? NULL : &data->targets[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline char *get_targetbase(struct job_target_data *data, int index)
|
||||||
|
{
|
||||||
|
return target_at(data, index)->targetbase;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void set_targetbase(struct job_target_data *data, int index,
|
||||||
|
char *value)
|
||||||
|
{
|
||||||
|
target_at(data, index)->targetbase = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline disk_type_t get_targettype(struct job_target_data *data,
|
||||||
|
int index)
|
||||||
|
{
|
||||||
|
return target_at(data, index)->targettype;
|
||||||
|
}
|
||||||
|
|
||||||
|
int set_targettype(struct job_target_data *data, int index, char *value);
|
||||||
|
|
||||||
|
static inline char *job_get_targetbase(struct job_data *job)
|
||||||
|
{
|
||||||
|
return get_targetbase(&job->target, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void job_set_targetbase(struct job_data *job, char *value)
|
||||||
|
{
|
||||||
|
set_targetbase(&job->target, 0, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int job_get_nr_targets(struct job_data *job)
|
||||||
|
{
|
||||||
|
return job->target.nr_targets;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void job_set_nr_targets(struct job_data *job, int value)
|
||||||
|
{
|
||||||
|
job->target.nr_targets = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline disk_type_t job_get_targettype(struct job_data *job)
|
||||||
|
{
|
||||||
|
return get_targettype(&job->target, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int job_set_targettype(struct job_data *job, char *value);
|
||||||
|
|
||||||
|
#define define_target_param_ops(_TYPE_, _PARAM_) \
|
||||||
|
static inline _TYPE_ get_target##_PARAM_(struct job_target_data *data, \
|
||||||
|
int index) \
|
||||||
|
{ \
|
||||||
|
return target_at(data, index)->target##_PARAM_; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline void set_target##_PARAM_(struct job_target_data *data, \
|
||||||
|
int index, _TYPE_ value) \
|
||||||
|
{ \
|
||||||
|
target_at(data, index)->target##_PARAM_ = value; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline _TYPE_ job_get_target##_PARAM_(struct job_data *job) \
|
||||||
|
{ \
|
||||||
|
return get_target##_PARAM_(&job->target, 0); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline void job_set_target##_PARAM_(struct job_data *job, \
|
||||||
|
_TYPE_ value) \
|
||||||
|
{ \
|
||||||
|
set_target##_PARAM_(&job->target, 0, value); \
|
||||||
|
}
|
||||||
|
|
||||||
|
define_target_param_ops(int, cylinders)
|
||||||
|
define_target_param_ops(int, heads)
|
||||||
|
define_target_param_ops(int, sectors)
|
||||||
|
define_target_param_ops(int, blocksize)
|
||||||
|
define_target_param_ops(blocknum_t, offset)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true, if target parameters for the base disk are set
|
* Return true, if target parameters are set at least for one target base disk
|
||||||
*/
|
*/
|
||||||
static inline int target_parameters_are_set(struct job_target_data *td)
|
static inline int target_parameters_are_set(struct job_target_data *td)
|
||||||
{
|
{
|
||||||
return td->targetbase != NULL;
|
return get_targetbase(td, 0) != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int job_get(int argc, char* argv[], struct job_data** data);
|
int job_get(int argc, char* argv[], struct job_data** data);
|
||||||
@@ -156,6 +257,8 @@ void free_target_data(struct job_target_data *td);
|
|||||||
int type_from_target(char *target, disk_type_t *type);
|
int type_from_target(char *target, disk_type_t *type);
|
||||||
int check_job_dump_images(struct job_dump_data* dump, char* name);
|
int check_job_dump_images(struct job_dump_data* dump, char* name);
|
||||||
int check_job_images_ngdump(struct job_dump_data* dump, char* name);
|
int check_job_images_ngdump(struct job_dump_data* dump, char* name);
|
||||||
bool is_ngdump_enabled(struct job_data *job);
|
void job_dump_check_set_ngdump(struct job_data *job,
|
||||||
|
struct disk_ext_type *ext_type);
|
||||||
|
bool job_dump_is_ngdump(struct job_data *job);
|
||||||
|
|
||||||
#endif /* not JOB_H */
|
#endif /* not JOB_H */
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
#define MENU_DEFAULT_TIMEOUT 0
|
#define MENU_DEFAULT_TIMEOUT 0
|
||||||
|
|
||||||
#define MAX_DUMP_VOLUMES 32
|
#define MAX_DUMP_VOLUMES 32
|
||||||
|
#define MAX_TARGETS 32
|
||||||
|
|
||||||
#define SECURE_BOOT_UNDEFINED -1
|
#define SECURE_BOOT_UNDEFINED -1
|
||||||
#define SECURE_BOOT_DISABLED 0
|
#define SECURE_BOOT_DISABLED 0
|
||||||
|
|||||||
+7
-3
@@ -13,21 +13,25 @@ objects = misc.o error.o scan.o job.o boot.o bootmap.o fs-map.o disk.o \
|
|||||||
bootmap_header.o envblk.o install.o zipl.o
|
bootmap_header.o envblk.o install.o zipl.o
|
||||||
|
|
||||||
zipl_helpers = $(basename $(wildcard zipl_helper.*.c))
|
zipl_helpers = $(basename $(wildcard zipl_helper.*.c))
|
||||||
|
zipl_helpers += zipl_helper.md
|
||||||
chreipl_helpers = $(subst zipl_,chreipl_, $(zipl_helpers))
|
chreipl_helpers = $(subst zipl_,chreipl_, $(zipl_helpers))
|
||||||
|
|
||||||
all: zipl zipl-editenv $(chreipl_helpers)
|
all: zipl zipl-editenv zipl_helper.md $(chreipl_helpers)
|
||||||
|
|
||||||
boot.o: ../boot/.loaders
|
boot.o: ../boot/.loaders
|
||||||
zipl: $(objects) $(libs)
|
zipl: $(objects) $(libs)
|
||||||
|
|
||||||
zipl_helper.device-mapper: $(rootdir)/libdasd/libdasd.a \
|
zipl_helper.device-mapper: $(rootdir)/libdasd/libdasd.a \
|
||||||
$(rootdir)/libvtoc/libvtoc.a \
|
$(rootdir)/libvtoc/libvtoc.a \
|
||||||
$(libs) zipl_helper.device-mapper.o
|
$(libs) misc.o error.o zipl_helper.device-mapper.o
|
||||||
|
|
||||||
zipl-editenv: $(libs) misc.o error.o fs-map.o bootmap_header.o \
|
zipl-editenv: $(libs) misc.o error.o fs-map.o bootmap_header.o \
|
||||||
envblk.o zipl-editenv.o
|
envblk.o zipl-editenv.o
|
||||||
|
|
||||||
chreipl_helper.%: zipl_helper.%
|
zipl_helper.md: zipl_helper.device-mapper
|
||||||
|
ln -f -s $< $@
|
||||||
|
|
||||||
|
chreipl_helper.%: zipl_helper.device-mapper
|
||||||
ln -f -s $< $@
|
ln -f -s $< $@
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
|
|||||||
+102
-116
@@ -298,6 +298,47 @@ create_component_header(void* buffer, component_header_type type)
|
|||||||
header->type = (uint8_t) type;
|
header->type = (uint8_t) type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Not precise check that the file FILENAME locates on specified physical DISK.
|
||||||
|
*
|
||||||
|
* Try to auto-detect parameters of the disk which the file locates on
|
||||||
|
* and compare found device-ID with DISK.
|
||||||
|
* Return 0, if auto-detection succeeded, and it is proven that the
|
||||||
|
* file does NOT locate on DISK. Otherwise, return 1.
|
||||||
|
*/
|
||||||
|
static int file_is_on_disk(const char *filename, dev_t disk)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Retrieve info of the underlying disk without any user hints
|
||||||
|
*/
|
||||||
|
struct job_target_data tmp = {.source = source_unknown};
|
||||||
|
struct disk_info *info;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = disk_get_info_from_file(filename, &tmp, &info);
|
||||||
|
free_target_data(&tmp);
|
||||||
|
if (rc) {
|
||||||
|
/*
|
||||||
|
* In some cases it is impossible to auto-detect
|
||||||
|
* disk parameters (e.g. when the file is on a
|
||||||
|
* mounted qcow2 image).
|
||||||
|
* Skip the check with warnings.
|
||||||
|
*/
|
||||||
|
fprintf(stderr,
|
||||||
|
"Warning: Could not auto-detect disk parameters for %s\n",
|
||||||
|
filename);
|
||||||
|
fprintf(stderr,
|
||||||
|
"Warning: Preparing a logical device for boot might fail\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (info->device != disk) {
|
||||||
|
disk_free_info(info);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
disk_free_info(info);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int add_component_file_range(struct install_set *bis,
|
static int add_component_file_range(struct install_set *bis,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
struct file_range *reg,
|
struct file_range *reg,
|
||||||
@@ -311,7 +352,6 @@ static int add_component_file_range(struct install_set *bis,
|
|||||||
struct component_loc *location = &pc->loc;
|
struct component_loc *location = &pc->loc;
|
||||||
disk_blockptr_t **list = &pc->list;
|
disk_blockptr_t **list = &pc->list;
|
||||||
blocknum_t *count = &pc->count;
|
blocknum_t *count = &pc->count;
|
||||||
struct disk_info* file_info;
|
|
||||||
disk_blockptr_t segment;
|
disk_blockptr_t segment;
|
||||||
char* buffer;
|
char* buffer;
|
||||||
size_t size;
|
size_t size;
|
||||||
@@ -338,26 +378,13 @@ static int add_component_file_range(struct install_set *bis,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/*
|
if (!file_is_on_disk(filename, bis->info->device)) {
|
||||||
* Make sure that file is on target device.
|
|
||||||
* For this, retrieve info of the underlying disk without
|
|
||||||
* any user hints
|
|
||||||
*/
|
|
||||||
struct job_target_data tmp = {.source = source_unknown};
|
|
||||||
|
|
||||||
rc = disk_get_info_from_file(filename, &tmp, &file_info);
|
|
||||||
free_target_data(&tmp);
|
|
||||||
if (rc)
|
|
||||||
return -1;
|
|
||||||
if (file_info->device != bis->info->device) {
|
|
||||||
disk_free_info(file_info);
|
|
||||||
error_reason("File is not on target device");
|
error_reason("File is not on target device");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* Get block list from existing file */
|
/* Get block list from existing file */
|
||||||
*count = disk_get_blocklist_from_file(filename, reg,
|
*count = disk_get_blocklist_from_file(filename, reg,
|
||||||
list, file_info);
|
list, bis->info);
|
||||||
disk_free_info(file_info);
|
|
||||||
if (*count == 0)
|
if (*count == 0)
|
||||||
return -1;
|
return -1;
|
||||||
*count -= DIV_ROUND_UP(trailer, bis->info->phy_block_size);
|
*count -= DIV_ROUND_UP(trailer, bis->info->phy_block_size);
|
||||||
@@ -942,62 +969,20 @@ static int add_segment_program(struct install_set *bis,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define DUMP_PARAM_MAX_LEN 896
|
#define DUMP_PARAM_MAX_LEN 896
|
||||||
|
|
||||||
static int
|
static int add_dump_program(struct install_set *bis,
|
||||||
check_dump_device_late(char *partition, struct disk_info *target_info,
|
const struct job_dump_data *dump,
|
||||||
struct job_target_data *target,
|
|
||||||
struct job_data *job)
|
|
||||||
{
|
|
||||||
struct disk_info* info;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
/* Get information about partition */
|
|
||||||
rc = disk_get_info(partition, target, &info);
|
|
||||||
if (rc) {
|
|
||||||
error_text("Could not get information for dump partition '%s'",
|
|
||||||
partition);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
if ((job->is_ldipl_dump && info->type != disk_type_eckd_cdl) ||
|
|
||||||
(!job->is_ldipl_dump && info->type != disk_type_scsi) ||
|
|
||||||
info->partnum == 0) {
|
|
||||||
error_reason("Device '%s' is not a SCSI or DASD partition",
|
|
||||||
partition);
|
|
||||||
disk_free_info(info);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (info->device != target_info->device) {
|
|
||||||
error_reason("Target directory is not on same device as "
|
|
||||||
"'%s'", partition);
|
|
||||||
disk_free_info(info);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
disk_free_info(info);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int add_dump_program(struct install_set *bis, struct job_data *job,
|
|
||||||
disk_blockptr_t *program, int verbose,
|
disk_blockptr_t *program, int verbose,
|
||||||
component_header_type type,
|
component_header_type type,
|
||||||
int program_table_id)
|
int program_table_id)
|
||||||
{
|
{
|
||||||
struct job_dump_data *dump = &job->data.dump;
|
|
||||||
struct job_target_data *target = &job->target;
|
|
||||||
struct job_ipl_data ipl;
|
struct job_ipl_data ipl;
|
||||||
int rc;
|
|
||||||
|
|
||||||
/* Convert fs dump job to IPL job */
|
/* Convert fs dump job to IPL job */
|
||||||
memset(&ipl, 0, sizeof(ipl));
|
memset(&ipl, 0, sizeof(ipl));
|
||||||
ipl.common = dump->common;
|
ipl.common = dump->common;
|
||||||
|
|
||||||
/* Get file system dump parmline */
|
|
||||||
rc = check_dump_device_late(dump->device, bis->info, target, job);
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
ipl.common.parmline = dump->common.parmline;
|
|
||||||
ipl.common.parm_addr = dump->common.parm_addr;
|
|
||||||
return add_ipl_program(bis, NULL, false, NULL, &ipl, program,
|
return add_ipl_program(bis, NULL, false, NULL, &ipl, program,
|
||||||
verbose, 1, type, SECURE_BOOT_DISABLED,
|
verbose, 1, type, SECURE_BOOT_DISABLED,
|
||||||
0 /* menu_idx */, program_table_id);
|
0 /* menu_idx */, program_table_id);
|
||||||
@@ -1068,7 +1053,7 @@ static int build_program_table(struct job_data *job,
|
|||||||
printf("Adding dump section '%s' (default)\n",
|
printf("Adding dump section '%s' (default)\n",
|
||||||
job->name);
|
job->name);
|
||||||
}
|
}
|
||||||
rc = add_dump_program(bis, job, &table[0],
|
rc = add_dump_program(bis, &job->data.dump, &table[0],
|
||||||
verbose || job->command_line,
|
verbose || job->command_line,
|
||||||
COMPONENT_HEADER_DUMP,
|
COMPONENT_HEADER_DUMP,
|
||||||
program_table_id);
|
program_table_id);
|
||||||
@@ -1381,7 +1366,7 @@ estimate_scsi_dump_size(struct job_data *job, struct disk_info *info, ulong *dum
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check that disk is appropriate for the JOB
|
* Check that disk with retrieved INFO is appropriate for the JOB
|
||||||
*/
|
*/
|
||||||
static int disk_is_appropriate(const struct job_data *job,
|
static int disk_is_appropriate(const struct job_data *job,
|
||||||
const struct disk_info *info)
|
const struct disk_info *info)
|
||||||
@@ -1392,11 +1377,31 @@ static int disk_is_appropriate(const struct job_data *job,
|
|||||||
error_reason("Secure boot forced for improper disk type");
|
error_reason("Secure boot forced for improper disk type");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (job->id == job_dump_partition &&
|
/* common checks */
|
||||||
job->is_ldipl_dump &&
|
if (job->target.source == source_auto &&
|
||||||
info->type != disk_type_eckd_cdl) {
|
info->type == disk_type_diag) {
|
||||||
error_reason("List-directed dump not support on DASD with LDL format");
|
error_reason("Unsupported disk type (%s)",
|
||||||
return 0;
|
disk_get_type_name(info->type));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* job-specific checks */
|
||||||
|
if (job->id == job_dump_partition) {
|
||||||
|
if (job->is_ldipl_dump && info->type != disk_type_eckd_cdl) {
|
||||||
|
error_reason("Inappropriate dump device (not DASD-CDL)");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!job->is_ldipl_dump && info->type != disk_type_scsi) {
|
||||||
|
error_reason("Inappropriate dump device (not SCSI)");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Check that data starts beyond the boot area on the base disk.
|
||||||
|
* In case of source_script the check is performed by the script
|
||||||
|
*/
|
||||||
|
if (job->target.source == source_auto && info->partnum == 0) {
|
||||||
|
error_reason("Dump device %s is not a partition",
|
||||||
|
job->data.dump.device);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1407,19 +1412,10 @@ check_dump_device(struct job_data *job, const struct disk_info *info,
|
|||||||
{
|
{
|
||||||
int rc, part_ext;
|
int rc, part_ext;
|
||||||
|
|
||||||
/* Check for supported disk and driver types */
|
|
||||||
if (job->target.source == source_auto &&
|
|
||||||
info->type == disk_type_diag) {
|
|
||||||
error_reason("Unsupported disk type (%s)",
|
|
||||||
disk_get_type_name(info->type));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!disk_is_appropriate(job, info))
|
if (!disk_is_appropriate(job, info))
|
||||||
return -1;
|
return -1;
|
||||||
|
if (job_dump_is_ngdump(job))
|
||||||
if (is_ngdump_enabled(job))
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
rc = util_part_search(device, info->geo.start,
|
rc = util_part_search(device, info->geo.start,
|
||||||
info->phy_blocks, info->phy_block_size, &part_ext);
|
info->phy_blocks, info->phy_block_size, &part_ext);
|
||||||
if (rc <= 0 || part_ext) {
|
if (rc <= 0 || part_ext) {
|
||||||
@@ -1446,30 +1442,18 @@ static int prepare_build_program_table_device(struct job_data *job,
|
|||||||
if (bis->skip_prepare)
|
if (bis->skip_prepare)
|
||||||
/* skip the preparation work */
|
/* skip the preparation work */
|
||||||
return 0;
|
return 0;
|
||||||
|
if (dry_run) {
|
||||||
|
error_text("Option '--dry-run' is not implemented for this type of dump");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
/* Get full path of bootmap file */
|
/* Get full path of bootmap file */
|
||||||
if (!dry_run) {
|
bis->filename = misc_strdup(job->data.dump.device);
|
||||||
bis->filename = misc_strdup(job->data.dump.device);
|
if (!bis->filename)
|
||||||
if (!bis->filename)
|
return -1;
|
||||||
return -1;
|
bis->fd = misc_open_exclusive(bis->filename);
|
||||||
bis->fd = misc_open_exclusive(bis->filename);
|
if (bis->fd == -1) {
|
||||||
if (bis->fd == -1) {
|
error_text("Could not open file '%s'", bis->filename);
|
||||||
error_text("Could not open file '%s'", bis->filename);
|
return -1;
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bis->filename = misc_make_path(job->target.bootmap_dir,
|
|
||||||
BOOTMAP_TEMPLATE_FILENAME);
|
|
||||||
if (!bis->filename)
|
|
||||||
return -1;
|
|
||||||
/* Create temporary bootmap file */
|
|
||||||
bis->fd = mkstemp(bis->filename);
|
|
||||||
if (bis->fd == -1) {
|
|
||||||
error_reason(strerror(errno));
|
|
||||||
error_text("Could not create file '%s':",
|
|
||||||
bis->filename);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
bis->tmp_filename_created = 1;
|
|
||||||
}
|
}
|
||||||
/* Retrieve target device information */
|
/* Retrieve target device information */
|
||||||
if (disk_get_info(bis->filename, &job->target, &bis->info))
|
if (disk_get_info(bis->filename, &job->target, &bis->info))
|
||||||
@@ -1479,9 +1463,9 @@ static int prepare_build_program_table_device(struct job_data *job,
|
|||||||
printf("Target device information\n");
|
printf("Target device information\n");
|
||||||
disk_print_info(bis->info, job->target.source);
|
disk_print_info(bis->info, job->target.source);
|
||||||
}
|
}
|
||||||
if (misc_temp_dev(bis->info->device, 1, &bis->device))
|
if (misc_temp_dev(bis->info->basedisks[0], 1, &bis->basetmp[0]))
|
||||||
return -1;
|
return -1;
|
||||||
if (check_dump_device(job, bis->info, bis->device))
|
if (check_dump_device(job, bis->info, bis->basetmp[0]))
|
||||||
return -1;
|
return -1;
|
||||||
printf("Building bootmap directly on partition '%s'%s\n",
|
printf("Building bootmap directly on partition '%s'%s\n",
|
||||||
bis->filename,
|
bis->filename,
|
||||||
@@ -1545,6 +1529,8 @@ static int prepare_bootloader_device(struct job_data *job,
|
|||||||
static int prepare_build_program_table_file(struct job_data *job,
|
static int prepare_build_program_table_file(struct job_data *job,
|
||||||
struct install_set *bis)
|
struct install_set *bis)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
if (bis->skip_prepare)
|
if (bis->skip_prepare)
|
||||||
/* skip the preparation work */
|
/* skip the preparation work */
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1565,21 +1551,18 @@ static int prepare_build_program_table_file(struct job_data *job,
|
|||||||
* block size. */
|
* block size. */
|
||||||
if (disk_get_info_from_file(bis->filename, &job->target, &bis->info))
|
if (disk_get_info_from_file(bis->filename, &job->target, &bis->info))
|
||||||
return -1;
|
return -1;
|
||||||
/* Check for supported disk and driver types */
|
|
||||||
if (job->target.source == source_auto &&
|
|
||||||
bis->info->type == disk_type_diag) {
|
|
||||||
error_reason("Unsupported disk type (%s)",
|
|
||||||
disk_get_type_name(bis->info->type));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!disk_is_appropriate(job, bis->info))
|
if (!disk_is_appropriate(job, bis->info))
|
||||||
return -1;
|
return -1;
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
printf("Target device information\n");
|
printf("Target device information\n");
|
||||||
disk_print_info(bis->info, job->target.source);
|
disk_print_info(bis->info, job->target.source);
|
||||||
}
|
}
|
||||||
if (misc_temp_dev(bis->info->device, 1, &bis->device))
|
for (i = 0; i < job_get_nr_targets(job); i++) {
|
||||||
return -1;
|
if (misc_temp_dev(bis->info->basedisks[i],
|
||||||
|
1,
|
||||||
|
&bis->basetmp[i]))
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
/* Check configuration number limits */
|
/* Check configuration number limits */
|
||||||
if (job->id == job_menu) {
|
if (job->id == job_menu) {
|
||||||
if (check_menu_positions(&job->data.menu, job->name,
|
if (check_menu_positions(&job->data.menu, job->name,
|
||||||
@@ -1694,9 +1677,9 @@ static int prepare_bootloader_ngdump(struct job_data *job,
|
|||||||
/* Retrieve target device information */
|
/* Retrieve target device information */
|
||||||
if (disk_get_info(job->data.dump.device, &job->target, &info))
|
if (disk_get_info(job->data.dump.device, &job->target, &info))
|
||||||
return -1;
|
return -1;
|
||||||
if (misc_temp_dev(info->device, 1, &bis->device))
|
if (misc_temp_dev(info->basedisks[0], 1, &bis->basetmp[0]))
|
||||||
return -1;
|
return -1;
|
||||||
if (check_dump_device(job, info, bis->device))
|
if (check_dump_device(job, info, bis->basetmp[0]))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
assert(!job->target.bootmap_dir);
|
assert(!job->target.bootmap_dir);
|
||||||
@@ -1802,7 +1785,7 @@ int prepare_bootloader(struct job_data *job, struct install_set *bis)
|
|||||||
if (init_bis(job, bis))
|
if (init_bis(job, bis))
|
||||||
return -1;
|
return -1;
|
||||||
if (job->id == job_dump_partition) {
|
if (job->id == job_dump_partition) {
|
||||||
if (is_ngdump_enabled(job))
|
if (job_dump_is_ngdump(job))
|
||||||
return prepare_bootloader_ngdump(job, bis);
|
return prepare_bootloader_ngdump(job, bis);
|
||||||
else
|
else
|
||||||
return prepare_bootloader_device(job, bis);
|
return prepare_bootloader_device(job, bis);
|
||||||
@@ -1818,7 +1801,7 @@ int prepare_bootloader(struct job_data *job, struct install_set *bis)
|
|||||||
int post_install_bootloader(struct job_data *job, struct install_set *bis)
|
int post_install_bootloader(struct job_data *job, struct install_set *bis)
|
||||||
{
|
{
|
||||||
if (job->id == job_dump_partition) {
|
if (job->id == job_dump_partition) {
|
||||||
if (is_ngdump_enabled(job))
|
if (job_dump_is_ngdump(job))
|
||||||
return dry_run ? 0 : finalize_create_file(job, bis);
|
return dry_run ? 0 : finalize_create_file(job, bis);
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1846,6 +1829,9 @@ void free_bootloader(struct install_set *bis)
|
|||||||
if (bis->tmp_filename_created)
|
if (bis->tmp_filename_created)
|
||||||
misc_free_temp_file(bis->filename);
|
misc_free_temp_file(bis->filename);
|
||||||
free(bis->filename);
|
free(bis->filename);
|
||||||
misc_free_temp_dev(bis->device);
|
for (i = 0; i < MAX_TARGETS; i++) {
|
||||||
|
if (bis->basetmp[i])
|
||||||
|
misc_free_temp_dev(bis->basetmp[i]);
|
||||||
|
}
|
||||||
disk_free_info(bis->info);
|
disk_free_info(bis->info);
|
||||||
}
|
}
|
||||||
|
|||||||
+263
-107
@@ -92,14 +92,6 @@ disk_determine_dasd_type(struct disk_info *data,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return non-zero for ECKD type. */
|
|
||||||
static int
|
|
||||||
disk_is_eckd(disk_type_t type)
|
|
||||||
{
|
|
||||||
return (type == disk_type_eckd_ldl ||
|
|
||||||
type == disk_type_eckd_cdl);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
read_block_by_offset(int fd, int blksize, uint64_t offset, char *buffer)
|
read_block_by_offset(int fd, int blksize, uint64_t offset, char *buffer)
|
||||||
{
|
{
|
||||||
@@ -187,43 +179,134 @@ out_err:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a script output represented by FH and consisting
|
||||||
|
* of pairs 'key=value' (each such pair is on a separate line).
|
||||||
|
* Check its consistency and set the extracted target parameters
|
||||||
|
* to the array of "targets" at TD.
|
||||||
|
*
|
||||||
|
* NOTE: this function defines specifications on valid output of
|
||||||
|
* zipl helper scripts. See zipl-support-for-mirrored-devices.txt
|
||||||
|
* for details. Before modifying this function, make sure that it
|
||||||
|
* won't lead to format change.
|
||||||
|
*/
|
||||||
static int set_target_parameters(FILE *fh, struct job_target_data *td)
|
static int set_target_parameters(FILE *fh, struct job_target_data *td)
|
||||||
{
|
{
|
||||||
int checkparm = 0;
|
int idx[LAST_TARGET_PARAM] = {0};
|
||||||
|
struct target *t;
|
||||||
char buffer[80];
|
char buffer[80];
|
||||||
char value[40];
|
char value[40];
|
||||||
|
char *error;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a stream of 'key=value' pairs and distribute
|
||||||
|
* them into groups.
|
||||||
|
* The i-th occurrence of some "key" in the stream means
|
||||||
|
* that the respective pair belongs to the group #i
|
||||||
|
*/
|
||||||
|
error = "Exceeded the maximum number of base disks";
|
||||||
while (fgets(buffer, 80, fh)) {
|
while (fgets(buffer, 80, fh)) {
|
||||||
if (sscanf(buffer, "targetbase=%s", value) == 1) {
|
if (sscanf(buffer, "targetbase=%s", value) == 1) {
|
||||||
td->targetbase = misc_strdup(value);
|
t = target_at(td, idx[TARGET_BASE]++);
|
||||||
checkparm++;
|
if (!t)
|
||||||
|
goto error;
|
||||||
|
t->targetbase = misc_strdup(value);
|
||||||
|
goto found;
|
||||||
}
|
}
|
||||||
if (sscanf(buffer, "targettype=%s", value) == 1) {
|
if (sscanf(buffer, "targettype=%s", value) == 1) {
|
||||||
type_from_target(value, &td->targettype);
|
t = target_at(td, idx[TARGET_TYPE]++);
|
||||||
checkparm++;
|
if (!t)
|
||||||
|
goto error;
|
||||||
|
type_from_target(value, &t->targettype);
|
||||||
|
goto found;
|
||||||
}
|
}
|
||||||
if (sscanf(buffer, "targetgeometry=%s", value) == 1) {
|
if (sscanf(buffer, "targetgeometry=%s", value) == 1) {
|
||||||
td->targetcylinders =
|
t = target_at(td, idx[TARGET_GEOMETRY]++);
|
||||||
atoi(strtok(value, ","));
|
if (!t)
|
||||||
td->targetheads = atoi(strtok(NULL, ","));
|
goto error;
|
||||||
td->targetsectors = atoi(strtok(NULL, ","));
|
t->targetcylinders = atoi(strtok(value, ","));
|
||||||
checkparm++;
|
t->targetheads = atoi(strtok(NULL, ","));
|
||||||
|
t->targetsectors = atoi(strtok(NULL, ","));
|
||||||
|
goto found;
|
||||||
}
|
}
|
||||||
if (sscanf(buffer, "targetblocksize=%s", value) == 1) {
|
if (sscanf(buffer, "targetblocksize=%s", value) == 1) {
|
||||||
td->targetblocksize = atoi(value);
|
t = target_at(td, idx[TARGET_BLOCKSIZE]++);
|
||||||
checkparm++;
|
if (!t)
|
||||||
|
goto error;
|
||||||
|
t->targetblocksize = atoi(value);
|
||||||
|
goto found;
|
||||||
}
|
}
|
||||||
if (sscanf(buffer, "targetoffset=%s", value) == 1) {
|
if (sscanf(buffer, "targetoffset=%s", value) == 1) {
|
||||||
td->targetoffset = atol(value);
|
t = target_at(td, idx[TARGET_OFFSET]++);
|
||||||
checkparm++;
|
if (!t)
|
||||||
|
goto error;
|
||||||
|
t->targetoffset = atol(value);
|
||||||
|
goto found;
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
|
found:
|
||||||
|
t->check_params++;
|
||||||
}
|
}
|
||||||
if ((!disk_is_eckd(td->targettype) && checkparm < 4) ||
|
/* Check for consistency */
|
||||||
(disk_is_eckd(td->targettype) && checkparm != 5)) {
|
error = "Inconsistent script output";
|
||||||
error_reason("Target parameters missing from script");
|
/*
|
||||||
return -1;
|
* First, calculate total number of groups
|
||||||
|
*/
|
||||||
|
td->nr_targets = 0;
|
||||||
|
for (i = 0; i < MAX_TARGETS; i++) {
|
||||||
|
t = target_at(td, i);
|
||||||
|
if (t->check_params == 0)
|
||||||
|
break;
|
||||||
|
td->nr_targets++;
|
||||||
|
}
|
||||||
|
if (!td->nr_targets)
|
||||||
|
/* No keywords found in the stream */
|
||||||
|
goto error;
|
||||||
|
/*
|
||||||
|
* Each group has to include targetbase, targettype,
|
||||||
|
* targetblocksize and targetoffset.
|
||||||
|
*/
|
||||||
|
if (td->nr_targets != idx[TARGET_BASE] ||
|
||||||
|
td->nr_targets != idx[TARGET_TYPE] ||
|
||||||
|
td->nr_targets != idx[TARGET_BLOCKSIZE] ||
|
||||||
|
td->nr_targets != idx[TARGET_OFFSET])
|
||||||
|
goto error;
|
||||||
|
/*
|
||||||
|
* In addition, any group of "ECKD" type has to include
|
||||||
|
* targetgeometry
|
||||||
|
*/
|
||||||
|
for (i = 0; i < td->nr_targets; i++) {
|
||||||
|
t = target_at(td, i);
|
||||||
|
assert(t->check_params >= 4);
|
||||||
|
if (disk_type_is_eckd(t->targettype) && t->check_params != 5)
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
error:
|
||||||
|
error_reason("%s", error);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_base_disk_params(struct job_target_data *td, int index)
|
||||||
|
{
|
||||||
|
disk_type_t type = get_targettype(td, index);
|
||||||
|
|
||||||
|
if (!verbose)
|
||||||
|
return;
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Base disk '%s':\n", get_targetbase(td, index));
|
||||||
|
fprintf(stderr, " layout........: %s\n", disk_get_type_name(type));
|
||||||
|
}
|
||||||
|
if (disk_type_is_eckd(type)) {
|
||||||
|
fprintf(stderr, " heads.........: %u\n", get_targetheads(td, index));
|
||||||
|
fprintf(stderr, " sectors.......: %u\n", get_targetsectors(td, index));
|
||||||
|
fprintf(stderr, " cylinders.....: %u\n", get_targetcylinders(td, index));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
fprintf(stderr, " start.........: %lu\n", get_targetoffset(td, index));
|
||||||
|
fprintf(stderr, " blksize.......: %u\n", get_targetblocksize(td, index));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -235,31 +318,57 @@ static int disk_set_info_by_hint(struct job_target_data *td,
|
|||||||
{
|
{
|
||||||
int majnum, minnum;
|
int majnum, minnum;
|
||||||
struct stat stats;
|
struct stat stats;
|
||||||
|
int i;
|
||||||
|
/*
|
||||||
|
* Currently multiple base disks with different parameters
|
||||||
|
* are not supported
|
||||||
|
*/
|
||||||
data->devno = -1;
|
data->devno = -1;
|
||||||
data->phy_block_size = td->targetblocksize;
|
data->phy_block_size = get_targetblocksize(td, 0);
|
||||||
data->type = td->targettype;
|
data->type = get_targettype(td, 0);
|
||||||
data->partnum = 0;
|
|
||||||
|
|
||||||
if (sscanf(td->targetbase, "%d:%d", &majnum, &minnum) == 2) {
|
assert(td->nr_targets != 0);
|
||||||
data->device = makedev(majnum, minnum);
|
for (i = 1; i < td->nr_targets; i++) {
|
||||||
data->targetbase = defined_as_device;
|
if (data->type != get_targettype(td, i) ||
|
||||||
data->partnum = minor(stats.st_rdev) - minnum;
|
data->phy_block_size != get_targetblocksize(td, i)) {
|
||||||
} else {
|
print_base_disk_params(td, 0);
|
||||||
if (stat(td->targetbase, &stats)) {
|
print_base_disk_params(td, i);
|
||||||
error_reason(strerror(errno));
|
error_reason("Inconsistent base disk geometry in target device");
|
||||||
error_text("Could not get information for "
|
|
||||||
"file '%s'", td->targetbase);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (!S_ISBLK(stats.st_mode)) {
|
}
|
||||||
error_reason("Target base device '%s' is not "
|
data->partnum = 0;
|
||||||
"a block device",
|
data->targetbase_def = undefined;
|
||||||
td->targetbase);
|
|
||||||
|
for (i = 0; i < td->nr_targets; i++) {
|
||||||
|
definition_t defined_as;
|
||||||
|
|
||||||
|
if (sscanf(get_targetbase(td, i),
|
||||||
|
"%d:%d", &majnum, &minnum) == 2) {
|
||||||
|
data->basedisks[i] = makedev(majnum, minnum);
|
||||||
|
defined_as = defined_as_device;
|
||||||
|
} else {
|
||||||
|
if (stat(get_targetbase(td, i), &stats)) {
|
||||||
|
error_reason(strerror(errno));
|
||||||
|
error_text("Could not get information for "
|
||||||
|
"file '%s'", get_targetbase(td, i));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!S_ISBLK(stats.st_mode)) {
|
||||||
|
error_reason("Target base device '%s' is not "
|
||||||
|
"a block device",
|
||||||
|
get_targetbase(td, i));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
data->basedisks[i] = stats.st_rdev;
|
||||||
|
defined_as = defined_as_name;
|
||||||
|
}
|
||||||
|
if (data->targetbase_def != undefined &&
|
||||||
|
data->targetbase_def != defined_as) {
|
||||||
|
error_reason("Target base disks are defined by different ways");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
data->device = stats.st_rdev;
|
data->targetbase_def = defined_as;
|
||||||
data->targetbase = defined_as_name;
|
|
||||||
}
|
}
|
||||||
if (data->type == disk_type_scsi && ioctl(fd, NVME_IOCTL_ID) >= 0)
|
if (data->type == disk_type_scsi && ioctl(fd, NVME_IOCTL_ID) >= 0)
|
||||||
data->is_nvme = 1;
|
data->is_nvme = 1;
|
||||||
@@ -446,11 +555,28 @@ static int run_targetbase_script(struct job_target_data *td,
|
|||||||
static int disk_set_geometry_by_hint(struct job_target_data *td,
|
static int disk_set_geometry_by_hint(struct job_target_data *td,
|
||||||
struct disk_info *data)
|
struct disk_info *data)
|
||||||
{
|
{
|
||||||
data->geo.heads = td->targetheads;
|
int i;
|
||||||
data->geo.sectors = td->targetsectors;
|
/*
|
||||||
data->geo.cylinders = td->targetcylinders;
|
* Currently multiple base disks with different parameters
|
||||||
data->geo.start = td->targetoffset;
|
* are not supported
|
||||||
|
*/
|
||||||
|
data->geo.heads = get_targetheads(td, 0);
|
||||||
|
data->geo.sectors = get_targetsectors(td, 0);
|
||||||
|
data->geo.cylinders = get_targetcylinders(td, 0);
|
||||||
|
data->geo.start = get_targetoffset(td, 0);
|
||||||
|
|
||||||
|
assert(td->nr_targets != 0);
|
||||||
|
for (i = 1; i < td->nr_targets; i++) {
|
||||||
|
if (data->geo.heads != get_targetheads(td, i) ||
|
||||||
|
data->geo.sectors != get_targetsectors(td, i) ||
|
||||||
|
data->geo.cylinders != get_targetcylinders(td, i) ||
|
||||||
|
data->geo.start != get_targetoffset(td, i)) {
|
||||||
|
print_base_disk_params(td, 0);
|
||||||
|
print_base_disk_params(td, i);
|
||||||
|
error_reason("Inconsistent base disk geometry in target device");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -483,7 +609,7 @@ static int disk_set_info_complete(struct job_target_data *td,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* Check for valid CHS geometry data. */
|
/* Check for valid CHS geometry data. */
|
||||||
if (disk_is_eckd(data->type) && (data->geo.cylinders == 0 ||
|
if (disk_type_is_eckd(data->type) && (data->geo.cylinders == 0 ||
|
||||||
data->geo.heads == 0 || data->geo.sectors == 0)) {
|
data->geo.heads == 0 || data->geo.sectors == 0)) {
|
||||||
error_reason("Invalid disk geometry (CHS=%d/%d/%d)",
|
error_reason("Invalid disk geometry (CHS=%d/%d/%d)",
|
||||||
data->geo.cylinders, data->geo.heads,
|
data->geo.cylinders, data->geo.heads,
|
||||||
@@ -515,14 +641,16 @@ static int disk_set_info_complete(struct job_target_data *td,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare INFO required to perform IPL installation on the physical
|
* Prepare INFO required to perform IPL installation on physical disks
|
||||||
* disk where the logical DEVICE is located.
|
* participating in the logical DEVICE.
|
||||||
* Preparation is performed in 2 steps:
|
* Preparation is performed in 2 steps:
|
||||||
*
|
*
|
||||||
* 1. Find out a physical "base" disk where the logical DEVICE is
|
* 1. Find out a set of physical "base" disks participating in the
|
||||||
* located. Calculate "target" parameters (type, geometry, physical
|
* logical DEVICE. For each found disk calculate "target" parameters
|
||||||
* block size, data offset, etc);
|
* (type, geometry, physical block size, data offset, etc) and store
|
||||||
* 2. Complete INFO by the found base disk and target parameters.
|
* it in the array of "targets" of TD;
|
||||||
|
* 2. Complete INFO using the found base disks and calculated target
|
||||||
|
* parameters.
|
||||||
*
|
*
|
||||||
* TD: optionally contains target parameters specified by user via
|
* TD: optionally contains target parameters specified by user via
|
||||||
* config file, or special "target options" of zipl tool.
|
* config file, or special "target options" of zipl tool.
|
||||||
@@ -569,6 +697,7 @@ int disk_get_info(const char *device, struct job_target_data *td,
|
|||||||
goto error;
|
goto error;
|
||||||
if (disk_set_info_by_hint(td, data, fd))
|
if (disk_set_info_by_hint(td, data, fd))
|
||||||
goto error;
|
goto error;
|
||||||
|
data->device = stats.st_rdev;
|
||||||
break;
|
break;
|
||||||
case source_user:
|
case source_user:
|
||||||
/*
|
/*
|
||||||
@@ -581,6 +710,12 @@ int disk_get_info(const char *device, struct job_target_data *td,
|
|||||||
goto error;
|
goto error;
|
||||||
if (disk_set_info_by_hint(td, data, fd))
|
if (disk_set_info_by_hint(td, data, fd))
|
||||||
goto error;
|
goto error;
|
||||||
|
/*
|
||||||
|
* multiple base disks are not supported
|
||||||
|
* with this source type
|
||||||
|
*/
|
||||||
|
assert(td->nr_targets == 1);
|
||||||
|
data->device = data->basedisks[0];
|
||||||
break;
|
break;
|
||||||
case source_auto:
|
case source_auto:
|
||||||
/* no ready target parameters are available */
|
/* no ready target parameters are available */
|
||||||
@@ -588,6 +723,12 @@ int disk_get_info(const char *device, struct job_target_data *td,
|
|||||||
goto error;
|
goto error;
|
||||||
if (disk_set_info_auto(data, &stats, fd))
|
if (disk_set_info_auto(data, &stats, fd))
|
||||||
goto error;
|
goto error;
|
||||||
|
/*
|
||||||
|
* multiple base disks are not supported
|
||||||
|
* with this source type
|
||||||
|
*/
|
||||||
|
data->basedisks[0] = data->device;
|
||||||
|
td->nr_targets = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
@@ -620,45 +761,48 @@ disk_is_tape(const char* device)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
/**
|
||||||
disk_is_scsi(const char* device, struct job_target_data* target)
|
* Get "extended type" of base disk by logical DEVICE
|
||||||
{
|
*
|
||||||
struct disk_info* info;
|
* This function may fail for various reasons. E.g. in case when
|
||||||
int rc = 0;
|
* DEVICE is not eligible for boot record installation (not a
|
||||||
|
* partition, etc). In case of success the resulted disk type is
|
||||||
if (disk_get_info(device, target, &info) == -1)
|
* stored in EXT_TYPE.
|
||||||
return 0;
|
*/
|
||||||
if (info->type == disk_type_scsi)
|
int disk_get_ext_type(const char *device, struct disk_ext_type *ext_type)
|
||||||
rc = 1;
|
|
||||||
disk_free_info(info);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
int disk_is_eckd_ldl(const char *device, struct job_target_data *target)
|
|
||||||
{
|
{
|
||||||
|
struct job_target_data tmp = {.source = source_unknown};
|
||||||
struct disk_info *info;
|
struct disk_info *info;
|
||||||
int rc = 0;
|
|
||||||
|
|
||||||
if (disk_get_info(device, target, &info) == -1)
|
if (disk_get_info(device, &tmp, &info))
|
||||||
return 0;
|
return -1;
|
||||||
if (info->type == disk_type_eckd_ldl)
|
ext_type->type = info->type;
|
||||||
rc = 1;
|
ext_type->is_nvme = info->is_nvme;
|
||||||
|
|
||||||
disk_free_info(info);
|
disk_free_info(info);
|
||||||
return rc;
|
free_target_data(&tmp);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int disk_type_is_scsi(struct disk_ext_type *ext_type)
|
||||||
disk_is_nvme(const char* device, struct job_target_data* target)
|
|
||||||
{
|
{
|
||||||
struct disk_info* info;
|
return ext_type->type == disk_type_scsi;
|
||||||
int rc = 0;
|
}
|
||||||
|
|
||||||
if (disk_get_info(device, target, &info) == -1)
|
int disk_type_is_eckd_ldl(struct disk_ext_type *ext_type)
|
||||||
return 0;
|
{
|
||||||
if (info->type == disk_type_scsi && info->is_nvme)
|
return ext_type->type == disk_type_eckd_ldl;
|
||||||
rc = 1;
|
}
|
||||||
disk_free_info(info);
|
|
||||||
return rc;
|
int disk_type_is_nvme(struct disk_ext_type *ext_type)
|
||||||
|
{
|
||||||
|
return ext_type->is_nvme;
|
||||||
|
}
|
||||||
|
|
||||||
|
int disk_type_is_eckd(disk_type_t type)
|
||||||
|
{
|
||||||
|
return (type == disk_type_eckd_ldl ||
|
||||||
|
type == disk_type_eckd_cdl);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -943,6 +1087,33 @@ disk_print_devt(dev_t d)
|
|||||||
printf("%02x:%02x", major(d), minor(d));
|
printf("%02x:%02x", major(d), minor(d));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void disk_print_devname(dev_t dev)
|
||||||
|
{
|
||||||
|
struct util_proc_part_entry part_entry;
|
||||||
|
|
||||||
|
if (!util_proc_part_get_entry(dev, &part_entry)) {
|
||||||
|
printf("%s", part_entry.name);
|
||||||
|
util_proc_part_free_entry(&part_entry);
|
||||||
|
} else {
|
||||||
|
disk_print_devt(dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void prepare_footnote_ptr(int source, char *ptr)
|
||||||
|
{
|
||||||
|
if (source == source_user || source == source_script)
|
||||||
|
strcpy(ptr, " *)");
|
||||||
|
else
|
||||||
|
strcpy(ptr, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_footnote_ref(int source, const char *prefix)
|
||||||
|
{
|
||||||
|
if (source == source_user)
|
||||||
|
printf("%s*) Data provided by user.\n", prefix);
|
||||||
|
else if (source == source_script)
|
||||||
|
printf("%s*) Data provided by script.\n", prefix);
|
||||||
|
}
|
||||||
|
|
||||||
/* Return a name for a given disk TYPE. */
|
/* Return a name for a given disk TYPE. */
|
||||||
char *
|
char *
|
||||||
@@ -994,12 +1165,11 @@ disk_is_large_volume(struct disk_info* info)
|
|||||||
void disk_print_info(struct disk_info *info, int source)
|
void disk_print_info(struct disk_info *info, int source)
|
||||||
{
|
{
|
||||||
char footnote[4] = "";
|
char footnote[4] = "";
|
||||||
if (source == source_user || source == source_script)
|
|
||||||
strcpy(footnote, " *)");
|
|
||||||
|
|
||||||
|
prepare_footnote_ptr(source, footnote);
|
||||||
printf(" Device..........................: ");
|
printf(" Device..........................: ");
|
||||||
disk_print_devt(info->device);
|
disk_print_devt(info->device);
|
||||||
if (info->targetbase == defined_as_device)
|
if (info->targetbase_def == defined_as_device)
|
||||||
printf("%s", footnote);
|
printf("%s", footnote);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
if (info->partnum != 0) {
|
if (info->partnum != 0) {
|
||||||
@@ -1010,7 +1180,7 @@ void disk_print_info(struct disk_info *info, int source)
|
|||||||
if (info->name) {
|
if (info->name) {
|
||||||
printf(" Device name.....................: %s",
|
printf(" Device name.....................: %s",
|
||||||
info->name);
|
info->name);
|
||||||
if (info->targetbase == defined_as_name)
|
if (info->targetbase_def == defined_as_name)
|
||||||
printf("%s", footnote);
|
printf("%s", footnote);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
@@ -1030,7 +1200,7 @@ void disk_print_info(struct disk_info *info, int source)
|
|||||||
(info->partnum != 0) ? "partition" : "device");
|
(info->partnum != 0) ? "partition" : "device");
|
||||||
printf(" Disk layout.....................: %s%s\n",
|
printf(" Disk layout.....................: %s%s\n",
|
||||||
disk_get_type_name(info->type), footnote);
|
disk_get_type_name(info->type), footnote);
|
||||||
if (disk_is_eckd(info->type)) {
|
if (disk_type_is_eckd(info->type)) {
|
||||||
printf(" Geometry - heads................: %d%s\n",
|
printf(" Geometry - heads................: %d%s\n",
|
||||||
info->geo.heads, footnote);
|
info->geo.heads, footnote);
|
||||||
printf(" Geometry - sectors..............: %d%s\n",
|
printf(" Geometry - sectors..............: %d%s\n",
|
||||||
@@ -1053,21 +1223,7 @@ void disk_print_info(struct disk_info *info, int source)
|
|||||||
info->phy_block_size, footnote);
|
info->phy_block_size, footnote);
|
||||||
printf(" Device size in physical blocks..: %ld\n",
|
printf(" Device size in physical blocks..: %ld\n",
|
||||||
(long) info->phy_blocks);
|
(long) info->phy_blocks);
|
||||||
if (source == source_user)
|
print_footnote_ref(source, " ");
|
||||||
printf(" *) Data provided by user.\n");
|
|
||||||
if (source == source_script)
|
|
||||||
printf(" *) Data provided by script.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Print textual representation of geo structure. */
|
|
||||||
void
|
|
||||||
disk_print_geo(struct disk_info *data)
|
|
||||||
{
|
|
||||||
printf(" geo.heads.........:%u\n", data->geo.heads);
|
|
||||||
printf(" geo.sectors.......:%u\n", data->geo.sectors);
|
|
||||||
printf(" geo.cylinders.....:%u\n", data->geo.cylinders);
|
|
||||||
printf(" geo.start.........:%lu\n", data->geo.start);
|
|
||||||
printf(" blksize...........:%u\n", data->phy_block_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check whether a block is a zero block which identifies a hole in a file.
|
/* Check whether a block is a zero block which identifies a hole in a file.
|
||||||
|
|||||||
+56
-35
@@ -434,11 +434,14 @@ int install_bootloader(struct job_data *job, struct install_set *bis)
|
|||||||
{
|
{
|
||||||
disk_blockptr_t *scsi_dump_sb_blockptr = &bis->scsi_dump_sb_blockptr;
|
disk_blockptr_t *scsi_dump_sb_blockptr = &bis->scsi_dump_sb_blockptr;
|
||||||
struct disk_info *info = bis->info;
|
struct disk_info *info = bis->info;
|
||||||
char *device = bis->device;
|
char footnote[4];
|
||||||
int fd, rc;
|
int rc;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (!info)
|
if (!info)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
prepare_footnote_ptr(job->target.source, footnote);
|
||||||
/* Inform user about what we're up to */
|
/* Inform user about what we're up to */
|
||||||
printf("Preparing boot device for %s%s: ",
|
printf("Preparing boot device for %s%s: ",
|
||||||
disk_get_ipl_type(info->type,
|
disk_get_ipl_type(info->type,
|
||||||
@@ -455,40 +458,58 @@ int install_bootloader(struct job_data *job, struct install_set *bis)
|
|||||||
disk_print_devt(info->device);
|
disk_print_devt(info->device);
|
||||||
printf(".\n");
|
printf(".\n");
|
||||||
}
|
}
|
||||||
/* Open device file */
|
/* Install independently on each physical target base */
|
||||||
fd = open(device, O_RDWR);
|
|
||||||
if (fd == -1) {
|
|
||||||
error_reason(strerror(errno));
|
|
||||||
error_text("Could not open temporary device file '%s'",
|
|
||||||
device);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
/* Ensure that potential cache inconsistencies between disk and
|
|
||||||
* partition are resolved by flushing the corresponding buffers. */
|
|
||||||
if (!dry_run) {
|
|
||||||
if (ioctl(fd, BLKFLSBUF)) {
|
|
||||||
fprintf(stderr, "Warning: Could not flush disk "
|
|
||||||
"caches.\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Depending on disk type, install one or two program tables
|
|
||||||
* for CCW-type IPL and (or) for List-Directed IPL (see the
|
|
||||||
* picture in comments above)
|
|
||||||
*/
|
|
||||||
if (job->id == job_dump_partition) {
|
|
||||||
rc = install_bootloader_dump(bis->tables, info,
|
|
||||||
scsi_dump_sb_blockptr,
|
|
||||||
is_ngdump_enabled(job),
|
|
||||||
fd);
|
|
||||||
} else {
|
|
||||||
rc = install_bootloader_ipl(bis->tables, info, fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fsync(fd))
|
for (i = 0; i < job_get_nr_targets(job); i++) {
|
||||||
error_text("Could not sync device file '%s'", device);
|
int fd;
|
||||||
if (close(fd))
|
|
||||||
error_text("Could not close device file '%s'", device);
|
if (verbose) {
|
||||||
|
printf("Installing on base disk: ");
|
||||||
|
disk_print_devname(info->basedisks[i]);
|
||||||
|
printf("%s.\n", footnote);
|
||||||
|
}
|
||||||
|
/* Open device file */
|
||||||
|
fd = open(bis->basetmp[i], O_RDWR);
|
||||||
|
if (fd == -1) {
|
||||||
|
error_reason(strerror(errno));
|
||||||
|
error_text("Could not open temporary device file '%s'",
|
||||||
|
bis->basetmp[i]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Ensure that potential cache inconsistencies between disk and
|
||||||
|
* partition are resolved by flushing the corresponding buffers.
|
||||||
|
*/
|
||||||
|
if (!dry_run) {
|
||||||
|
if (ioctl(fd, BLKFLSBUF)) {
|
||||||
|
fprintf(stderr, "Warning: Could not flush disk "
|
||||||
|
"caches.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Depending on disk type, install one or two program tables
|
||||||
|
* for CCW-type IPL and (or) for List-Directed IPL (see the
|
||||||
|
* picture in comments above)
|
||||||
|
*/
|
||||||
|
if (job->id == job_dump_partition) {
|
||||||
|
rc = install_bootloader_dump(bis->tables, info,
|
||||||
|
scsi_dump_sb_blockptr,
|
||||||
|
job_dump_is_ngdump(job),
|
||||||
|
fd);
|
||||||
|
} else {
|
||||||
|
rc = install_bootloader_ipl(bis->tables, info,
|
||||||
|
fd);
|
||||||
|
}
|
||||||
|
if (fsync(fd))
|
||||||
|
error_text("Could not sync device file '%s'",
|
||||||
|
bis->basetmp[i]);
|
||||||
|
if (close(fd))
|
||||||
|
error_text("Could not close device file '%s'",
|
||||||
|
bis->basetmp[i]);
|
||||||
|
if (rc)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (verbose)
|
||||||
|
print_footnote_ref(job->target.source, "");
|
||||||
|
|
||||||
if (!dry_run && rc == 0) {
|
if (!dry_run && rc == 0) {
|
||||||
if (info->devno >= 0)
|
if (info->devno >= 0)
|
||||||
|
|||||||
+64
-42
@@ -369,11 +369,13 @@ get_command_line(int argc, char* argv[], struct command_line* line)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void free_target_data(struct job_target_data *data)
|
void free_target_data(struct job_target_data *data)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
free(data->bootmap_dir);
|
free(data->bootmap_dir);
|
||||||
free(data->targetbase);
|
for (i = 0; i < data->nr_targets; i++)
|
||||||
|
free(get_targetbase(data, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1345,6 +1347,27 @@ type_from_target(char *target, disk_type_t *type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int set_targettype(struct job_target_data *data, int index, char *value)
|
||||||
|
{
|
||||||
|
return type_from_target(value,
|
||||||
|
&target_at(data, index)->targettype);
|
||||||
|
}
|
||||||
|
|
||||||
|
int job_set_targettype(struct job_data *job, char *value)
|
||||||
|
{
|
||||||
|
return set_targettype(&job->target, 0, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int job_set_target(struct job_data *job, char *value)
|
||||||
|
{
|
||||||
|
job_set_targetbase(job, value);
|
||||||
|
if (!job_get_targetbase(job))
|
||||||
|
return -1;
|
||||||
|
job_set_nr_targets(job, 1);
|
||||||
|
job->target.source = source_user;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
get_job_from_section_data(char* data[], struct job_data* job, char* section)
|
get_job_from_section_data(char* data[], struct job_data* job, char* section)
|
||||||
{
|
{
|
||||||
@@ -1361,32 +1384,28 @@ get_job_from_section_data(char* data[], struct job_data* job, char* section)
|
|||||||
return -1;
|
return -1;
|
||||||
/* Fill in target */
|
/* Fill in target */
|
||||||
if (data[(int) scan_keyword_targetbase] != NULL) {
|
if (data[(int) scan_keyword_targetbase] != NULL) {
|
||||||
job->target.targetbase =
|
if (job_set_target(job, misc_strdup(data[(int)
|
||||||
misc_strdup(data[(int)
|
scan_keyword_targetbase])))
|
||||||
scan_keyword_targetbase]);
|
|
||||||
if (job->target.targetbase == NULL)
|
|
||||||
return -1;
|
return -1;
|
||||||
job->target.source = source_user;
|
|
||||||
}
|
}
|
||||||
if (data[(int) scan_keyword_targettype] != NULL) {
|
if (data[(int) scan_keyword_targettype] != NULL) {
|
||||||
if (type_from_target(
|
if (job_set_targettype(job,
|
||||||
data[(int) scan_keyword_targettype],
|
data[(int) scan_keyword_targettype]))
|
||||||
&job->target.targettype))
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (data[(int) scan_keyword_targetgeometry] != NULL) {
|
if (data[(int) scan_keyword_targetgeometry] != NULL) {
|
||||||
job->target.targetcylinders =
|
job_set_targetcylinders(job,
|
||||||
atoi(strtok(data[(int)
|
atoi(strtok(data[(int)
|
||||||
scan_keyword_targetgeometry], ","));
|
scan_keyword_targetgeometry], ",")));
|
||||||
job->target.targetheads = atoi(strtok(NULL, ","));
|
job_set_targetheads(job, atoi(strtok(NULL, ",")));
|
||||||
job->target.targetsectors = atoi(strtok(NULL, ","));
|
job_set_targetsectors(job, atoi(strtok(NULL, ",")));
|
||||||
}
|
}
|
||||||
if (data[(int) scan_keyword_targetblocksize] != NULL)
|
if (data[(int) scan_keyword_targetblocksize] != NULL)
|
||||||
job->target.targetblocksize =
|
job_set_targetblocksize(job,
|
||||||
atoi(data[(int) scan_keyword_targetblocksize]);
|
atoi(data[(int) scan_keyword_targetblocksize]));
|
||||||
if (data[(int) scan_keyword_targetoffset] != NULL)
|
if (data[(int) scan_keyword_targetoffset] != NULL)
|
||||||
job->target.targetoffset =
|
job_set_targetoffset(job,
|
||||||
atol(data[(int) scan_keyword_targetoffset]);
|
atol(data[(int) scan_keyword_targetoffset]));
|
||||||
/* Fill in name and address of image file */
|
/* Fill in name and address of image file */
|
||||||
|
|
||||||
job->data.ipl.common.image = misc_strdup(
|
job->data.ipl.common.image = misc_strdup(
|
||||||
@@ -1614,37 +1633,32 @@ get_menu_job(struct scan_token* scan, char* menu, struct job_data* job)
|
|||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
case scan_keyword_targetbase:
|
case scan_keyword_targetbase:
|
||||||
job->target.targetbase = misc_strdup(
|
if (job_set_target(job, misc_strdup(
|
||||||
scan[i].content.keyword.value);
|
scan[i].content.keyword.value)))
|
||||||
if (job->target.targetbase == NULL)
|
|
||||||
return -1;
|
return -1;
|
||||||
job->target.source = source_user;
|
|
||||||
break;
|
break;
|
||||||
case scan_keyword_targettype:
|
case scan_keyword_targettype:
|
||||||
if (type_from_target(
|
if (job_set_targettype(job,
|
||||||
scan[i].content.keyword.value,
|
scan[i].content.keyword.value))
|
||||||
&job->target.targettype))
|
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
case scan_keyword_targetgeometry:
|
case scan_keyword_targetgeometry:
|
||||||
job->target.targetcylinders =
|
job_set_targetcylinders(job,
|
||||||
atoi(strtok(
|
atoi(strtok(
|
||||||
scan[i].content.keyword.value,
|
scan[i].content.keyword.value,
|
||||||
","));
|
",")));
|
||||||
job->target.targetheads =
|
job_set_targetheads(job,
|
||||||
atoi(strtok(NULL, ","));
|
atoi(strtok(NULL, ",")));
|
||||||
job->target.targetsectors =
|
job_set_targetsectors(job,
|
||||||
atoi(strtok(NULL, ","));
|
atoi(strtok(NULL, ",")));
|
||||||
break;
|
break;
|
||||||
case scan_keyword_targetblocksize:
|
case scan_keyword_targetblocksize:
|
||||||
job->target.targetblocksize =
|
job_set_targetblocksize(job, atoi(
|
||||||
atoi(
|
scan[i].content.keyword.value));
|
||||||
scan[i].content.keyword.value);
|
|
||||||
break;
|
break;
|
||||||
case scan_keyword_targetoffset:
|
case scan_keyword_targetoffset:
|
||||||
job->target.targetoffset =
|
job_set_targetoffset(job, atol(
|
||||||
atol(
|
scan[i].content.keyword.value));
|
||||||
scan[i].content.keyword.value);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* Should not happen */
|
/* Should not happen */
|
||||||
@@ -2043,10 +2057,18 @@ job_get(int argc, char* argv[], struct job_data** data)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void job_dump_check_set_ngdump(struct job_data *job,
|
||||||
is_ngdump_enabled(struct job_data *job)
|
struct disk_ext_type *ext_type)
|
||||||
{
|
{
|
||||||
if (job->is_ldipl_dump)
|
assert(job->id == job_dump_partition);
|
||||||
return true;
|
|
||||||
return disk_is_nvme(job->data.dump.device, &job->target);
|
if (job->is_ldipl_dump || disk_type_is_nvme(ext_type))
|
||||||
|
job->data.dump.is_ngdump = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool job_dump_is_ngdump(struct job_data *job)
|
||||||
|
{
|
||||||
|
assert(job->id == job_dump_partition);
|
||||||
|
|
||||||
|
return job->data.dump.is_ngdump;
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-4
@@ -128,6 +128,7 @@ check_for_root(void)
|
|||||||
int
|
int
|
||||||
main(int argc, char* argv[])
|
main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
struct disk_ext_type ext_type = {0};
|
||||||
struct install_set bis;
|
struct install_set bis;
|
||||||
struct job_data* job;
|
struct job_data* job;
|
||||||
int rc;
|
int rc;
|
||||||
@@ -173,9 +174,18 @@ main(int argc, char* argv[])
|
|||||||
/* Do it */
|
/* Do it */
|
||||||
switch (job->id) {
|
switch (job->id) {
|
||||||
case job_dump_partition:
|
case job_dump_partition:
|
||||||
if (!is_ngdump_enabled(job) &&
|
rc = disk_get_ext_type(job->data.dump.device, &ext_type);
|
||||||
|
if (rc)
|
||||||
|
break;
|
||||||
|
job_dump_check_set_ngdump(job, &ext_type);
|
||||||
|
if (!job_dump_is_ngdump(job) &&
|
||||||
(disk_is_tape(job->data.dump.device) ||
|
(disk_is_tape(job->data.dump.device) ||
|
||||||
!disk_is_scsi(job->data.dump.device, &job->target))) {
|
!disk_type_is_scsi(&ext_type))) {
|
||||||
|
if (dry_run) {
|
||||||
|
error_text("Option '--dry-run' is not implemented for this type of dump");
|
||||||
|
rc = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
rc = install_dump(job->data.dump.device, &job->target,
|
rc = install_dump(job->data.dump.device, &job->target,
|
||||||
job->data.dump.mem, job->data.dump.no_compress);
|
job->data.dump.mem, job->data.dump.no_compress);
|
||||||
break;
|
break;
|
||||||
@@ -187,8 +197,8 @@ main(int argc, char* argv[])
|
|||||||
rc = -1;
|
rc = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (is_ngdump_enabled(job)) {
|
if (job_dump_is_ngdump(job)) {
|
||||||
if (disk_is_eckd_ldl(job->data.dump.device, &job->target)) {
|
if (disk_type_is_eckd_ldl(&ext_type)) {
|
||||||
error_reason("List-directed dump on ECKD with LDL not supported");
|
error_reason("List-directed dump on ECKD with LDL not supported");
|
||||||
rc = -1;
|
rc = -1;
|
||||||
break;
|
break;
|
||||||
|
|||||||
+1228
-305
File diff suppressed because it is too large
Load Diff
@@ -908,7 +908,7 @@ static const struct util_opt configure_options[] = {
|
|||||||
"server's certificate. For self signed EKMF Web server "
|
"server's certificate. For self signed EKMF Web server "
|
||||||
"certificates, this is the default. Use option "
|
"certificates, this is the default. Use option "
|
||||||
"'--tls-pin-server-cert' to ensure the self signed "
|
"'--tls-pin-server-cert' to ensure the self signed "
|
||||||
"certificate's authenticity explicitely. CA signed "
|
"certificate's authenticity explicitly. CA signed "
|
||||||
"EKMF Web server certificates are verified by default. "
|
"EKMF Web server certificates are verified by default. "
|
||||||
"This option disables the verification.",
|
"This option disables the verification.",
|
||||||
.command = KMS_COMMAND_CONFIGURE,
|
.command = KMS_COMMAND_CONFIGURE,
|
||||||
|
|||||||
+1
-1
@@ -1382,7 +1382,7 @@ static int _keystore_lock_repository(struct keystore *keystore)
|
|||||||
if (fchown(keystore->lock_fd, geteuid(),
|
if (fchown(keystore->lock_fd, geteuid(),
|
||||||
keystore->owner) != 0) {
|
keystore->owner) != 0) {
|
||||||
rc = -errno;
|
rc = -errno;
|
||||||
warnx("chown faild on file '%s': %s", lock_file_name,
|
warnx("chown failed on file '%s': %s", lock_file_name,
|
||||||
strerror(-rc));
|
strerror(-rc));
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -90,7 +90,7 @@ a software RAID can transparently re-integrate the recovered device. For
|
|||||||
example, after a failure and recovery, a software RAID can resync a stroage
|
example, after a failure and recovery, a software RAID can resync a stroage
|
||||||
device or a network interface can be re-integrated in a bond. In contrast to
|
device or a network interface can be re-integrated in a bond. In contrast to
|
||||||
a complete shut down, the device driver remains active and informs higher
|
a complete shut down, the device driver remains active and informs higher
|
||||||
layers of both the occurence of an error state and the eventual recovery.
|
layers of both the occurrence of an error state and the eventual recovery.
|
||||||
.PP
|
.PP
|
||||||
.
|
.
|
||||||
.OD deconfigure "" "DEVICE"
|
.OD deconfigure "" "DEVICE"
|
||||||
|
|||||||
Reference in New Issue
Block a user