diff options
author | Vishal Verma <vishal.l.verma@intel.com> | 2021-12-10 15:34:38 -0700 |
---|---|---|
committer | Vishal Verma <vishal.l.verma@intel.com> | 2021-12-17 10:56:33 -0700 |
commit | 33a3791218da499d8de8ade1f4e04b3a5c0431f7 (patch) | |
tree | e64f9c53f6dfbdd21e51d07b1cdb46563149a027 | |
parent | 27cec4f0ca274e78d8444425e3b63f479759b9a6 (diff) |
daxctl/device.c: add an option for getting params from a config file
Add a new option to daxctl-reconfigure-device that allows it to
comprehend the new global config system in ndctl/daxctl. With this, the
reconfigure-device command can query the config to match a specific
device UUID, and operate using the parameters supplied in that INI
section.
This is in preparation to make daxctl device reconfiguration (usually
as system-ram) policy based, so that reconfiguration can happen
automatically on boot.
Link: https://lore.kernel.org/r/20211210223440.3946603-10-vishal.l.verma@intel.com
Cc: QI Fuli <qi.fuli@fujitsu.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
-rw-r--r-- | daxctl/Makefile.am | 1 | ||||
-rw-r--r-- | daxctl/device.c | 174 |
2 files changed, 173 insertions, 2 deletions
diff --git a/daxctl/Makefile.am b/daxctl/Makefile.am index 7ee65c40..5cebb6cb 100644 --- a/daxctl/Makefile.am +++ b/daxctl/Makefile.am @@ -22,6 +22,7 @@ daxctl_SOURCES =\ daxctl_LDADD =\ lib/libdaxctl.la \ + ../ndctl/lib/libndctl.la \ ../libutil.a \ $(UUID_LIBS) \ $(KMOD_LIBS) \ diff --git a/daxctl/device.c b/daxctl/device.c index a427b7d2..c2ff0cc6 100644 --- a/daxctl/device.c +++ b/daxctl/device.c @@ -14,8 +14,10 @@ #include <util/filter.h> #include <json-c/json.h> #include <json-c/json_util.h> +#include <ndctl/libndctl.h> #include <daxctl/libdaxctl.h> #include <util/parse-options.h> +#include <util/parse-configs.h> #include <ccan/array_size/array_size.h> static struct { @@ -25,6 +27,7 @@ static struct { const char *size; const char *align; const char *input; + bool check_config; bool no_online; bool no_movable; bool force; @@ -65,6 +68,9 @@ enum device_action { ACTION_DESTROY, }; +#define CONF_SECTION "reconfigure-device" +#define CONF_NVDIMM_UUID_STR "nvdimm.uuid" + #define BASE_OPTIONS() \ OPT_STRING('r', "region", ¶m.region, "region-id", "filter by region"), \ OPT_BOOLEAN('u', "human", ¶m.human, "use human friendly number formats"), \ @@ -75,7 +81,9 @@ OPT_STRING('m', "mode", ¶m.mode, "mode", "mode to switch the device to"), \ OPT_BOOLEAN('N', "no-online", ¶m.no_online, \ "don't auto-online memory sections"), \ OPT_BOOLEAN('f', "force", ¶m.force, \ - "attempt to offline memory sections before reconfiguration") + "attempt to offline memory sections before reconfiguration"), \ +OPT_BOOLEAN('C', "check-config", ¶m.check_config, \ + "use config files to determine parameters for the operation") #define CREATE_OPTIONS() \ OPT_STRING('s', "size", ¶m.size, "size", "size to switch the device to"), \ @@ -218,6 +226,137 @@ err: return rc; } +static int conf_string_to_bool(const char *str) +{ + if (!str) + return INT_MAX; + if (strncmp(str, "t", 1) == 0 || + strncmp(str, "T", 1) == 0 || + strncmp(str, "y", 1) == 0 || + strncmp(str, "Y", 1) == 0 || + strncmp(str, "1", 1) == 0) + return true; + if (strncmp(str, "f", 1) == 0 || + strncmp(str, "F", 1) == 0 || + strncmp(str, "n", 1) == 0 || + strncmp(str, "N", 1) == 0 || + strncmp(str, "0", 1) == 0) + return false; + return INT_MAX; +} + +#define conf_assign_inverted_bool(p, conf_var) \ +do { \ + if (conf_string_to_bool(conf_var) != INT_MAX) \ + param.p = !conf_string_to_bool(conf_var); \ +} while(0) + +static int parse_config_reconfig_set_params(struct daxctl_ctx *ctx, const char *device, + const char *uuid) +{ + const char *conf_online = NULL, *conf_movable = NULL; + const struct config configs[] = { + CONF_SEARCH(CONF_SECTION, CONF_NVDIMM_UUID_STR, uuid, + "mode", ¶m.mode, NULL), + CONF_SEARCH(CONF_SECTION, CONF_NVDIMM_UUID_STR, uuid, + "online", &conf_online, NULL), + CONF_SEARCH(CONF_SECTION, CONF_NVDIMM_UUID_STR, uuid, + "movable", &conf_movable, NULL), + CONF_END(), + }; + const char *prefix = "./", *daxctl_configs; + int rc; + + daxctl_configs = daxctl_get_config_path(ctx); + if (daxctl_configs == NULL) + return 0; + + rc = parse_configs_prefix(daxctl_configs, prefix, configs); + if (rc < 0) + return rc; + + conf_assign_inverted_bool(no_online, conf_online); + conf_assign_inverted_bool(no_movable, conf_movable); + + return 0; +} + +static bool daxctl_ndns_has_device(struct ndctl_namespace *ndns, + const char *device) +{ + struct daxctl_region *dax_region; + struct ndctl_dax *dax; + + dax = ndctl_namespace_get_dax(ndns); + if (!dax) + return false; + + dax_region = ndctl_dax_get_daxctl_region(dax); + if (dax_region) { + struct daxctl_dev *dev; + + dev = daxctl_dev_get_first(dax_region); + if (dev) { + if (strcmp(daxctl_dev_get_devname(dev), device) == 0) + return true; + } + } + return false; +} + +static int parse_config_reconfig(struct daxctl_ctx *ctx, const char *device) +{ + struct ndctl_namespace *ndns; + struct ndctl_ctx *ndctl_ctx; + struct ndctl_region *region; + struct ndctl_bus *bus; + struct ndctl_dax *dax; + int rc, found = 0; + char uuid_buf[40]; + uuid_t uuid; + + if (strcmp(device, "all") == 0) + return 0; + + rc = ndctl_new(&ndctl_ctx); + if (rc < 0) + return rc; + + ndctl_bus_foreach(ndctl_ctx, bus) { + ndctl_region_foreach(bus, region) { + ndctl_namespace_foreach(region, ndns) { + if (daxctl_ndns_has_device(ndns, device)) { + dax = ndctl_namespace_get_dax(ndns); + if (!dax) + continue; + ndctl_dax_get_uuid(dax, uuid); + found = 1; + } + } + } + } + + if (!found) { + fprintf(stderr, "no UUID match for %s found in config files\n", + device); + return 0; + } + + uuid_unparse(uuid, uuid_buf); + return parse_config_reconfig_set_params(ctx, device, uuid_buf); +} + +static int parse_device_config(struct daxctl_ctx *ctx, const char *device, + enum device_action action) +{ + switch (action) { + case ACTION_RECONFIG: + return parse_config_reconfig(ctx, device); + default: + return 0; + } +} + static const char *parse_device_options(int argc, const char **argv, enum device_action action, const struct option *options, const char *usage, struct daxctl_ctx *ctx) @@ -228,8 +367,11 @@ static const char *parse_device_options(int argc, const char **argv, }; unsigned long long units = 1; int i, rc = 0; + char *device = NULL; argc = parse_options(argc, argv, options, u, 0); + if (argc > 0) + device = basename(argv[0]); /* Handle action-agnostic non-option arguments */ if (argc == 0 && @@ -279,6 +421,34 @@ static const char *parse_device_options(int argc, const char **argv, if (param.human) flags |= UTIL_JSON_HUMAN; + /* Scan config file(s) for options. This sets param.foo accordingly */ + if (device && param.check_config) { + if (param.mode || param.no_online || param.no_movable) { + fprintf(stderr, + "%s: -C cannot be used with --mode, --(no-)movable, or --(no-)online\n", + device); + usage_with_options(u, options); + } + rc = parse_device_config(ctx, device, action); + if (rc) { + fprintf(stderr, "error parsing config file: %s\n", + strerror(-rc)); + return NULL; + } + if (!param.mode && !param.no_online && !param.no_movable) { + fprintf(stderr, "%s: missing or malformed config section\n", + device); + /* + * Exit with success since the most common case is there is + * no config defined for this device, and we don't want to + * treat that as an error. There isn't an easy way currently + * to distinguish between a malformed config entry from a + * completely missing config section. + */ + exit(0); + } + } + /* Handle action-specific options */ switch (action) { case ACTION_RECONFIG: @@ -336,7 +506,7 @@ static const char *parse_device_options(int argc, const char **argv, return NULL; } - return argv[0]; + return device; } static int dev_online_memory(struct daxctl_dev *dev) |