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", ¶m.force, \
#define CREATE_OPTIONS() \
OPT_STRING('s', "size", ¶m.size, "size", "size to switch the device to"), \
-OPT_STRING('a', "align", ¶m.align, "align", "alignment to switch the device to")
+OPT_STRING('a', "align", ¶m.align, "align", "alignment to switch the device to"), \
+OPT_STRING('\0', "restore", ¶m.restore, "restore", \
+ "restore the device from device JSON")
#define DESTROY_OPTIONS() \
OPT_BOOLEAN('f', "force", ¶m.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", ®ion_id, &id) != 2)
+ return rc;
+ if (asprintf(®ion, "%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
next prev 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).