@@ -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)
@@ -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_ */
@@ -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)
new file mode 100644
@@ -0,0 +1,237 @@
+// 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, 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('O', "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 json_object *jdevs = json_object_new_array();
+ struct daxctl_region *region;
+ struct json_object *jdev;
+ 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;
+ if (param.do_offline) {
+ fprintf(stderr,
+ "can't --attempt-offline for system-ram mode\n");
+ return -EINVAL;
+ }
+ } else if (strcmp(param.mode, "devdax") == 0) {
+ mode = DAXCTL_DEV_MODE_DEVDAX;
+ if (param.no_online) {
+ fprintf(stderr,
+ "can't --no-online for devdax mode\n");
+ return -EINVAL;
+ }
+ }
+
+ 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, mode);
+ if (rc < 0)
+ goto out_err;
+ done++;
+ if (!jdevs)
+ continue;
+ jdev = util_daxctl_dev_to_json(dev, flags);
+ if (jdev)
+ json_object_array_add(jdevs, jdev);
+ }
+ }
+ }
+ if (jdevs)
+ util_display_json_array(stdout, jdevs, flags);
+
+ 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;
+}
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.tatashin@soleen.com> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: Dan Williams <dan.j.williams@intel.com> Signed-off-by: Vishal Verma <vishal.l.verma@intel.com> --- daxctl/Makefile.am | 2 + daxctl/builtin.h | 1 + daxctl/daxctl.c | 1 + daxctl/device.c | 237 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 241 insertions(+) create mode 100644 daxctl/device.c