All of lore.kernel.org
 help / color / mirror / Atom feed
From: Joao Martins <joao.m.martins@oracle.com>
To: linux-nvdimm@lists.01.org
Cc: Jason Zeng <jason.zeng@intel.com>
Subject: [PATCH ndctl v1 8/8] daxctl: Allow restore devices from JSON metadata
Date: Thu, 16 Jul 2020 19:47:07 +0100	[thread overview]
Message-ID: <20200716184707.23018-9-joao.m.martins@oracle.com> (raw)
In-Reply-To: <20200716184707.23018-1-joao.m.martins@oracle.com>

Add an option namely --restore which passes a parameter
which is a JSON file path. The JSON file contains the
data usually returned by:

	$ daxctl list -d dax0.1
	{
	  "chardev":"dax0.1",
	  "size":34359738368,
	  "target_node":0,
	  "align":1073741824,
	  "mode":"devdax",
	  "mappings":[
	    {
	      "page_offset":4194304,
	      "start":25769803776,
	      "end":42949672959,
	      "size":17179869184
	    },
	    {
	      "page_offset":0,
	      "start":8589934592,
	      "end":25769803775,
	      "size":17179869184
	    }
	  ]
	}

For purposes of RFC, the input values in the mapping json are decimal
for now. A device can then be created by specifying this same data
to restore it e.g.

	daxctl create-device -u --restore device.json
	{
	  "chardev":"dax0.1",
	  "size":"32.00 GiB (34.36 GB)",
	  "target_node":0,
	  "align":"1024.00 MiB (1073.74 MB)",
	  "mode":"devdax",
	  "mappings":[
	    {
	      "page_offset":"0x400000",
	      "start":"0x600000000",
	      "end":"0x9ffffffff",
	      "size":"16.00 GiB (17.18 GB)"
	    },
	    {
	      "page_offset":"0",
	      "start":"0x200000000",
	      "end":"0x5ffffffff",
	      "size":"16.00 GiB (17.18 GB)"
	    }
	  ]
	}

	created 1 device

This is handy as we are able to kexec and restore previously mappings
that we had established.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
---
 daxctl/device.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 124 insertions(+), 5 deletions(-)

diff --git a/daxctl/device.c b/daxctl/device.c
index 3a844462829b..fe34f0e44569 100644
--- a/daxctl/device.c
+++ b/daxctl/device.c
@@ -13,6 +13,7 @@
 #include <util/json.h>
 #include <util/filter.h>
 #include <json-c/json.h>
+#include <json-c/json_util.h>
 #include <daxctl/libdaxctl.h>
 #include <util/parse-options.h>
 #include <ccan/array_size/array_size.h>
@@ -23,6 +24,7 @@ static struct {
 	const char *region;
 	const char *size;
 	const char *align;
+	const char *restore;
 	bool no_online;
 	bool no_movable;
 	bool force;
@@ -36,10 +38,16 @@ enum dev_mode {
 	DAXCTL_DEV_MODE_RAM,
 };
 
+struct mapping {
+	unsigned long long start, end, pgoff;
+};
+
 static enum dev_mode reconfig_mode = DAXCTL_DEV_MODE_UNKNOWN;
 static long long align = -1;
 static long long size = -1;
 static unsigned long flags;
+static struct mapping *maps = NULL;
+static long long nmaps = -1;
 
 enum memory_zone {
 	MEM_ZONE_MOVABLE,
@@ -71,7 +79,9 @@ OPT_BOOLEAN('f', "force", &param.force, \
 
 #define CREATE_OPTIONS() \
 OPT_STRING('s', "size", &param.size, "size", "size to switch the device to"), \
-OPT_STRING('a', "align", &param.align, "align", "alignment to switch the device to")
+OPT_STRING('a', "align", &param.align, "align", "alignment to switch the device to"), \
+OPT_STRING('\0', "restore", &param.restore, "restore", \
+		"restore the device from device JSON")
 
 #define DESTROY_OPTIONS() \
 OPT_BOOLEAN('f', "force", &param.force, \
@@ -124,6 +134,94 @@ static const struct option destroy_options[] = {
 	OPT_END(),
 };
 
+static int sort_mappings(const void *a, const void *b)
+{
+	json_object **jsoa, **jsob;
+	struct json_object *va, *vb;
+	unsigned long long pga, pgb;
+
+	jsoa = (json_object **)a;
+	jsob = (json_object **)b;
+	if (!*jsoa && !*jsob)
+		return 0;
+
+	if (!json_object_object_get_ex(*jsoa, "page_offset", &va) ||
+	    !json_object_object_get_ex(*jsob, "page_offset", &vb))
+		return 0;
+
+	pga = json_object_get_int64(va);
+	pgb = json_object_get_int64(vb);
+
+	return pga > pgb;
+}
+
+static int parse_device_file(const char *filename)
+{
+	struct json_object *jobj, *jval = NULL, *jmappings = NULL;
+	int i, len, rc = -EINVAL, region_id, id;
+	const char *chardev;
+	char  *region = NULL;
+	struct mapping *m;
+
+	jobj = json_object_from_file(filename);
+	if (!jobj)
+		return rc;
+
+	if (!json_object_object_get_ex(jobj, "align", &jval))
+		return rc;
+	param.align = json_object_get_string(jval);
+
+	if (!json_object_object_get_ex(jobj, "size", &jval))
+		return rc;
+	param.size = json_object_get_string(jval);
+
+	if (!json_object_object_get_ex(jobj, "chardev", &jval))
+		return rc;
+	chardev = json_object_get_string(jval);
+	if (sscanf(chardev, "dax%u.%u", &region_id, &id) != 2)
+		return rc;
+	if (asprintf(&region, "%u", region_id) < 0)
+		return rc;
+	param.region = region;
+
+	if (!json_object_object_get_ex(jobj, "mappings", &jmappings))
+		return rc;
+	json_object_array_sort(jmappings, sort_mappings);
+
+	len = json_object_array_length(jmappings);
+	m = calloc(len, sizeof(*m));
+	if (!m)
+		return -ENOMEM;
+
+	for (i = 0; i < len; i++) {
+		struct json_object *j, *val;
+
+		j = json_object_array_get_idx(jmappings, i);
+		if (!j)
+			goto err;
+
+		if (!json_object_object_get_ex(j, "start", &val))
+			goto err;
+		m[i].start = json_object_get_int64(val);
+
+		if (!json_object_object_get_ex(j, "end", &val))
+			goto err;
+		m[i].end = json_object_get_int64(val);
+
+		if (!json_object_object_get_ex(j, "page_offset", &val))
+			goto err;
+		m[i].pgoff = json_object_get_int64(val);
+	}
+	maps = m;
+	nmaps = len;
+	rc = 0;
+
+err:
+	if (!maps)
+		free(m);
+	return rc;
+}
+
 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)
@@ -213,6 +311,13 @@ static const char *parse_device_options(int argc, const char **argv,
 			align = __parse_size64(param.align, &units);
 		break;
 	case ACTION_CREATE:
+		if (param.restore &&
+		    (rc = parse_device_file(param.restore)) != 0) {
+			fprintf(stderr,
+				"error: failed to parse device file: %s\n",
+				strerror(-rc));
+			break;
+		}
 		if (param.size)
 			size = __parse_size64(param.size, &units);
 		if (param.align)
@@ -524,7 +629,8 @@ static int do_create(struct daxctl_region *region, long long val,
 {
 	struct json_object *jdev;
 	struct daxctl_dev *dev;
-	int rc = 0;
+	int i, rc = 0;
+	long long alloc = 0;
 
 	if (daxctl_region_create_dev(region))
 		return -ENOSPC;
@@ -545,9 +651,22 @@ static int do_create(struct daxctl_region *region, long long val,
 			return rc;
 	}
 
-	rc = daxctl_dev_set_size(dev, val);
-	if (rc < 0)
-		return rc;
+	/* @maps is ordered by page_offset */
+	for (i = 0; i < nmaps; i++) {
+		rc = daxctl_dev_set_mapping(dev, maps[i].start, maps[i].end);
+		if (rc < 0)
+			return rc;
+		alloc += (maps[i].end - maps[i].start + 1);
+	}
+
+	if (nmaps > 0 && val > 0 && alloc != val) {
+		fprintf(stderr, "%s: allocated %lld but specified size %lld\n",
+			daxctl_dev_get_devname(dev), alloc, val);
+	} else {
+		rc = daxctl_dev_set_size(dev, val);
+		if (rc < 0)
+			return rc;
+	}
 
 	rc = daxctl_dev_enable_devdax(dev);
 	if (rc) {
-- 
1.8.3.1
_______________________________________________
Linux-nvdimm mailing list -- linux-nvdimm@lists.01.org
To unsubscribe send an email to linux-nvdimm-leave@lists.01.org

  parent reply	other threads:[~2020-07-16 18:47 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-07-16 18:46 [PATCH ndctl v1 0/8] daxctl: Add device align and range mapping allocation Joao Martins
2020-07-16 18:47 ` [PATCH ndctl v1 1/8] daxctl: add daxctl_dev_{get,set}_align() Joao Martins
2020-07-16 18:47 ` [PATCH ndctl v1 2/8] util/json: Print device align Joao Martins
2020-07-16 18:47 ` [PATCH ndctl v1 3/8] daxctl: add align support in reconfigure-device Joao Martins
2020-07-16 18:47 ` [PATCH ndctl v1 4/8] daxctl: add align support in create-device Joao Martins
2020-07-16 18:47 ` [PATCH ndctl v1 5/8] libdaxctl: add mapping iterator APIs Joao Martins
2020-07-16 18:47 ` [PATCH ndctl v1 6/8] daxctl: include mappings when listing Joao Martins
2020-07-16 18:47 ` [PATCH ndctl v1 7/8] libdaxctl: add daxctl_dev_set_mapping() Joao Martins
2020-07-16 18:47 ` Joao Martins [this message]
2020-12-16 11:39 ` [PATCH ndctl v1 0/8] daxctl: Add device align and range mapping allocation Joao Martins
2020-12-16 18:42   ` Verma, Vishal L
2020-12-16 21:49     ` Joao Martins
2020-12-16 22:31       ` Dan Williams
2020-12-16 22:53         ` Joao Martins
2020-12-16 23:42           ` Dan Williams
2020-12-17 11:23             ` Joao Martins
2020-12-17 20:18               ` Verma, Vishal L
2020-12-16 19:13   ` Dan Williams
2020-12-16 21:35     ` Joao Martins

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200716184707.23018-9-joao.m.martins@oracle.com \
    --to=joao.m.martins@oracle.com \
    --cc=jason.zeng@intel.com \
    --cc=linux-nvdimm@lists.01.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.