* [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(®ion->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", ¶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', "input", ¶m.input, "input", "input device JSON file")
#define DESTROY_OPTIONS() \
OPT_BOOLEAN('f', "force", ¶m.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", ®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)
@@ -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.