diff --git a/zdev/dracut/95zdev/module-setup.sh b/zdev/dracut/95zdev/module-setup.sh index 9079f355..4d4ae053 100644 --- a/zdev/dracut/95zdev/module-setup.sh +++ b/zdev/dracut/95zdev/module-setup.sh @@ -45,23 +45,12 @@ install() { # Hook to parse zdev kernel parameter inst_hook cmdline 95 "$moddir/parse-zdev.sh" - # Obtain root device configuration - - # Exit early if root device type is unknown - if ! lszdev --by-path / >/dev/null 2>&1 ; then - return 0 - fi - + # Obtain early + root device configuration _tempfile=$(mktemp --tmpdir dracut-zdev.XXXXXX) - - if chzdev --export - --persistent --by-path / >/dev/null 2>&1 ; then - # Use persistent configuration - chzdev --export "$_tempfile" --persistent --by-path / --quiet --type - else - # Use active configuration - chzdev --export "$_tempfile" --active --by-path / --quiet --type - sed -i -e 's/active/persistent/g' "$_tempfile" - fi + chzdev --export "$_tempfile" --persistent --by-path / --quiet \ + --type 2>/dev/null + chzdev --export - --persistent --by-attrib "zdev:early=1" --quiet \ + --type 2>/dev/null >> "$_tempfile" # Apply via --import to prevent other devices from being configured chzdev --import "$_tempfile" --persistent --base "/etc=$initdir/etc" \ diff --git a/zdev/include/internal.h b/zdev/include/internal.h index a658988a..044112fc 100644 --- a/zdev/include/internal.h +++ b/zdev/include/internal.h @@ -12,7 +12,12 @@ #include +#include "attrib.h" + #define INTERNAL_ATTR_PREFIX "zdev:" +#define INTERNAL_ATTR_EARLY INTERNAL_ATTR_PREFIX "early" + +extern struct attrib internal_attr_early; const char *internal_get_name(const char *name); bool internal_by_name(const char *name); diff --git a/zdev/initramfs/hooks/zdev b/zdev/initramfs/hooks/zdev index 234e5bb0..7ba771e1 100644 --- a/zdev/initramfs/hooks/zdev +++ b/zdev/initramfs/hooks/zdev @@ -10,7 +10,8 @@ # configuration data during boot. # -PREREQ="" +# Needs to run after udev or resulting udev rules could be overwritten +PREREQ="udev" prereqs() { @@ -37,3 +38,19 @@ done copy_exec /sbin/chzdev copy_exec /sbin/lszdev copy_exec /sbin/vmcp + +_tempfile=$(mktemp --tmpdir initramfs-zdev.XXXXXX) + +# Obtain early + root device configuration +chzdev --export "$_tempfile" --persistent --by-path / \ + --by-attrib "zdev:early=1" --quiet --type 2>/dev/null + +# Apply via --import to prevent other devices from being configured. +# Rename the resulting cio-ignore rule to ensure that it does not override +# the one copied by the initramfs udev hook to /lib/udev. +chzdev --import "$_tempfile" --persistent \ + --base "/etc/udev/rules.d/41-cio-ignore.rules=$DESTDIR/etc/udev/rules.d/41-cio-ignore-root.rules" \ + --base "/etc=$DESTDIR/etc" --yes --quiet --no-root-update --force \ + >/dev/null + +rm -f "$_tempfile" diff --git a/zdev/man/chzdev.8 b/zdev/man/chzdev.8 index b0c24af5..67a5dce6 100644 --- a/zdev/man/chzdev.8 +++ b/zdev/man/chzdev.8 @@ -334,6 +334,35 @@ a specific attribute. .PP . . +.SS "Special settings" +The following special settings affect how devices are handled by chzdev: +.PP +. +.BR zdev:early =0|1 +.RS 4 +Control in which stage of the boot process a device is activated: +.TP 4 +.B 0 +Device is activated normally during boot (default). +.PP +.TP 4 +.B 1 +Device is activated early in the boot process, by the initial RAM-disk. +.PP +Specify a value of 1 for this attribute in any of the following situations: +.TP 4 +\(bu +To ensure that your settings override auto-configuration settings. +.PP +.TP 4 +\(bu +To ensure that a device required to access the root file system is correctly +enabled during boot. An example would be a networking device, or a device that +is intended to extend a logical volume that provides the root file system. +.PP +.RE +. +. .SH ACTIONS You can use one of the action options listed below to specify the .B main tool action diff --git a/zdev/src/chzdev.c b/zdev/src/chzdev.c index 4372e546..7452ad16 100644 --- a/zdev/src/chzdev.c +++ b/zdev/src/chzdev.c @@ -3025,8 +3025,8 @@ int main(int argc, char *argv[]) if ((pers_mod_devs || pers_mod_devtypes) && !opts.no_root_check && !dryrun) { - /* If the root device/device type has been modified, additional - * work might be necessary. */ + /* If the root device/device type or early devices have been + * modified, additional work might be necessary. */ rc = root_check(); if (rc && !drc) drc = rc; diff --git a/zdev/src/ctc.c b/zdev/src/ctc.c index d96729cc..27b075db 100644 --- a/zdev/src/ctc.c +++ b/zdev/src/ctc.c @@ -17,6 +17,7 @@ #include "ctc_auto.h" #include "device.h" #include "devtype.h" +#include "internal.h" #include "misc.h" #include "namespace.h" #include "path.h" @@ -425,6 +426,7 @@ static struct subtype ctc_subtype = { &ccw_attr_online, &ctc_attr_buffer, &ctc_attr_protocol, + &internal_attr_early, ), .unknown_dev_attribs = 1, .support_definable = 1, diff --git a/zdev/src/dasd.c b/zdev/src/dasd.c index 510339fc..645e8b02 100644 --- a/zdev/src/dasd.c +++ b/zdev/src/dasd.c @@ -16,6 +16,7 @@ #include "dasd.h" #include "device.h" #include "devtype.h" +#include "internal.h" #include "misc.h" #include "modprobe.h" #include "module.h" @@ -616,6 +617,7 @@ struct subtype dasd_subtype_eckd = { &dasd_attr_reservation_policy, &dasd_attr_last_known_reservation_state, &dasd_attr_safe_offline, + &internal_attr_early, ), .unknown_dev_attribs = 1, @@ -651,6 +653,7 @@ struct subtype dasd_subtype_fba = { &dasd_attr_reservation_policy, &dasd_attr_last_known_reservation_state, &dasd_attr_safe_offline, + &internal_attr_early, ), .unknown_dev_attribs = 1, diff --git a/zdev/src/generic_ccw.c b/zdev/src/generic_ccw.c index 9132d4a7..1ec8a2a2 100644 --- a/zdev/src/generic_ccw.c +++ b/zdev/src/generic_ccw.c @@ -17,6 +17,7 @@ #include "devnode.h" #include "devtype.h" #include "generic_ccw.h" +#include "internal.h" #include "namespace.h" #include "path.h" #include "subtype.h" @@ -182,6 +183,7 @@ static struct subtype generic_ccw_subtype = { .dev_attribs = ATTRIB_ARRAY( &ccw_attr_online, &ccw_attr_cmb_enable, + &internal_attr_early, ), .unknown_dev_attribs = 1, .generic = 1, diff --git a/zdev/src/internal.c b/zdev/src/internal.c index 6472bf39..ec5a42fa 100644 --- a/zdev/src/internal.c +++ b/zdev/src/internal.c @@ -9,9 +9,22 @@ #include +#include "attrib.h" #include "internal.h" #include "misc.h" +struct attrib internal_attr_early = { + .name = INTERNAL_ATTR_EARLY, + .title = "Activate device early during boot", + .desc = "Control the time of activation of a device:\n" + " 0: Device is activated normally during boot\n" + " 1: Device is activated early in the boot process, by the\n" + " initial RAM-disk\n", + .defval = "0", + .accept = ACCEPT_ARRAY(ACCEPT_RANGE(0, 1)), + .internal = 1, +}; + /* Return identifier of internal attribute with specified @name. */ const char *internal_get_name(const char *name) { diff --git a/zdev/src/lcs.c b/zdev/src/lcs.c index 1859891c..861d030d 100644 --- a/zdev/src/lcs.c +++ b/zdev/src/lcs.c @@ -15,6 +15,7 @@ #include "ccwgroup.h" #include "device.h" #include "devtype.h" +#include "internal.h" #include "lcs.h" #include "lcs_auto.h" #include "misc.h" @@ -362,6 +363,7 @@ static struct subtype lcs_subtype = { &ccw_attr_online, &lcs_attr_lancmd_timeout, &lcs_attr_recover, + &internal_attr_early, ), .unknown_dev_attribs = 1, .support_definable = 1, diff --git a/zdev/src/qeth.c b/zdev/src/qeth.c index 07b8d8e9..46bc23d6 100644 --- a/zdev/src/qeth.c +++ b/zdev/src/qeth.c @@ -15,6 +15,7 @@ #include "ccwgroup.h" #include "device.h" #include "devtype.h" +#include "internal.h" #include "misc.h" #include "namespace.h" #include "nic.h" @@ -1445,6 +1446,7 @@ struct subtype qeth_subtype_qeth = { &qeth_attr_vnicc_takeover_learning, &qeth_attr_vnicc_bridge_invisible, &qeth_attr_vnicc_rx_bcast, + &internal_attr_early, ), .unknown_dev_attribs = 1, .support_definable = 1, diff --git a/zdev/src/root.c b/zdev/src/root.c index 173071b7..a6d9e0cc 100644 --- a/zdev/src/root.c +++ b/zdev/src/root.c @@ -8,11 +8,13 @@ */ #include +#include #include "lib/util_path.h" #include "device.h" #include "devtype.h" +#include "internal.h" #include "misc.h" #include "path.h" #include "root.h" @@ -20,31 +22,78 @@ #include "setting.h" #include "subtype.h" -/* Determine if the root device was modified. If it was modified, run the - * corresponding root-install scripts. */ +static bool is_early_removed(struct device *dev) +{ + struct setting *s; + + s = setting_list_find(dev->persistent.settings, + internal_attr_early.name); + if (!s || !s->modified) + return false; + if (!s->actual_value || strcmp(s->actual_value, "1") != 0) + return false; + if (s->removed || strcmp(s->value, "0") == 0) + return true; + return false; +} + +static void add_early_removed(struct util_list *selected) +{ + int i, j; + struct devtype *dt; + struct subtype *st; + struct device *dev; + + for (i = 0; devtypes[i]; i++) { + dt = devtypes[i]; + for (j = 0; dt->subtypes[j]; j++) { + st = dt->subtypes[j]; + util_list_iterate(&st->devices->hash.list, dev) { + if (is_early_removed(dev)) { + selected_dev_list_add(selected, dt, st, + dev->id, NULL, EXIT_OK); + } + } + } + } +} + +/* Determine if initial RAM-disk needs updating. If so, run the corresponding + * scripts if available. */ exit_code_t root_check(void) { struct util_list *selected, *params, *mod = NULL; struct selected_dev_node *sel; struct device *dev; char *params_str; - exit_code_t rc; + exit_code_t rc = EXIT_OK; struct strlist_node *s; struct devtype *dt; + struct select_opts *select; - debug("Checking for modified root device configuration\n"); + debug("Checking for required initial RAM-disk update\n"); - /* Get list of devices that provide the root device. */ + /* Get list of devices that provide the root device or require + * early configuration. */ selected = selected_dev_list_new(); - rc = select_by_path(NULL, selected, config_active, scope_mandatory, - NULL, NULL, PATH_ROOT, err_ignore); - if (rc) { + /* First add devices that had zdev:early removed or changed to 0. + * The subsequent call to select_devices() will filter out any + * duplicates. */ + add_early_removed(selected); + /* Now add devices required for root file system. */ + if (select_by_path(NULL, selected, config_active, scope_mandatory, + NULL, NULL, PATH_ROOT, err_ignore)) { /* Running from an unknown root device is not an error. */ verb("Note: Could not determine if root device configuration " "needs to be updated\n"); - rc = 0; - goto out; } + /* Finally add devices with zdev:early=1. */ + select = select_opts_new(); + strlist_add(&select->by_attr, "%s=1", INTERNAL_ATTR_EARLY); + select_devices(select, selected, 1, 0, 0, + config_active | config_persistent, scope_mandatory, + err_ignore); + select_opts_free(select); /* Determine if any of the devices or device types has been modified. */ mod = strlist_new(); @@ -68,19 +117,18 @@ exit_code_t root_check(void) if (util_list_is_empty(mod)) goto out; - info("Note: Some of the changes affect devices providing the root " - "file system:\n"); + info("Note: The initial RAM-disk must be updated for these changes to take effect:\n"); util_list_iterate(mod, s) info(" - %s\n", s->str); - info(" Additional steps such as rebuilding the RAM-disk might be " - "required.\n"); /* Check if script is available. */ - if (!util_path_is_reg_file(PATH_ROOT_SCRIPT)) + if (!util_path_is_reg_file(PATH_ROOT_SCRIPT)) { + warn("A manual update of the initial RAM-disk is required.\n"); goto out; + } /* Ask for confirmation. */ - if (!confirm("Update persistent root device configuration now?")) { + if (!confirm("Update initial RAM-disk now?")) { rc = EXIT_ABORTED; goto out; } @@ -97,7 +145,7 @@ exit_code_t root_check(void) /* Run update command. */ if (misc_system(err_delayed_print, "%s %s", PATH_ROOT_SCRIPT, params_str) != 0) { - error("Failure while updating root device configuration\n"); + error("Failure while updating initial RAM-disk\n"); delayed_print(DELAY_INDENT); rc = EXIT_RUNTIME_ERROR; } diff --git a/zdev/src/zfcp_host.c b/zdev/src/zfcp_host.c index 9e739734..729bc425 100644 --- a/zdev/src/zfcp_host.c +++ b/zdev/src/zfcp_host.c @@ -17,6 +17,7 @@ #include "ccw.h" #include "device.h" #include "devtype.h" +#include "internal.h" #include "misc.h" #include "path.h" #include "setting.h" @@ -247,6 +248,7 @@ struct subtype zfcp_host_subtype = { &zfcp_host_attr_failed, &zfcp_host_attr_port_remove, &zfcp_host_attr_port_rescan, + &internal_attr_early, ), .unknown_dev_attribs = 1, diff --git a/zdev/src/zfcp_lun.c b/zdev/src/zfcp_lun.c index d5a148e6..f16cbfd8 100644 --- a/zdev/src/zfcp_lun.c +++ b/zdev/src/zfcp_lun.c @@ -21,6 +21,7 @@ #include "devnode.h" #include "devtype.h" #include "misc.h" +#include "internal.h" #include "namespace.h" #include "path.h" #include "scsi.h" @@ -1097,6 +1098,7 @@ struct subtype zfcp_lun_subtype = { &zfcp_lun_attr_scsi_timeout, &zfcp_lun_attr_scsi_state, &zfcp_lun_attr_scsi_delete, + &internal_attr_early, ), .prefixes = STRING_ARRAY(SCSI_ATTR_PREFIX), .unknown_dev_attribs = 1,