mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
zdev: Implement internal device attributes
This change adds base infrastructure for implementing internal device
attributes. In the context of the zdev tools, an internal device
attribute is a new type of device attribute with the following
characteristics:
- Can be set and removed like normal device attributes
- Affects zdev-internal handling only
- Does not correspond to an actual device attribute, that is
it has no representation in SysFS
- Can not be set in the active configuration
- Name starts with "zdev:" to prevent conflicts with actual
device attributes
Values for internal device attributes are stored in udev rules alongside
the normal persistent configuration of a device. They are encoded as
udev environment variables. Note that they have no further effect on
udev processing.
Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
3c5644ccfd
commit
c0392efa39
@@ -8,7 +8,7 @@ ALL_CPPFLAGS += -I ../include -std=gnu99 -Wno-unused-parameter \
|
||||
chzdev_objects += attrib.o chzdev.o device.o devnode.o devtype.o exit_code.o \
|
||||
export.o hash.o inuse.o misc.o namespace.o opts.o path.o \
|
||||
root.o select.o setting.o subtype.o table.o table_attribs.o \
|
||||
table_types.o net.o firmware.o
|
||||
table_types.o net.o firmware.o internal.o
|
||||
|
||||
# Devtype Helpers
|
||||
chzdev_objects += blkinfo.o ccw.o ccwgroup.o findmnt.o modprobe.o module.o \
|
||||
@@ -38,7 +38,7 @@ chzdev_objects += generic_ccw.o
|
||||
lszdev_objects += attrib.o lszdev.o device.o devnode.o devtype.o exit_code.o \
|
||||
export.o hash.o inuse.o misc.o namespace.o opts.o path.o \
|
||||
root.o select.o setting.o subtype.o table.o table_types.o \
|
||||
net.o
|
||||
net.o internal.o
|
||||
|
||||
# Devtype Helpers
|
||||
lszdev_objects += blkinfo.o ccw.o ccwgroup.o findmnt.o modprobe.o module.o \
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "attrib.h"
|
||||
#include "device.h"
|
||||
#include "devtype.h"
|
||||
#include "internal.h"
|
||||
#include "misc.h"
|
||||
#include "namespace.h"
|
||||
#include "setting.h"
|
||||
@@ -221,6 +222,9 @@ static exit_code_t apply_setting(struct device *dev, config_t config,
|
||||
goto err_activeonly_forceable;
|
||||
if (!force && SCOPE_AUTOCONF(config) && a->activeonly)
|
||||
goto err_activeonly_forceable;
|
||||
/* Check for internal. */
|
||||
if (config == config_active && a->internal)
|
||||
goto err_int_noactive;
|
||||
/* Check for multiple values. */
|
||||
if (!force && !a->multi && strlist_find(processed, key))
|
||||
goto err_multi_forceable;
|
||||
@@ -230,6 +234,9 @@ static exit_code_t apply_setting(struct device *dev, config_t config,
|
||||
goto err_unknown;
|
||||
if (!force)
|
||||
goto err_unknown_forceable;
|
||||
/* Check for internal. */
|
||||
if (config == config_active && internal_by_name(key))
|
||||
goto err_int_noactive;
|
||||
}
|
||||
|
||||
strlist_add(processed, "%s", key);
|
||||
@@ -294,6 +301,11 @@ err_activeonly_forceable:
|
||||
delayed_forceable("Attribute '%s' should only be changed in the active "
|
||||
"config\n", a->name);
|
||||
return EXIT_INVALID_SETTING;
|
||||
|
||||
err_int_noactive:
|
||||
delayed_err("Internal attribute '%s' cannot be set in the active config\n",
|
||||
key);
|
||||
return EXIT_INVALID_SETTING;
|
||||
}
|
||||
|
||||
/* Apply device settings from strlist to device. */
|
||||
@@ -542,6 +554,9 @@ exit_code_t device_write_active_settings(struct device *dev)
|
||||
s = p->ptr;
|
||||
if (!s->modified || s->removed)
|
||||
continue;
|
||||
if ((s->attrib && s->attrib->internal) ||
|
||||
internal_by_name(s->name))
|
||||
continue;
|
||||
|
||||
path = subtype_get_active_attrib_path(st, dev, s->name);
|
||||
if (!path) {
|
||||
|
||||
25
zdev/src/internal.c
Normal file
25
zdev/src/internal.c
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* zdev - Modify and display the persistent configuration of devices
|
||||
*
|
||||
* Copyright IBM Corp. 2017
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "misc.h"
|
||||
|
||||
/* Return identifier of internal attribute with specified @name. */
|
||||
const char *internal_get_name(const char *name)
|
||||
{
|
||||
return name + sizeof(INTERNAL_ATTR_PREFIX) - 1;
|
||||
}
|
||||
|
||||
/* Check if attribute is internal by name. */
|
||||
bool internal_by_name(const char *name)
|
||||
{
|
||||
return starts_with(name, INTERNAL_ATTR_PREFIX);
|
||||
}
|
||||
@@ -1717,3 +1717,18 @@ void debug_init(int argc, char *argv[])
|
||||
fprintf(stderr, "%s\"%s\"", i > 0 ? ", " : "", argv[i]);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
/* Return the last occurrence of @needle in @haystack, or %NULL if @needle
|
||||
* was not found. */
|
||||
char *misc_strrstr(const char *haystack, const char *needle)
|
||||
{
|
||||
char *result, *next;
|
||||
|
||||
result = strstr(haystack, needle);
|
||||
if (result) {
|
||||
while ((next = strstr(result + 1, needle)))
|
||||
result = next;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -409,3 +409,35 @@ void udev_settle(void)
|
||||
return;
|
||||
misc_system(err_ignore, "%s settle", PATH_UDEVADM);
|
||||
}
|
||||
|
||||
/* Extract internal attribute settings from @entry and add to @list.
|
||||
* Associate corresponding attribute if found in @attribs. */
|
||||
void udev_add_internal_from_entry(struct setting_list *list,
|
||||
struct udev_entry_node *entry,
|
||||
struct attrib **attribs)
|
||||
{
|
||||
char *copy, *name, *end, *u;
|
||||
struct attrib *a;
|
||||
|
||||
/* ENV{zdev_var}="1" */
|
||||
copy = misc_strdup(entry->key);
|
||||
|
||||
/* Find attribute name start. */
|
||||
name = strchr(copy, '{');
|
||||
end = strrchr(copy, '}');
|
||||
if (!name || !end)
|
||||
goto out;
|
||||
*end = 0;
|
||||
name++;
|
||||
|
||||
/* zdev_ => zdev: */
|
||||
u = strchr(name, '_');
|
||||
if (u)
|
||||
*u = ':';
|
||||
|
||||
a = attrib_find(attribs, name);
|
||||
setting_list_apply_actual(list, a, name, entry->value);
|
||||
|
||||
out:
|
||||
free(copy);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "attrib.h"
|
||||
#include "ccw.h"
|
||||
#include "device.h"
|
||||
#include "internal.h"
|
||||
#include "misc.h"
|
||||
#include "path.h"
|
||||
#include "setting.h"
|
||||
@@ -49,6 +50,12 @@ static void add_setting_from_entry(struct setting_list *list,
|
||||
char *copy, *name, *end;
|
||||
struct attrib *a;
|
||||
|
||||
/* ENV{zdev_var}="1" */
|
||||
if (starts_with(entry->key, "ENV{zdev_") &&
|
||||
strcmp(entry->op, "=") == 0) {
|
||||
udev_add_internal_from_entry(list, entry, attribs);
|
||||
return;
|
||||
}
|
||||
/* ATTR{[ccw/0.0.37bf]online}=1 */
|
||||
if (strncmp(entry->key, "ATTR{[ccw/", 10) != 0 ||
|
||||
strcmp(entry->op, "=") != 0)
|
||||
@@ -190,7 +197,14 @@ exit_code_t udev_ccw_write_device(struct device *dev, bool autoconf)
|
||||
s = p->ptr;
|
||||
if (s->removed)
|
||||
continue;
|
||||
fprintf(fd, "ATTR{[ccw/%s]%s}=\"%s\"\n", id, s->name, s->value);
|
||||
if ((s->attrib && s->attrib->internal) ||
|
||||
internal_by_name(s->name)) {
|
||||
fprintf(fd, "ENV{zdev_%s}=\"%s\"\n",
|
||||
internal_get_name(s->name), s->value);
|
||||
} else {
|
||||
fprintf(fd, "ATTR{[ccw/%s]%s}=\"%s\"\n", id, s->name,
|
||||
s->value);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write udev rule epilog. */
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "attrib.h"
|
||||
#include "ccwgroup.h"
|
||||
#include "device.h"
|
||||
#include "internal.h"
|
||||
#include "misc.h"
|
||||
#include "path.h"
|
||||
#include "setting.h"
|
||||
@@ -68,6 +69,12 @@ static void add_setting_from_entry(struct setting_list *list,
|
||||
char *copy, *name, *end;
|
||||
struct attrib *a;
|
||||
|
||||
/* ENV{zdev_var}="1" */
|
||||
if (starts_with(entry->key, "ENV{zdev_") &&
|
||||
strcmp(entry->op, "=") == 0) {
|
||||
udev_add_internal_from_entry(list, entry, attribs);
|
||||
return;
|
||||
}
|
||||
/* ATTR{[ccwgroup/0.0.f5f0]online}=1 */
|
||||
if (strncmp(entry->key, "ATTR{[ccwgroup/", 10) != 0 ||
|
||||
strcmp(entry->op, "=") != 0)
|
||||
@@ -282,6 +289,10 @@ exit_code_t udev_ccwgroup_write_device(struct device *dev, bool autoconf)
|
||||
fprintf(fd, "ATTR{[ccwgroup/%s]%s}=\"%s\"\n",
|
||||
ccw_id, s->name, str->str);
|
||||
}
|
||||
} else if ((s->attrib && s->attrib->internal) ||
|
||||
internal_by_name(s->name)) {
|
||||
fprintf(fd, "ENV{zdev_%s}=\"%s\"\n",
|
||||
internal_get_name(s->name), s->value);
|
||||
} else {
|
||||
fprintf(fd, "ATTR{[ccwgroup/%s]%s}=\"%s\"\n", ccw_id,
|
||||
s->name, s->value);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "attrib.h"
|
||||
#include "device.h"
|
||||
#include "internal.h"
|
||||
#include "misc.h"
|
||||
#include "path.h"
|
||||
#include "scsi.h"
|
||||
@@ -128,7 +129,7 @@ static bool zfcp_lun_devid_from_entry(struct zfcp_lun_devid *id_ptr,
|
||||
struct udev_entry_node *entry)
|
||||
{
|
||||
struct zfcp_lun_devid id;
|
||||
char *copy = NULL, *s;
|
||||
char *copy = NULL, *s, *e, *u;
|
||||
int i;
|
||||
bool rc = false;
|
||||
|
||||
@@ -182,6 +183,28 @@ static bool zfcp_lun_devid_from_entry(struct zfcp_lun_devid *id_ptr,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*ENV{zdev_var__0_0_1941_0x500507630510c1ae_0x402340d400000000}="1"*/
|
||||
if (starts_with(entry->key, "ENV{zdev_")) {
|
||||
copy = misc_strdup(entry->key);
|
||||
|
||||
/* Find ID start (last __) and end (last }). */
|
||||
s = misc_strrstr(copy, "__");
|
||||
e = strrchr(copy, '}');
|
||||
if (!s || !e)
|
||||
goto out;
|
||||
*e = 0;
|
||||
s += 2;
|
||||
/* Convert variable name to ID format. */
|
||||
for (i = 0, u = s; (u = strchr(u, '_')); i++, u++) {
|
||||
if (i < 2)
|
||||
*u = '.';
|
||||
else
|
||||
*u = ':';
|
||||
}
|
||||
rc = zfcp_lun_parse_devid(&id, s, err_ignore) == EXIT_OK ?
|
||||
true : false;
|
||||
}
|
||||
|
||||
out:
|
||||
free(copy);
|
||||
if (rc)
|
||||
@@ -211,11 +234,46 @@ static struct zfcp_lun_node *zfcp_lun_node_from_entry(
|
||||
return node;
|
||||
}
|
||||
|
||||
static void add_internal_setting_from_entry(struct udev_entry_node *entry,
|
||||
struct zfcp_lun_node *node)
|
||||
{
|
||||
char *copy, *name, *end, *u;
|
||||
struct attrib *a;
|
||||
|
||||
/*ENV{zdev_var__0_0_1941_0x500507630510c1ae_0x402340d400000000}="1"*/
|
||||
copy = misc_strdup(entry->key);
|
||||
|
||||
/* Find attribute name start and end. */
|
||||
name = strchr(copy, '{');
|
||||
end = misc_strrstr(copy, "__");
|
||||
if (!name || !end)
|
||||
goto out;
|
||||
*end = 0;
|
||||
name++;
|
||||
|
||||
/* zdev_ => zdev: */
|
||||
u = strchr(name, '_');
|
||||
if (u)
|
||||
*u = ':';
|
||||
|
||||
a = attrib_find(zfcp_lun_subtype.dev_attribs, name);
|
||||
setting_list_apply_actual(node->fc_settings, a, name, entry->value);
|
||||
|
||||
out:
|
||||
free(copy);
|
||||
}
|
||||
|
||||
static void add_fc_setting_from_entry(struct udev_entry_node *entry,
|
||||
struct zfcp_lun_node *node)
|
||||
{
|
||||
char *copy, *s, *e;
|
||||
|
||||
/*ENV{zdev_var__0_0_1941_0x500507630510c1ae_0x402340d400000000}="1"*/
|
||||
if (starts_with(entry->key, "ENV{zdev_") &&
|
||||
strcmp(entry->op, "=") == 0) {
|
||||
add_internal_setting_from_entry(entry, node);
|
||||
return;
|
||||
}
|
||||
/*ATTR{[ccw/0.0.1941]0x500507630510c1ae/0x402340d400000000/failed}="0"*/
|
||||
if (!starts_with(entry->key, "ATTR{[ccw/"))
|
||||
return;
|
||||
@@ -490,7 +548,7 @@ static struct zfcp_lun_node *state_to_zfcp_lun_node(struct zfcp_lun_devid *id,
|
||||
s->value);
|
||||
setting_list_add(node->scsi_settings, n);
|
||||
} else {
|
||||
n = setting_new(NULL, s->name, s->value);
|
||||
n = setting_new(s->attrib, s->name, s->value);
|
||||
setting_list_add(node->fc_settings, n);
|
||||
}
|
||||
}
|
||||
@@ -580,9 +638,21 @@ static exit_code_t write_luns_rule(const char *path, struct util_list *list)
|
||||
node->id.lun);
|
||||
|
||||
util_list_iterate(&node->fc_settings->list, s) {
|
||||
fprintf(fd, "ATTR{[ccw/%s]0x%016" PRIx64 "/0x%016"
|
||||
PRIx64 "/%s}=\"%s\"\n", hba_id, node->id.wwpn,
|
||||
node->id.lun, s->name, s->value);
|
||||
if ((s->attrib && s->attrib->internal) ||
|
||||
internal_by_name(s->name)) {
|
||||
fprintf(fd, "ENV{zdev_%s__%x_%x_%04x_0x%016"
|
||||
PRIx64 "_0x%016" PRIx64 "}=\"%s\"\n",
|
||||
internal_get_name(s->name),
|
||||
node->id.fcp_dev.cssid,
|
||||
node->id.fcp_dev.ssid,
|
||||
node->id.fcp_dev.devno, node->id.wwpn,
|
||||
node->id.lun, s->value);
|
||||
} else {
|
||||
fprintf(fd, "ATTR{[ccw/%s]0x%016" PRIx64
|
||||
"/0x%016" PRIx64 "/%s}=\"%s\"\n",
|
||||
hba_id, node->id.wwpn, node->id.lun,
|
||||
s->name, s->value);
|
||||
}
|
||||
}
|
||||
last_node = node;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user