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