All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH daxctl v2 0/5] daxctl: range mapping allocation
@ 2020-12-18  2:14 Joao Martins
  2020-12-18  2:14 ` [PATCH daxctl v2 1/5] libdaxctl: add mapping iterator APIs Joao Martins
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Joao Martins @ 2020-12-18  2:14 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Joao Martins

Hey,

This series adds support for:

 1) Listing mappings when passing -M to ´daxctl list´. These are ommited
 by default.

 2) Iteration APIs for the mappings.

 3) Allow passing an input JSON file with the manually selected ranges
 to be used when creating the device-dax instance.

This applies on top of 'jm/devdax_subdiv' branch in github.com:pmem/ndctl.git

Testing requires a 5.10+ kernel.

v1 -> v2:
  * List mappings only with -M|--mappings option
  * Adds a unit test for --input file (while testing with -M listing too)
  * Rename --restore to --input
  * Add Documentation for -M and for --input

Joao Martins (5):
  libdaxctl: add mapping iterator APIs
  daxctl: include mappings when listing
  libdaxctl: add daxctl_dev_set_mapping()
  daxctl: allow creating devices from input json
  daxctl/test: add a test for daxctl-create with input file

 Documentation/daxctl/daxctl-create-device.txt |  13 +++
 Documentation/daxctl/daxctl-list.txt          |   4 +
 daxctl/device.c                               | 128 +++++++++++++++++++++++++-
 daxctl/lib/libdaxctl-private.h                |   8 ++
 daxctl/lib/libdaxctl.c                        | 118 +++++++++++++++++++++++-
 daxctl/lib/libdaxctl.sym                      |   7 ++
 daxctl/libdaxctl.h                            |  14 +++
 daxctl/list.c                                 |   4 +
 test/daxctl-create.sh                         |  31 ++++++-
 util/json.c                                   |  57 +++++++++++-
 util/json.h                                   |   4 +
 11 files changed, 380 insertions(+), 8 deletions(-)

-- 
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

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH daxctl v2 1/5] libdaxctl: add mapping iterator APIs
  2020-12-18  2:14 [PATCH daxctl v2 0/5] daxctl: range mapping allocation Joao Martins
@ 2020-12-18  2:14 ` Joao Martins
  2020-12-18  2:14 ` [PATCH daxctl v2 2/5] daxctl: include mappings when listing Joao Martins
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Joao Martins @ 2020-12-18  2:14 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Joao Martins

Add the following APIs to be able to iterate over a
dynamic device-dax mapping list, as well as fetching
each of the mapping attributes.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
---
 daxctl/lib/libdaxctl-private.h |  8 ++++
 daxctl/lib/libdaxctl.c         | 91 +++++++++++++++++++++++++++++++++++++++++-
 daxctl/lib/libdaxctl.sym       |  6 +++
 daxctl/libdaxctl.h             | 12 ++++++
 4 files changed, 116 insertions(+), 1 deletion(-)

diff --git a/daxctl/lib/libdaxctl-private.h b/daxctl/lib/libdaxctl-private.h
index b307a8bc9438..6d05aefbeda0 100644
--- a/daxctl/lib/libdaxctl-private.h
+++ b/daxctl/lib/libdaxctl-private.h
@@ -91,6 +91,12 @@ struct daxctl_region {
 	struct list_head devices;
 };
 
+struct daxctl_mapping {
+	struct daxctl_dev *dev;
+	unsigned long long pgoff, start, end;
+	struct list_node list;
+};
+
 struct daxctl_dev {
 	int id, major, minor;
 	void *dev_buf;
@@ -104,6 +110,8 @@ struct daxctl_dev {
 	struct daxctl_region *region;
 	struct daxctl_memory *mem;
 	int target_node;
+	int num_mappings;
+	struct list_head mappings;
 };
 
 struct daxctl_memory {
diff --git a/daxctl/lib/libdaxctl.c b/daxctl/lib/libdaxctl.c
index 39871427c799..3781e9ed27d5 100644
--- a/daxctl/lib/libdaxctl.c
+++ b/daxctl/lib/libdaxctl.c
@@ -526,7 +526,8 @@ static void *add_dax_dev(void *parent, int id, const char *daxdev_base)
 			free(path);
 			return dev_dup;
 		}
-
+	dev->num_mappings = -1;
+	list_head_init(&dev->mappings);
 	list_add(&region->devices, &dev->list);
 	free(path);
 	return dev;
@@ -1150,6 +1151,94 @@ DAXCTL_EXPORT unsigned long daxctl_memory_get_block_size(struct daxctl_memory *m
 	return mem->block_size;
 }
 
+static void mappings_init(struct daxctl_dev *dev)
+{
+	struct daxctl_ctx *ctx = daxctl_dev_get_ctx(dev);
+	char buf[SYSFS_ATTR_SIZE];
+	char *path = dev->dev_buf;
+	int i;
+
+	if (dev->num_mappings != -1)
+		return;
+
+	dev->num_mappings = 0;
+	for (;;) {
+		struct daxctl_mapping *mapping;
+		unsigned long long pgoff, start, end;
+
+		i = dev->num_mappings;
+		mapping = calloc(1, sizeof(*mapping));
+		if (!mapping) {
+			err(ctx, "%s: mapping%u allocation failure\n",
+				daxctl_dev_get_devname(dev), i);
+			continue;
+		}
+
+		sprintf(path, "%s/mapping%d/start", dev->dev_path, i);
+		if (sysfs_read_attr(ctx, path, buf) < 0) {
+			free(mapping);
+			break;
+		}
+		start = strtoull(buf, NULL, 0);
+
+		sprintf(path, "%s/mapping%d/end", dev->dev_path, i);
+		if (sysfs_read_attr(ctx, path, buf) < 0) {
+			free(mapping);
+			break;
+		}
+		end = strtoull(buf, NULL, 0);
+
+		sprintf(path, "%s/mapping%d/page_offset", dev->dev_path, i);
+		if (sysfs_read_attr(ctx, path, buf) < 0) {
+			free(mapping);
+			break;
+		}
+		pgoff = strtoull(buf, NULL, 0);
+
+		mapping->dev = dev;
+		mapping->start = start;
+		mapping->end = end;
+		mapping->pgoff = pgoff;
+
+		dev->num_mappings++;
+		list_add(&dev->mappings, &mapping->list);
+	}
+}
+
+DAXCTL_EXPORT struct daxctl_mapping *daxctl_mapping_get_first(struct daxctl_dev *dev)
+{
+	mappings_init(dev);
+
+	return list_top(&dev->mappings, struct daxctl_mapping, list);
+}
+
+DAXCTL_EXPORT struct daxctl_mapping *daxctl_mapping_get_next(struct daxctl_mapping *mapping)
+{
+	struct daxctl_dev *dev = mapping->dev;
+
+	return list_next(&dev->mappings, mapping, list);
+}
+
+DAXCTL_EXPORT unsigned long long daxctl_mapping_get_start(struct daxctl_mapping *mapping)
+{
+	return mapping->start;
+}
+
+DAXCTL_EXPORT unsigned long long daxctl_mapping_get_end(struct daxctl_mapping *mapping)
+{
+	return mapping->end;
+}
+
+DAXCTL_EXPORT unsigned long long  daxctl_mapping_get_offset(struct daxctl_mapping *mapping)
+{
+	return mapping->pgoff;
+}
+
+DAXCTL_EXPORT unsigned long long daxctl_mapping_get_size(struct daxctl_mapping *mapping)
+{
+	return mapping->end - mapping->start + 1;
+}
+
 static int memblock_is_online(struct daxctl_memory *mem, char *memblock)
 {
 	struct daxctl_dev *dev = daxctl_memory_get_dev(mem);
diff --git a/daxctl/lib/libdaxctl.sym b/daxctl/lib/libdaxctl.sym
index c3d08179c9fd..08362b683678 100644
--- a/daxctl/lib/libdaxctl.sym
+++ b/daxctl/lib/libdaxctl.sym
@@ -83,4 +83,10 @@ global:
 	daxctl_region_destroy_dev;
 	daxctl_dev_get_align;
 	daxctl_dev_set_align;
+	daxctl_mapping_get_first;
+	daxctl_mapping_get_next;
+	daxctl_mapping_get_start;
+	daxctl_mapping_get_end;
+	daxctl_mapping_get_offset;
+	daxctl_mapping_get_size;
 } LIBDAXCTL_7;
diff --git a/daxctl/libdaxctl.h b/daxctl/libdaxctl.h
index b0bb5d78d357..f94a72fed85b 100644
--- a/daxctl/libdaxctl.h
+++ b/daxctl/libdaxctl.h
@@ -103,6 +103,18 @@ int daxctl_memory_online_no_movable(struct daxctl_memory *mem);
              region != NULL; \
              region = daxctl_region_get_next(region))
 
+struct daxctl_mapping;
+struct daxctl_mapping *daxctl_mapping_get_first(struct daxctl_dev *dev);
+struct daxctl_mapping *daxctl_mapping_get_next(struct daxctl_mapping *mapping);
+#define daxctl_mapping_foreach(dev, mapping) \
+        for (mapping = daxctl_mapping_get_first(dev); \
+             mapping != NULL; \
+             mapping = daxctl_mapping_get_next(mapping))
+unsigned long long daxctl_mapping_get_start(struct daxctl_mapping *mapping);
+unsigned long long daxctl_mapping_get_end(struct daxctl_mapping *mapping);
+unsigned long long  daxctl_mapping_get_offset(struct daxctl_mapping *mapping);
+unsigned long long daxctl_mapping_get_size(struct daxctl_mapping *mapping);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
-- 
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

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH daxctl v2 2/5] daxctl: include mappings when listing
  2020-12-18  2:14 [PATCH daxctl v2 0/5] daxctl: range mapping allocation Joao Martins
  2020-12-18  2:14 ` [PATCH daxctl v2 1/5] libdaxctl: add mapping iterator APIs Joao Martins
@ 2020-12-18  2:14 ` Joao Martins
  2020-12-18  2:14 ` [PATCH daxctl v2 3/5] libdaxctl: add daxctl_dev_set_mapping() Joao Martins
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Joao Martins @ 2020-12-18  2:14 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Joao Martins

Iterate over the device mappings and print @page_offset,
 @start, @end and a computed size, but only if user
 passes -M|--mappings to daxctl list as the output can
get verbose with a lot of mapping entries.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
---
 Documentation/daxctl/daxctl-list.txt |  4 +++
 daxctl/list.c                        |  4 +++
 util/json.c                          | 57 +++++++++++++++++++++++++++++++++++-
 util/json.h                          |  4 +++
 4 files changed, 68 insertions(+), 1 deletion(-)

diff --git a/Documentation/daxctl/daxctl-list.txt b/Documentation/daxctl/daxctl-list.txt
index cb82c3cc6fb2..5a6a98e73849 100644
--- a/Documentation/daxctl/daxctl-list.txt
+++ b/Documentation/daxctl/daxctl-list.txt
@@ -67,6 +67,10 @@ OPTIONS
 --devices::
 	Include device-dax instance info in the listing (default)
 
+-M::
+--mappings::
+	Include device-dax instance mappings info in the listing
+
 -R::
 --regions::
 	Include region info in the listing
diff --git a/daxctl/list.c b/daxctl/list.c
index 6c6251b4de37..6860a460e4c0 100644
--- a/daxctl/list.c
+++ b/daxctl/list.c
@@ -25,6 +25,7 @@
 static struct {
 	bool devs;
 	bool regions;
+	bool mappings;
 	bool idle;
 	bool human;
 } list;
@@ -35,6 +36,8 @@ static unsigned long listopts_to_flags(void)
 
 	if (list.devs)
 		flags |= UTIL_JSON_DAX_DEVS;
+	if (list.mappings)
+		flags |= UTIL_JSON_DAX_MAPPINGS;
 	if (list.idle)
 		flags |= UTIL_JSON_IDLE;
 	if (list.human)
@@ -70,6 +73,7 @@ int cmd_list(int argc, const char **argv, struct daxctl_ctx *ctx)
 				"filter by dax device instance name"),
 		OPT_BOOLEAN('D', "devices", &list.devs, "include dax device info"),
 		OPT_BOOLEAN('R', "regions", &list.regions, "include dax region info"),
+		OPT_BOOLEAN('M', "mappings", &list.mappings, "include dax mappings info"),
 		OPT_BOOLEAN('i', "idle", &list.idle, "include idle devices"),
 		OPT_BOOLEAN('u', "human", &list.human,
 				"use human friendly number formats "),
diff --git a/util/json.c b/util/json.c
index 357dff20d6be..dcc927294e4f 100644
--- a/util/json.c
+++ b/util/json.c
@@ -454,7 +454,8 @@ struct json_object *util_daxctl_dev_to_json(struct daxctl_dev *dev,
 {
 	struct daxctl_memory *mem = daxctl_dev_get_memory(dev);
 	const char *devname = daxctl_dev_get_devname(dev);
-	struct json_object *jdev, *jobj;
+	struct json_object *jdev, *jobj, *jmappings = NULL;
+	struct daxctl_mapping *mapping = NULL;
 	int node, movable, align;
 
 	jdev = json_object_new_object();
@@ -508,6 +509,25 @@ struct json_object *util_daxctl_dev_to_json(struct daxctl_dev *dev,
 			json_object_object_add(jdev, "state", jobj);
 	}
 
+	if (!(flags & UTIL_JSON_DAX_MAPPINGS))
+		return jdev;
+
+	daxctl_mapping_foreach(dev, mapping) {
+		struct json_object *jmapping;
+
+		if (!jmappings) {
+			jmappings = json_object_new_array();
+			if (!jmappings)
+				continue;
+
+			json_object_object_add(jdev, "mappings", jmappings);
+		}
+
+		jmapping = util_daxctl_mapping_to_json(mapping, flags);
+		if (!jmapping)
+			continue;
+		json_object_array_add(jmappings, jmapping);
+	}
 	return jdev;
 }
 
@@ -1357,6 +1377,41 @@ struct json_object *util_mapping_to_json(struct ndctl_mapping *mapping,
 	return NULL;
 }
 
+struct json_object *util_daxctl_mapping_to_json(struct daxctl_mapping *mapping,
+		unsigned long flags)
+{
+	struct json_object *jmapping = json_object_new_object();
+	struct json_object *jobj;
+
+	if (!jmapping)
+		return NULL;
+
+	jobj = util_json_object_hex(daxctl_mapping_get_offset(mapping), flags);
+	if (!jobj)
+		goto err;
+	json_object_object_add(jmapping, "page_offset", jobj);
+
+	jobj = util_json_object_hex(daxctl_mapping_get_start(mapping), flags);
+	if (!jobj)
+		goto err;
+	json_object_object_add(jmapping, "start", jobj);
+
+	jobj = util_json_object_hex(daxctl_mapping_get_end(mapping), flags);
+	if (!jobj)
+		goto err;
+	json_object_object_add(jmapping, "end", jobj);
+
+	jobj = util_json_object_size(daxctl_mapping_get_size(mapping), flags);
+	if (!jobj)
+		goto err;
+	json_object_object_add(jmapping, "size", jobj);
+
+	return jmapping;
+ err:
+	json_object_put(jmapping);
+	return NULL;
+}
+
 struct json_object *util_badblock_rec_to_json(u64 block, u64 count,
 		unsigned long flags)
 {
diff --git a/util/json.h b/util/json.h
index 39a33789bac9..e26875a5ecd8 100644
--- a/util/json.h
+++ b/util/json.h
@@ -15,6 +15,7 @@
 #include <stdio.h>
 #include <stdbool.h>
 #include <ndctl/libndctl.h>
+#include <daxctl/libdaxctl.h>
 #include <ccan/short_types/short_types.h>
 
 enum util_json_flags {
@@ -27,6 +28,7 @@ enum util_json_flags {
 	UTIL_JSON_CAPABILITIES	= (1 << 6),
 	UTIL_JSON_CONFIGURED	= (1 << 7),
 	UTIL_JSON_FIRMWARE	= (1 << 8),
+	UTIL_JSON_DAX_MAPPINGS	= (1 << 9),
 };
 
 struct json_object;
@@ -38,6 +40,8 @@ struct json_object *util_dimm_to_json(struct ndctl_dimm *dimm,
 		unsigned long flags);
 struct json_object *util_mapping_to_json(struct ndctl_mapping *mapping,
 		unsigned long flags);
+struct json_object *util_daxctl_mapping_to_json(struct daxctl_mapping *mapping,
+		unsigned long flags);
 struct json_object *util_namespace_to_json(struct ndctl_namespace *ndns,
 		unsigned long flags);
 struct json_object *util_badblock_rec_to_json(u64 block, u64 count,
-- 
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

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH daxctl v2 3/5] libdaxctl: add daxctl_dev_set_mapping()
  2020-12-18  2:14 [PATCH daxctl v2 0/5] daxctl: range mapping allocation Joao Martins
  2020-12-18  2:14 ` [PATCH daxctl v2 1/5] libdaxctl: add mapping iterator APIs Joao Martins
  2020-12-18  2:14 ` [PATCH daxctl v2 2/5] daxctl: include mappings when listing Joao Martins
@ 2020-12-18  2:14 ` Joao Martins
  2020-12-18  2:14 ` [PATCH daxctl v2 4/5] daxctl: allow creating devices from input json Joao Martins
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Joao Martins @ 2020-12-18  2:14 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Joao Martins

This API adds the ability to manually pick a range within the region
device.  Such routine allows for a admin to restore the mappings of a
device after kexec. This is specially useful for hmem dynamic devdax
which do not persistent ranges allocation through say a e.g. namespace
label storage area. It also allows an userspace application to pick
it's own ranges, should it want to avoid relying on kernel's policy.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
---
 daxctl/lib/libdaxctl.c   | 27 +++++++++++++++++++++++++++
 daxctl/lib/libdaxctl.sym |  1 +
 daxctl/libdaxctl.h       |  2 ++
 3 files changed, 30 insertions(+)

diff --git a/daxctl/lib/libdaxctl.c b/daxctl/lib/libdaxctl.c
index 3781e9ed27d5..59fe84fee409 100644
--- a/daxctl/lib/libdaxctl.c
+++ b/daxctl/lib/libdaxctl.c
@@ -1123,6 +1123,33 @@ DAXCTL_EXPORT int daxctl_dev_set_align(struct daxctl_dev *dev, unsigned long ali
 	return 0;
 }
 
+DAXCTL_EXPORT int daxctl_dev_set_mapping(struct daxctl_dev *dev,
+					unsigned long long start,
+					unsigned long long end)
+{
+	struct daxctl_ctx *ctx = daxctl_dev_get_ctx(dev);
+	unsigned long long size = end - start + 1;
+	char buf[SYSFS_ATTR_SIZE];
+	char *path = dev->dev_buf;
+	int len = dev->buf_len;
+
+	if (snprintf(path, len, "%s/mapping", dev->dev_path) >= len) {
+		err(ctx, "%s: buffer too small!\n",
+				daxctl_dev_get_devname(dev));
+		return -ENXIO;
+	}
+
+	sprintf(buf, "%#llx-%#llx\n", start, end);
+	if (sysfs_write_attr(ctx, path, buf) < 0) {
+		err(ctx, "%s: failed to set mapping\n",
+				daxctl_dev_get_devname(dev));
+		return -ENXIO;
+	}
+	dev->size += size;
+
+	return 0;
+}
+
 DAXCTL_EXPORT int daxctl_dev_get_target_node(struct daxctl_dev *dev)
 {
 	return dev->target_node;
diff --git a/daxctl/lib/libdaxctl.sym b/daxctl/lib/libdaxctl.sym
index 08362b683678..a4e16848494b 100644
--- a/daxctl/lib/libdaxctl.sym
+++ b/daxctl/lib/libdaxctl.sym
@@ -89,4 +89,5 @@ global:
 	daxctl_mapping_get_end;
 	daxctl_mapping_get_offset;
 	daxctl_mapping_get_size;
+	daxctl_dev_set_mapping;
 } LIBDAXCTL_7;
diff --git a/daxctl/libdaxctl.h b/daxctl/libdaxctl.h
index f94a72fed85b..09439c16d6df 100644
--- a/daxctl/libdaxctl.h
+++ b/daxctl/libdaxctl.h
@@ -73,6 +73,8 @@ unsigned long long daxctl_dev_get_size(struct daxctl_dev *dev);
 int daxctl_dev_set_size(struct daxctl_dev *dev, unsigned long long size);
 unsigned long daxctl_dev_get_align(struct daxctl_dev *dev);
 int daxctl_dev_set_align(struct daxctl_dev *dev, unsigned long align);
+int daxctl_dev_set_mapping(struct daxctl_dev *dev, unsigned long long start,
+			unsigned long long end);
 struct daxctl_ctx *daxctl_dev_get_ctx(struct daxctl_dev *dev);
 int daxctl_dev_is_enabled(struct daxctl_dev *dev);
 int daxctl_dev_disable(struct daxctl_dev *dev);
-- 
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

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH daxctl v2 4/5] daxctl: allow creating devices from input json
  2020-12-18  2:14 [PATCH daxctl v2 0/5] daxctl: range mapping allocation Joao Martins
                   ` (2 preceding siblings ...)
  2020-12-18  2:14 ` [PATCH daxctl v2 3/5] libdaxctl: add daxctl_dev_set_mapping() Joao Martins
@ 2020-12-18  2:14 ` Joao Martins
  2020-12-18  2:14 ` [PATCH daxctl v2 5/5] daxctl/test: add a test for daxctl-create with input file Joao Martins
  2020-12-19  8:21 ` [PATCH daxctl v2 0/5] daxctl: range mapping allocation Verma, Vishal L
  5 siblings, 0 replies; 7+ messages in thread
From: Joao Martins @ 2020-12-18  2:14 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Joao Martins

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

	$ daxctl list -d dax0.1 | jq -er '.[]' > device.json
	{
	  "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
	    }
	  ]
	}

The input values in the mapping json are decimal
for now. A device can then be created by specifying this same data
to re-create it e.g.

	$ daxctl create-device -u --input device.json
	{
	  "chardev":"dax0.1",
	  "size":"32.00 GiB (34.36 GB)",
	  "target_node":0,
	  "align":"1024.00 MiB (1073.74 MB)",
	  "mode":"devdax",
	}

	$ 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
	    }
	  ]
	}

	created 1 device

This means we can restore/recreate previously established mappings.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
---
 Documentation/daxctl/daxctl-create-device.txt |  13 +++
 daxctl/device.c                               | 128 +++++++++++++++++++++++++-
 2 files changed, 136 insertions(+), 5 deletions(-)

diff --git a/Documentation/daxctl/daxctl-create-device.txt b/Documentation/daxctl/daxctl-create-device.txt
index 7f64719d16f2..05f4dbd9d61c 100644
--- a/Documentation/daxctl/daxctl-create-device.txt
+++ b/Documentation/daxctl/daxctl-create-device.txt
@@ -90,6 +90,19 @@ include::region-option.txt[]
 	to 2M. Note that "devdax" mode enforces all mappings to be
 	aligned to this value, i.e. it fails unaligned mapping attempts.
 
+--input::
+	Applications that want to select ranges assigned to a device-dax
+	instance, or wanting to establish previously created devices, can
+	pass an input JSON file. The file option lets a user pass a JSON
+	object similar to the one listed with "daxctl list".
+
+	The device name is not re-created, but if a "chardev" is passed in
+	the JSON file, it will use that to get the region id.
+
+	Note that the JSON content in the file cannot be an array of
+	JSON objects but rather a single JSON object i.e. without the
+	array enclosing brackets.
+
 include::human-option.txt[]
 
 include::verbose-option.txt[]
diff --git a/daxctl/device.c b/daxctl/device.c
index 3c2d4e3d8b48..fe4291199312 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 *input;
 	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,8 @@ 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', "input", &param.input, "input", "input device JSON file")
 
 #define DESTROY_OPTIONS() \
 OPT_BOOLEAN('f', "force", &param.force, \
@@ -124,6 +133,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)
@@ -214,6 +311,13 @@ static const char *parse_device_options(int argc, const char **argv,
 		}
 		break;
 	case ACTION_CREATE:
+		if (param.input &&
+		    (rc = parse_device_file(param.input)) != 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)
@@ -525,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;
@@ -546,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

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH daxctl v2 5/5] daxctl/test: add a test for daxctl-create with input file
  2020-12-18  2:14 [PATCH daxctl v2 0/5] daxctl: range mapping allocation Joao Martins
                   ` (3 preceding siblings ...)
  2020-12-18  2:14 ` [PATCH daxctl v2 4/5] daxctl: allow creating devices from input json Joao Martins
@ 2020-12-18  2:14 ` Joao Martins
  2020-12-19  8:21 ` [PATCH daxctl v2 0/5] daxctl: range mapping allocation Verma, Vishal L
  5 siblings, 0 replies; 7+ messages in thread
From: Joao Martins @ 2020-12-18  2:14 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Joao Martins

The test creates a multi-range device (4 mappings) using the
same setup as one of the tests. Afterwards we validate that
the size/nr-mappings are the same as the original test.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
---
 test/daxctl-create.sh | 31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/test/daxctl-create.sh b/test/daxctl-create.sh
index 41d5ba5888f7..e1d733916851 100755
--- a/test/daxctl-create.sh
+++ b/test/daxctl-create.sh
@@ -199,6 +199,7 @@ daxctl_test_multi()
 daxctl_test_multi_reconfig()
 {
 	local ncfgs=$1
+	local dump=$2
 	local daxdev
 
 	size=$((available / ncfgs))
@@ -226,6 +227,10 @@ daxctl_test_multi_reconfig()
 	test "$(daxctl_get_nr_mappings "$testdev")" -eq $((ncfgs / 2))
 	test "$(daxctl_get_nr_mappings "$daxdev_1")" -eq $((ncfgs / 2))
 
+	if [[ $dump ]]; then
+		"$DAXCTL" list -M -d "$daxdev_1" | jq -er '.[]' > $dump
+	fi
+
 	fail_if_available
 
 	"$DAXCTL" disable-device "$daxdev_1" && "$DAXCTL" destroy-device "$daxdev_1"
@@ -328,7 +333,7 @@ daxctl_test3()
 # pick at the end of the region
 daxctl_test4()
 {
-	daxctl_test_multi_reconfig 8
+	daxctl_test_multi_reconfig 8 ""
 	clear_dev
 	test_pass
 }
@@ -371,6 +376,29 @@ daxctl_test6()
 	test_pass
 }
 
+# Test 7: input device
+# Successfully creates a device with an input file from the multi-range
+# device test, and checking that we have the same number of mappings/size.
+daxctl_test7()
+{
+	daxctl_test_multi_reconfig 8 "input.json"
+
+	# The parameter should parse the region_id from the chardev entry
+	# therefore using the same region_id as test4
+	daxdev_1=$("$DAXCTL" create-device --input input.json | jq -er '.[].chardev')
+
+	# Validate if it's the same mappings as done by test4
+	# It also validates the size computed from the mappings
+	# A zero value means it failed, and four mappings is what's
+	# created by daxctl_test4
+	test "$(daxctl_get_nr_mappings "$daxdev_1")" -eq 4
+
+	"$DAXCTL" disable-device "$daxdev_1" && "$DAXCTL" destroy-device "$daxdev_1"
+
+	clear_dev
+	test_pass
+}
+
 find_testdev
 rc=1
 setup_dev
@@ -381,5 +409,6 @@ daxctl_test3
 daxctl_test4
 daxctl_test5
 daxctl_test6
+daxctl_test7
 reset_dev
 exit 0
-- 
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

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH daxctl v2 0/5] daxctl: range mapping allocation
  2020-12-18  2:14 [PATCH daxctl v2 0/5] daxctl: range mapping allocation Joao Martins
                   ` (4 preceding siblings ...)
  2020-12-18  2:14 ` [PATCH daxctl v2 5/5] daxctl/test: add a test for daxctl-create with input file Joao Martins
@ 2020-12-19  8:21 ` Verma, Vishal L
  5 siblings, 0 replies; 7+ messages in thread
From: Verma, Vishal L @ 2020-12-19  8:21 UTC (permalink / raw)
  To: linux-nvdimm, joao.m.martins; +Cc: Williams, Dan J

On Fri, 2020-12-18 at 02:14 +0000, Joao Martins wrote:
> Hey,
> 
> This series adds support for:
> 
>  1) Listing mappings when passing -M to ´daxctl list´. These are ommited
>  by default.
> 
>  2) Iteration APIs for the mappings.
> 
>  3) Allow passing an input JSON file with the manually selected ranges
>  to be used when creating the device-dax instance.
> 
> This applies on top of 'jm/devdax_subdiv' branch in github.com:pmem/ndctl.git
> 
> Testing requires a 5.10+ kernel.
> 
> v1 -> v2:
>   * List mappings only with -M|--mappings option
>   * Adds a unit test for --input file (while testing with -M listing too)
>   * Rename --restore to --input
>   * Add Documentation for -M and for --input
> 
> Joao Martins (5):
>   libdaxctl: add mapping iterator APIs
>   daxctl: include mappings when listing
>   libdaxctl: add daxctl_dev_set_mapping()
>   daxctl: allow creating devices from input json
>   daxctl/test: add a test for daxctl-create with input file
> 
>  Documentation/daxctl/daxctl-create-device.txt |  13 +++
>  Documentation/daxctl/daxctl-list.txt          |   4 +
>  daxctl/device.c                               | 128 +++++++++++++++++++++++++-
>  daxctl/lib/libdaxctl-private.h                |   8 ++
>  daxctl/lib/libdaxctl.c                        | 118 +++++++++++++++++++++++-
>  daxctl/lib/libdaxctl.sym                      |   7 ++
>  daxctl/libdaxctl.h                            |  14 +++
>  daxctl/list.c                                 |   4 +
>  test/daxctl-create.sh                         |  31 ++++++-
>  util/json.c                                   |  57 +++++++++++-
>  util/json.h                                   |   4 +
>  11 files changed, 380 insertions(+), 8 deletions(-)
> 
Hi Joao,

These all look good, applied. Thanks for the quick turnaround!

-Vishal
_______________________________________________
Linux-nvdimm mailing list -- linux-nvdimm@lists.01.org
To unsubscribe send an email to linux-nvdimm-leave@lists.01.org

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2020-12-19  8:22 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-18  2:14 [PATCH daxctl v2 0/5] daxctl: range mapping allocation Joao Martins
2020-12-18  2:14 ` [PATCH daxctl v2 1/5] libdaxctl: add mapping iterator APIs Joao Martins
2020-12-18  2:14 ` [PATCH daxctl v2 2/5] daxctl: include mappings when listing Joao Martins
2020-12-18  2:14 ` [PATCH daxctl v2 3/5] libdaxctl: add daxctl_dev_set_mapping() Joao Martins
2020-12-18  2:14 ` [PATCH daxctl v2 4/5] daxctl: allow creating devices from input json Joao Martins
2020-12-18  2:14 ` [PATCH daxctl v2 5/5] daxctl/test: add a test for daxctl-create with input file Joao Martins
2020-12-19  8:21 ` [PATCH daxctl v2 0/5] daxctl: range mapping allocation Verma, Vishal L

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.