Add a new command 'daxctl-reconfigure-device'. This is used to switch the mode of a dax device between regular 'device_dax' and 'system-memory'. The command also uses the memory hotplug sysfs interfaces to online the newly available memory when converting to 'system-ram', and to attempt to offline the memory when converting back to a DAX device.
Cc: Pavel Tatashin <pasha.tatas...@soleen.com> Cc: Dave Hansen <dave.han...@linux.intel.com> Cc: Dan Williams <dan.j.willi...@intel.com> Signed-off-by: Vishal Verma <vishal.l.ve...@intel.com> --- daxctl/Makefile.am | 2 + daxctl/builtin.h | 1 + daxctl/daxctl.c | 1 + daxctl/device.c | 217 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 221 insertions(+) create mode 100644 daxctl/device.c diff --git a/daxctl/Makefile.am b/daxctl/Makefile.am index 94f73f9..66dcc7f 100644 --- a/daxctl/Makefile.am +++ b/daxctl/Makefile.am @@ -15,10 +15,12 @@ daxctl_SOURCES =\ daxctl.c \ list.c \ migrate.c \ + device.c \ ../util/json.c daxctl_LDADD =\ lib/libdaxctl.la \ ../libutil.a \ $(UUID_LIBS) \ + $(KMOD_LIBS) \ $(JSON_LIBS) diff --git a/daxctl/builtin.h b/daxctl/builtin.h index 00ef5e9..756ba2a 100644 --- a/daxctl/builtin.h +++ b/daxctl/builtin.h @@ -6,4 +6,5 @@ struct daxctl_ctx; int cmd_list(int argc, const char **argv, struct daxctl_ctx *ctx); int cmd_migrate(int argc, const char **argv, struct daxctl_ctx *ctx); +int cmd_reconfig_device(int argc, const char **argv, struct daxctl_ctx *ctx); #endif /* _DAXCTL_BUILTIN_H_ */ diff --git a/daxctl/daxctl.c b/daxctl/daxctl.c index 2e41747..e1ba7b8 100644 --- a/daxctl/daxctl.c +++ b/daxctl/daxctl.c @@ -71,6 +71,7 @@ static struct cmd_struct commands[] = { { "list", .d_fn = cmd_list }, { "help", .d_fn = cmd_help }, { "migrate-device-model", .d_fn = cmd_migrate }, + { "reconfigure-device", .d_fn = cmd_reconfig_device }, }; int main(int argc, const char **argv) diff --git a/daxctl/device.c b/daxctl/device.c new file mode 100644 index 0000000..0a6102f --- /dev/null +++ b/daxctl/device.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2019 Intel Corporation. All rights reserved. */ +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#include <util/json.h> +#include <util/filter.h> +#include <json-c/json.h> +#include <daxctl/libdaxctl.h> +#include <util/parse-options.h> +#include <ccan/array_size/array_size.h> + +static struct { + const char *dev; + const char *mode; + int region_id; + bool no_online; + bool do_offline; + bool human; + bool verbose; +} param = { + .region_id = -1, +}; + +static int dev_disable(struct daxctl_dev *dev) +{ + int rc; + + if (!daxctl_dev_is_enabled(dev)) + return 0; + + rc = daxctl_dev_disable(dev); + if (rc) + fprintf(stderr, "%s: disable failed: %s\n", + daxctl_dev_get_devname(dev), strerror(-rc)); + + return rc; +} + +static int reconfig_mode_ram(struct daxctl_dev *dev) +{ + const char *devname = daxctl_dev_get_devname(dev); + int rc; + + rc = dev_disable(dev); + if (rc) + return rc; + rc = daxctl_dev_enable_ram(dev); + if (rc) + return rc; + + if (param.no_online) + return 0; + + rc = daxctl_dev_online_node(dev); + if (rc < 0) { + fprintf(stderr, "%s: unable to online memory: %s\n", + devname, strerror(-rc)); + return rc; + } + if (param.verbose) + fprintf(stderr, "%s: onlined %d memory sections\n", + devname, rc); + + return 0; +} + +static int reconfig_mode_devdax(struct daxctl_dev *dev) +{ + const char *devname = daxctl_dev_get_devname(dev); + int rc; + + if (param.do_offline) { + rc = daxctl_dev_offline_node(dev); + if (rc < 0) { + fprintf(stderr, "%s: unable to offline memory: %s\n", + devname, strerror(-rc)); + return rc; + } + if (param.verbose) + fprintf(stderr, "%s: offlined %d memory sections\n", + devname, rc); + } + + rc = daxctl_dev_node_is_online(dev); + if (rc < 0) { + fprintf(stderr, "%s: unable to determine node state: %s\n", + devname, strerror(-rc)); + return rc; + } + if (rc > 0) { + if (param.verbose) { + fprintf(stderr, "%s: found %d memory sections online\n", + devname, rc); + fprintf(stderr, "%s: refusing to change modes\n", + devname); + } + return -EBUSY; + } + + rc = dev_disable(dev); + if (rc) + return rc; + + rc = daxctl_dev_enable_devdax(dev); + if (rc) + return rc; + + return 0; +} + +static int do_reconfig(struct daxctl_dev *dev, unsigned long flags, + enum daxctl_dev_mode mode) +{ + int rc = 0; + + switch (mode) { + case DAXCTL_DEV_MODE_RAM: + rc = reconfig_mode_ram(dev); + break; + case DAXCTL_DEV_MODE_DEVDAX: + rc = reconfig_mode_devdax(dev); + break; + default: + fprintf(stderr, "%s: unknown mode: %d\n", + daxctl_dev_get_devname(dev), mode); + rc = -EINVAL; + } + + return rc; +} + +int cmd_reconfig_device(int argc, const char **argv, struct daxctl_ctx *ctx) +{ + const struct option options[] = { + OPT_INTEGER('r', "region", ¶m.region_id, + "restrict to the given region"), + 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('\0', "attempt-offline", ¶m.do_offline, + "attempt to offline memory sections"), + OPT_BOOLEAN('u', "human", ¶m.human, + "use human friendly number formats"), + OPT_BOOLEAN('v', "verbose", ¶m.verbose, + "emit more debug messages"), + OPT_END(), + }; + const char * const u[] = { + "daxctl reconfigure-device [<options>] <device> ...", + NULL + }; + enum daxctl_dev_mode mode = DAXCTL_DEV_MODE_UNKNOWN; + struct daxctl_region *region; + int i, rc = 0, done = 0; + unsigned long flags = 0; + struct daxctl_dev *dev; + + argc = parse_options(argc, argv, options, u, 0); + if (argc == 0) + usage_with_options(u, options); + for (i = 0; i < argc; i++) { + if (strcmp(argv[i], "all") == 0) { + argv[0] = "all"; + argc = 1; + break; + } + } + + if (param.human) + flags |= UTIL_JSON_HUMAN; + + if (!param.mode) { + fprintf(stderr, "error: a 'mode' option is required\n"); + usage_with_options(u, options); + } + if (strcmp(param.mode, "system-ram") == 0) + mode = DAXCTL_DEV_MODE_RAM; + else if (strcmp(param.mode, "devdax") == 0) + mode = DAXCTL_DEV_MODE_DEVDAX; + + daxctl_region_foreach(ctx, region) { + if (param.region_id >= 0 && param.region_id + != daxctl_region_get_id(region)) + continue; + + daxctl_dev_foreach(region, dev) { + bool dev_requested = false; + + for (i = 0; i < argc; i++) { + if ((strcmp(daxctl_dev_get_devname(dev), + argv[i]) == 0) || + (strcmp(argv[i], "all") == 0)) { + dev_requested = true; + break; + } + } + if (dev_requested) { + rc = do_reconfig(dev, flags, mode); + if (rc < 0) + goto out_err; + done++; + } + } + } + fprintf(stderr, "reconfigured %d device%s\n", done, + done == 1 ? "" : "s"); + return 0; + +out_err: + fprintf(stderr, "error reconfiguring %s: %s\n", + daxctl_dev_get_devname(dev), strerror(-rc)); + return rc; +} -- 2.20.1 _______________________________________________ Linux-nvdimm mailing list Linux-nvdimm@lists.01.org https://lists.01.org/mailman/listinfo/linux-nvdimm