Subject: zdev: Write zfcp-lun udev rules to separate files From: Peter Oberparleiter Summary: zdev: Add support for handling I/O configuration data Description: LPARs that are running in IBM Dynamic Partition Manager (DPM) mode can access a firmware-generated I/O configuration data file that contains s390-specific information about available I/O devices such as qeth device numbers and parameters, and FCP device IDs. This data file is intended to remove the need for users to manually enter the corresponding device data during installation. Linux kernels with the corresponding support make the I/O configuration data available at the following location: /sys/firmware/sclp_sd/config/data This patch set adds support for handling this data file using the chzdev and lszdev tools: - I/O configuration data can be applied using chzdev's --import option - Initial RAM-Disk scripts automatically apply the I/O configuration data to the system configuration - lszdev can be used to display the applied auto-configuration data - chzdev can be used to manually override the auto-configuration data Upstream-ID: a86fb8b09118e6de7463882f889eff7e278163cd Problem-ID: LS1604 Upstream-Description: zdev: Write zfcp-lun udev rules to separate files Change chzdev's udev rule generation from the previous approach of combining all zfcp-lun udev rules associated with an FCP device into a single file to storing zfcp-lun udev rules in one file per zfcp-lun. This is done to enable per-device udev rule masking. With udev rule masking, if a udev rule file by the same name exists in both /etc and /run, the udev daemon will only consider the rules found in /etc. The auto-configuration feature will make use of per-device udev rule masking to introduce a new class of configuration data (stored in /run) that is only active if no user-provided configuration data (in /etc) exists. In addition, change chzdev to allow the regeneration of udev rules by using the --force command line like in the following example: # chzdev zfcp-lun --configured --enable --persistent --force This can be used to convert all existing zfcp-lun udev rules from the old format to the new one. Signed-off-by: Peter Oberparleiter Signed-off-by: Jan Höppner Signed-off-by: Peter Oberparleiter --- zdev/src/chzdev.c | 6 +++- zdev/src/root.c | 2 - zdev/src/udev_zfcp_lun.c | 56 ++++++++++++++++++++++++++++++++++----- 3 files changed, 55 insertions(+), 9 deletions(-) --- a/zdev/src/chzdev.c +++ b/zdev/src/chzdev.c @@ -1333,7 +1333,7 @@ static exit_code_t cfg_write(struct devi struct subtype *st = dev->subtype; exit_code_t rc = EXIT_OK; - if (!device_needs_writing(dev, config)) + if (!device_needs_writing(dev, config) && !force) goto out; if (check_active && config == config_persistent && @@ -1624,6 +1624,10 @@ static exit_code_t print_config_result(s already = device_needs_writing(dev, config) ? 0 : 1; } + /* Re-do actions if run with --force */ + if (force) + already = 0; + if (dev) { devname = dev->subtype->devname; devid = dev->id; --- a/zdev/src/root.c +++ b/zdev/src/root.c @@ -60,7 +60,7 @@ exit_code_t root_check(void) /* Check devices. */ dev = device_list_find(sel->st->devices, sel->id, NULL); if (dev && dev->persistent.exists && - device_needs_writing(dev, config_persistent)) { + (device_needs_writing(dev, config_persistent) || force)) { strlist_add(mod, "%s %s", dev->subtype->devname, dev->id); } --- a/zdev/src/udev_zfcp_lun.c +++ b/zdev/src/udev_zfcp_lun.c @@ -385,6 +385,8 @@ void udev_zfcp_lun_add_device_ids(struct free(cb_data.prefix); } +/* Return path to zfcp lun udev rule file containing configuration data for + * all LUNs of a zfcp device. */ static char *get_zfcp_lun_path(const char *id) { char *copy, *e, *path; @@ -399,6 +401,13 @@ static char *get_zfcp_lun_path(const cha return path; } +/* Return path to zfcp lun udev rule file containing configuration data for + * a single LUN. */ +static char *get_single_zfcp_lun_path(const char *id) +{ + return path_get_udev_rule(ZFCP_LUN_NAME, id); +} + /* Apply the settings found in NODE to STATE. */ static void zfcp_lun_node_to_state(struct zfcp_lun_node *node, struct attrib **attribs, @@ -437,7 +446,12 @@ exit_code_t udev_zfcp_lun_read_device(st exit_code_t rc = EXIT_OK; char *path; - path = get_zfcp_lun_path(dev->id); + /* Check for single lun file first then try multi lun file. */ + path = get_single_zfcp_lun_path(dev->id); + if (!util_path_exists(path)) { + free(path); + path = get_zfcp_lun_path(dev->id); + } /* Get previous rule data. */ luns = zfcp_lun_node_list_new(); @@ -599,8 +613,10 @@ out: /* Update the udev rule file that configures the zfcp lun with the specified * ID. If @state is %NULL, remove the rule, otherwise create a rule that - * applies the corresponding parameters. */ -static exit_code_t update_lun_rule(const char *id, struct device_state *state) + * applies the corresponding parameters. If @single is set, update a single + * lun rule file, otherwise update a multi lun rule file. */ +static exit_code_t update_lun_rule(const char *id, struct device_state *state, + bool single) { struct zfcp_lun_devid devid; struct util_list *luns; @@ -612,7 +628,7 @@ static exit_code_t update_lun_rule(const rc = zfcp_lun_parse_devid(&devid, id, err_delayed_print); if (rc) return rc; - path = get_zfcp_lun_path(id); + path = single ? get_single_zfcp_lun_path(id) : get_zfcp_lun_path(id); /* Get previous rule data. */ luns = zfcp_lun_node_list_new(); @@ -650,24 +666,50 @@ static exit_code_t update_lun_rule(const * device state. */ exit_code_t udev_zfcp_lun_write_device(struct device *dev) { - return update_lun_rule(dev->id, &dev->persistent); + exit_code_t rc; + + rc = update_lun_rule(dev->id, &dev->persistent, true); + + /* We only want single lun rule files so remove any remaining + * references in multi lun rule files. */ + update_lun_rule(dev->id, NULL, false); + + return rc; } /* Remove the UDEV rule used to configure the zfcp lun with the specified ID. */ exit_code_t udev_zfcp_lun_remove_rule(const char *id) { - return update_lun_rule(id, NULL); + exit_code_t rc, rc2; + + rc = update_lun_rule(id, NULL, true); + rc2 = update_lun_rule(id, NULL, false); + + if (rc) + return rc; + + return rc2; } /* Determine if a udev rule exists for configuring the specified zfcp lun. */ bool udev_zfcp_lun_exists(const char *id) { struct zfcp_lun_devid devid; - char *path, *rule, *pattern = NULL; + char *path, *rule = NULL, *pattern = NULL; bool rc = false; if (zfcp_lun_parse_devid(&devid, id, err_ignore) != EXIT_OK) return false; + + /* Check for single lun rule file first. */ + path = get_single_zfcp_lun_path(id); + if (util_path_exists(path)) { + rc = true; + goto out; + } + free(path); + + /* Check multi lun rule file next. */ path = get_zfcp_lun_path(id); rule = misc_read_text_file(path, 1, err_ignore); if (!rule)