From: Dan Williams <dan.j.williams@intel.com>
To: linux-nvdimm@lists.01.org
Cc: vishal.l.verma@intel.com
Subject: [ndctl PATCH 12/36] ndctl/namespace: Add read-infoblock command
Date: Sat, 29 Feb 2020 12:21:08 -0800 [thread overview]
Message-ID: <158300766814.2141307.3604583129159405889.stgit@dwillia2-desk3.amr.corp.intel.com> (raw)
In-Reply-To: <158300760415.2141307.14060353322051900501.stgit@dwillia2-desk3.amr.corp.intel.com>
Namespaces may contain an info-block that correlates with the possible
modes of a namespace: 'sector', 'fsdax', or 'devdax'. Provide a command
that can temporarily convert the namespace into 'raw' mode to read the
info-block.
Also, similar to 'read-labels' provide a facility to decode the
info-block into json.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
Documentation/ndctl/Makefile.am | 3
Documentation/ndctl/ndctl-read-infoblock.txt | 94 ++++++
ndctl/action.h | 1
ndctl/builtin.h | 1
ndctl/check.c | 20 -
ndctl/namespace.c | 404 ++++++++++++++++++++++++++
ndctl/namespace.h | 51 +++
ndctl/ndctl.c | 1
util/fletcher.h | 1
util/size.h | 1
10 files changed, 555 insertions(+), 22 deletions(-)
create mode 100644 Documentation/ndctl/ndctl-read-infoblock.txt
diff --git a/Documentation/ndctl/Makefile.am b/Documentation/ndctl/Makefile.am
index 659cb32f0878..a5b20715fa9b 100644
--- a/Documentation/ndctl/Makefile.am
+++ b/Documentation/ndctl/Makefile.am
@@ -55,7 +55,8 @@ man1_MANS = \
ndctl-freeze-security.1 \
ndctl-sanitize-dimm.1 \
ndctl-load-keys.1 \
- ndctl-wait-overwrite.1
+ ndctl-wait-overwrite.1 \
+ ndctl-read-infoblock.1
EXTRA_DIST = $(man1_MANS)
diff --git a/Documentation/ndctl/ndctl-read-infoblock.txt b/Documentation/ndctl/ndctl-read-infoblock.txt
new file mode 100644
index 000000000000..603cd6b223d3
--- /dev/null
+++ b/Documentation/ndctl/ndctl-read-infoblock.txt
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0
+
+ndctl-read-infoblock(1)
+=======================
+
+NAME
+----
+ndctl-read-infoblock - read and optionally parse the info-block a namespace
+
+SYNOPSIS
+--------
+[verse]
+'ndctl read-infoblock' <namespace0.0> [<namespace1.0>..<namespaceN.Y>] [<options>]
+
+DESCRIPTION
+-----------
+As described in the theory of operation section of
+linkndctl:ndctl-create-namespace[1], the raw capacity of a namespace may
+encapsulate a personality, or mode of operation. Specifically, the mode
+may be set to one of "sector", "fsdax", and "devdax". Each of those
+modes is defined by an info-block format that uniquely identifies the
+mode of operation. The read-infoblock command knows the location
+(relative to the start of the namespace) and field definition of those
+data structures.
+
+Note that unlike a partition table info-block is not exposed by default,
+so the namespace needs to be disabled before the info-block can be
+accessed.
+
+EXAMPLE
+-------
+
+[verse]
+ndctl disable-namespace namespace0.0
+disabled 1 namespace
+ndctl read-infoblock -j namespace0.0
+[
+ {
+ "dev":"namespace0.0",
+ "signature":"NVDIMM_PFN_INFO",
+ "uuid":"56b11990-66b1-4d91-9cac-ca084c051259",
+ "parent_uuid":"00000000-0000-0000-0000-000000000000",
+ "flags":0,
+ "version":"1.3",
+ "dataoff":69206016,
+ "npfns":1031680,
+ "mode":2,
+ "start_pad":0,
+ "end_trunc":0,
+ "align":2097152
+ }
+]
+
+
+OPTIONS
+-------
+<namespace(s)>::
+ One or more 'namespaceX.Y' device names. The keyword 'all' can be specified to
+ operate on every namespace in the system, optionally filtered by bus id (see
+ --bus= option), or region id (see --region= option).
+
+-V::
+--verify::
+ Attempt to validate that the info-block is self consistent by
+ validating the embedded checksum, and that info-block formats
+ that contain a 'parent-uuid' attribute also match the base-uuid
+ of the namespace.
+
+-o::
+--output::
+ Output file
+
+-j::
+--json::
+ Parse the info-block data into json.
+-u::
+--human::
+ Enable json output and convert number formats to human readable
+ strings, for example show the size in terms of "KB", "MB", "GB", etc
+ instead of a signed 64-bit numbers per the JSON interchange
+ format (implies --json).
+
+-r::
+--region=::
+include::xable-region-options.txt[]
+
+
+include::../copyright.txt[]
+
+SEE ALSO
+--------
+linkndctl:ndctl-create-namespace[1],
+http://www.uefi.org/sites/default/files/resources/UEFI_Spec_2_7.pdf[UEFI NVDIMM Label Protocol]
+
diff --git a/ndctl/action.h b/ndctl/action.h
index 50da010ae826..636524c01f20 100644
--- a/ndctl/action.h
+++ b/ndctl/action.h
@@ -14,5 +14,6 @@ enum device_action {
ACTION_WAIT,
ACTION_START,
ACTION_CLEAR,
+ ACTION_READ_INFOBLOCK,
};
#endif /* __NDCTL_ACTION_H__ */
diff --git a/ndctl/builtin.h b/ndctl/builtin.h
index 94ab3177e9b6..aa41ad01a84c 100644
--- a/ndctl/builtin.h
+++ b/ndctl/builtin.h
@@ -8,6 +8,7 @@ int cmd_create_nfit(int argc, const char **argv, struct ndctl_ctx *ctx);
int cmd_enable_namespace(int argc, const char **argv, struct ndctl_ctx *ctx);
int cmd_create_namespace(int argc, const char **argv, struct ndctl_ctx *ctx);
int cmd_destroy_namespace(int argc, const char **argv, struct ndctl_ctx *ctx);
+int cmd_read_infoblock(int argc, const char **argv, struct ndctl_ctx *ctx);
int cmd_disable_namespace(int argc, const char **argv, struct ndctl_ctx *ctx);
int cmd_check_namespace(int argc, const char **argv, struct ndctl_ctx *ctx);
int cmd_clear_errors(int argc, const char **argv, struct ndctl_ctx *ctx);
diff --git a/ndctl/check.c b/ndctl/check.c
index 365abafc12d1..cdb3d0bb5ae7 100644
--- a/ndctl/check.c
+++ b/ndctl/check.c
@@ -297,24 +297,6 @@ static int btt_log_read(struct arena_info *a, u32 lane, struct log_entry *ent)
return 0;
}
-static int btt_checksum_verify(struct btt_sb *btt_sb)
-{
- uint64_t sum;
- le64 sum_save;
-
- BUILD_BUG_ON(sizeof(struct btt_sb) != SZ_4K);
-
- sum_save = btt_sb->checksum;
- btt_sb->checksum = 0;
- sum = fletcher64(btt_sb, sizeof(*btt_sb), 1);
- if (sum != sum_save)
- return 1;
- /* restore the checksum in the buffer */
- btt_sb->checksum = sum_save;
-
- return 0;
-}
-
/*
* Never pass a mmapped buffer to this as it will attempt to write to
* the buffer, and we want writes to only happened in a controlled fashion.
@@ -330,7 +312,7 @@ static int btt_info_verify(struct btt_chk *bttc, struct btt_sb *btt_sb)
if (uuid_compare(bttc->parent_uuid, btt_sb->parent_uuid) != 0)
return -ENXIO;
- if (btt_checksum_verify(btt_sb))
+ if (!verify_infoblock_checksum((union info_block *) btt_sb))
return -ENXIO;
return 0;
diff --git a/ndctl/namespace.c b/ndctl/namespace.c
index 96d318166300..9bc54abfd437 100644
--- a/ndctl/namespace.c
+++ b/ndctl/namespace.c
@@ -21,6 +21,7 @@
#include <ndctl.h>
#include "action.h"
+#include "namespace.h"
#include <sys/stat.h>
#include <uuid/uuid.h>
#include <sys/types.h>
@@ -42,6 +43,9 @@ static struct parameters {
bool mode_default;
bool autolabel;
bool greedy;
+ bool verify;
+ bool human;
+ bool json;
const char *bus;
const char *map;
const char *type;
@@ -53,6 +57,8 @@ static struct parameters {
const char *reconfig;
const char *sector_size;
const char *align;
+ const char *outfile;
+ const char *infile;
} param = {
.autolabel = true,
};
@@ -83,6 +89,13 @@ struct parsed_parameters {
bool autolabel;
};
+#define pr_verbose(fmt, ...) \
+ ({if (verbose) { \
+ fprintf(stderr, fmt, ##__VA_ARGS__); \
+ } else { \
+ do { } while (0); \
+ }})
+
#define debug(fmt, ...) \
({if (verbose) { \
fprintf(stderr, "%s:%d: " fmt, __func__, __LINE__, ##__VA_ARGS__); \
@@ -133,6 +146,16 @@ OPT_BOOLEAN('f', "force", &force, "check namespace even if currently active")
#define CLEAR_OPTIONS() \
OPT_BOOLEAN('s', "scrub", &scrub, "run a scrub to find latent errors")
+#define READ_INFOBLOCK_OPTIONS() \
+OPT_FILENAME('o', "output", ¶m.outfile, "output-file", \
+ "filename to write info-block contents"), \
+OPT_FILENAME('i', "input", ¶m.infile, "input-file", \
+ "filename to read info-block instead of a namespace"), \
+OPT_BOOLEAN('V', "verify", ¶m.verify, \
+ "validate parent uuid, and info-block checksum"), \
+OPT_BOOLEAN('j', "json", ¶m.json, "parse label data into json"), \
+OPT_BOOLEAN('u', "human", ¶m.human, "use human friendly number formats (implies --json)")
+
static const struct option base_options[] = {
BASE_OPTIONS(),
OPT_END(),
@@ -163,6 +186,12 @@ static const struct option clear_options[] = {
OPT_END(),
};
+static const struct option read_infoblock_options[] = {
+ BASE_OPTIONS(),
+ READ_INFOBLOCK_OPTIONS(),
+ OPT_END(),
+};
+
static int set_defaults(enum device_action mode)
{
int rc = 0;
@@ -307,18 +336,30 @@ static const char *parse_namespace_options(int argc, const char **argv,
case ACTION_CLEAR:
action_string = "clear errors for";
break;
+ case ACTION_READ_INFOBLOCK:
+ action_string = "read-infoblock";
+ break;
default:
action_string = "<>";
break;
}
- error("specify a namespace to %s, or \"all\"\n", action_string);
- rc = -EINVAL;
+
+ if ((mode == ACTION_READ_INFOBLOCK && !param.infile)
+ || mode != ACTION_READ_INFOBLOCK) {
+ error("specify a namespace to %s, or \"all\"\n", action_string);
+ rc = -EINVAL;
+ }
}
for (i = mode == ACTION_CREATE ? 0 : 1; i < argc; i++) {
error("unknown extra parameter \"%s\"\n", argv[i]);
rc = -EINVAL;
}
+ if (mode == ACTION_READ_INFOBLOCK && param.infile && argc) {
+ error("specify a namespace, or --input, not both\n");
+ rc = -EINVAL;
+ }
+
if (rc) {
usage_with_options(u, options);
return NULL; /* we won't return from usage_with_options() */
@@ -1377,10 +1418,322 @@ static int namespace_clear_bb(struct ndctl_namespace *ndns, bool do_scrub)
return 0;
}
+struct read_infoblock_ctx {
+ struct json_object *jblocks;
+ FILE *f_out;
+};
+
+#define parse_field(sb, field) \
+do { \
+ jobj = json_object_new_int(le32_to_cpu((sb)->field)); \
+ if (!jobj) \
+ goto err; \
+ json_object_object_add(jblock, #field, jobj); \
+} while (0)
+
+#define parse_hex(sb, field, sz) \
+do { \
+ jobj = util_json_object_hex(le##sz##_to_cpu((sb)->field), flags); \
+ if (!jobj) \
+ goto err; \
+ json_object_object_add(jblock, #field, jobj); \
+} while (0)
+
+static json_object *btt_parse(struct btt_sb *btt_sb, struct ndctl_namespace *ndns,
+ const char *path, unsigned long flags)
+{
+ uuid_t uuid;
+ char str[40];
+ struct json_object *jblock, *jobj;
+ const char *cmd = "read-info-block";
+ const bool verify = param.verify;
+
+ if (verify && !verify_infoblock_checksum((union info_block *) btt_sb)) {
+ pr_verbose("%s: %s checksum verification failed\n", cmd, __func__);
+ return NULL;
+ }
+
+ if (ndns) {
+ ndctl_namespace_get_uuid(ndns, uuid);
+ if (verify && !uuid_is_null(uuid) && memcmp(uuid, btt_sb->parent_uuid,
+ sizeof(uuid) != 0)) {
+ pr_verbose("%s: %s uuid verification failed\n", cmd, __func__);
+ return NULL;
+ }
+ }
+
+ jblock = json_object_new_object();
+ if (!jblock)
+ return NULL;
+
+ if (ndns) {
+ jobj = json_object_new_string(ndctl_namespace_get_devname(ndns));
+ if (!jobj)
+ goto err;
+ json_object_object_add(jblock, "dev", jobj);
+ } else {
+ jobj = json_object_new_string(path);
+ if (!jobj)
+ goto err;
+ json_object_object_add(jblock, "file", jobj);
+ }
+
+ jobj = json_object_new_string((char *) btt_sb->signature);
+ if (!jobj)
+ goto err;
+ json_object_object_add(jblock, "signature", jobj);
+
+ uuid_unparse((void *) btt_sb->uuid, str);
+ jobj = json_object_new_string(str);
+ if (!jobj)
+ goto err;
+ json_object_object_add(jblock, "uuid", jobj);
+
+ uuid_unparse((void *) btt_sb->parent_uuid, str);
+ jobj = json_object_new_string(str);
+ if (!jobj)
+ goto err;
+ json_object_object_add(jblock, "parent_uuid", jobj);
+
+ jobj = util_json_object_hex(le32_to_cpu(btt_sb->flags), flags);
+ if (!jobj)
+ goto err;
+ json_object_object_add(jblock, "flags", jobj);
+
+ if (snprintf(str, 4, "%d.%d", btt_sb->version_major,
+ btt_sb->version_minor) >= 4)
+ goto err;
+ jobj = json_object_new_string(str);
+ if (!jobj)
+ goto err;
+ json_object_object_add(jblock, "version", jobj);
+
+ parse_field(btt_sb, external_lbasize);
+ parse_field(btt_sb, external_nlba);
+ parse_field(btt_sb, internal_lbasize);
+ parse_field(btt_sb, internal_nlba);
+ parse_field(btt_sb, nfree);
+ parse_field(btt_sb, infosize);
+ parse_hex(btt_sb, nextoff, 64);
+ parse_hex(btt_sb, dataoff, 64);
+ parse_hex(btt_sb, mapoff, 64);
+ parse_hex(btt_sb, logoff, 64);
+ parse_hex(btt_sb, info2off, 64);
+
+ return jblock;
+err:
+ pr_verbose("%s: failed to create json representation\n", cmd);
+ json_object_put(jblock);
+ return NULL;
+}
+
+static json_object *pfn_parse(struct pfn_sb *pfn_sb, struct ndctl_namespace *ndns,
+ const char *path, unsigned long flags)
+{
+ uuid_t uuid;
+ char str[40];
+ struct json_object *jblock, *jobj;
+ const char *cmd = "read-info-block";
+ const bool verify = param.verify;
+
+ if (verify && !verify_infoblock_checksum((union info_block *) pfn_sb)) {
+ pr_verbose("%s: %s checksum verification failed\n", cmd, __func__);
+ return NULL;
+ }
+
+ if (ndns) {
+ ndctl_namespace_get_uuid(ndns, uuid);
+ if (verify && !uuid_is_null(uuid) && memcmp(uuid, pfn_sb->parent_uuid,
+ sizeof(uuid) != 0)) {
+ pr_verbose("%s: %s uuid verification failed\n", cmd, __func__);
+ return NULL;
+ }
+ }
+
+ jblock = json_object_new_object();
+ if (!jblock)
+ return NULL;
+
+ if (ndns) {
+ jobj = json_object_new_string(ndctl_namespace_get_devname(ndns));
+ if (!jobj)
+ goto err;
+ json_object_object_add(jblock, "dev", jobj);
+ } else {
+ jobj = json_object_new_string(path);
+ if (!jobj)
+ goto err;
+ json_object_object_add(jblock, "file", jobj);
+ }
+
+ jobj = json_object_new_string((char *) pfn_sb->signature);
+ if (!jobj)
+ goto err;
+ json_object_object_add(jblock, "signature", jobj);
+
+ uuid_unparse((void *) pfn_sb->uuid, str);
+ jobj = json_object_new_string(str);
+ if (!jobj)
+ goto err;
+ json_object_object_add(jblock, "uuid", jobj);
+
+ uuid_unparse((void *) pfn_sb->parent_uuid, str);
+ jobj = json_object_new_string(str);
+ if (!jobj)
+ goto err;
+ json_object_object_add(jblock, "parent_uuid", jobj);
+
+ jobj = util_json_object_hex(le32_to_cpu(pfn_sb->flags), flags);
+ if (!jobj)
+ goto err;
+ json_object_object_add(jblock, "flags", jobj);
+
+ if (snprintf(str, 4, "%d.%d", pfn_sb->version_major,
+ pfn_sb->version_minor) >= 4)
+ goto err;
+ jobj = json_object_new_string(str);
+ if (!jobj)
+ goto err;
+ json_object_object_add(jblock, "version", jobj);
+
+ parse_hex(pfn_sb, dataoff, 64);
+ parse_hex(pfn_sb, npfns, 64);
+ parse_field(pfn_sb, mode);
+ parse_hex(pfn_sb, start_pad, 32);
+ parse_hex(pfn_sb, end_trunc, 32);
+ parse_hex(pfn_sb, align, 32);
+
+ return jblock;
+err:
+ pr_verbose("%s: failed to create json representation\n", cmd);
+ json_object_put(jblock);
+ return NULL;
+}
+
+#define INFOBLOCK_SZ SZ_8K
+
+static int parse_namespace_infoblock(char *_buf, struct ndctl_namespace *ndns,
+ const char *path, struct read_infoblock_ctx *ri_ctx)
+{
+ int rc;
+ void *buf = _buf;
+ unsigned long flags = param.human ? UTIL_JSON_HUMAN : 0;
+ struct btt_sb *btt1_sb = buf + SZ_4K, *btt2_sb = buf;
+ struct json_object *jblock = NULL, *jblocks = ri_ctx->jblocks;
+ struct pfn_sb *pfn_sb = buf + SZ_4K, *dax_sb = buf + SZ_4K;
+
+ if (!param.json && !param.human) {
+ rc = fwrite(buf, 1, INFOBLOCK_SZ, ri_ctx->f_out);
+ if (rc != INFOBLOCK_SZ)
+ return -EIO;
+ fflush(ri_ctx->f_out);
+ return 0;
+ }
+
+ if (!jblocks) {
+ jblocks = json_object_new_array();
+ if (!jblocks)
+ return -ENOMEM;
+ ri_ctx->jblocks = jblocks;
+ }
+
+ if (memcmp(btt1_sb->signature, BTT_SIG, BTT_SIG_LEN) == 0) {
+ jblock = btt_parse(btt1_sb, ndns, path, flags);
+ if (jblock)
+ json_object_array_add(jblocks, jblock);
+ }
+
+ if (memcmp(btt2_sb->signature, BTT_SIG, BTT_SIG_LEN) == 0) {
+ jblock = btt_parse(btt2_sb, ndns, path, flags);
+ if (jblock)
+ json_object_array_add(jblocks, jblock);
+ }
+
+ if (memcmp(pfn_sb->signature, PFN_SIG, PFN_SIG_LEN) == 0) {
+ jblock = pfn_parse(pfn_sb, ndns, path, flags);
+ if (jblock)
+ json_object_array_add(jblocks, jblock);
+ }
+
+ if (memcmp(dax_sb->signature, DAX_SIG, PFN_SIG_LEN) == 0) {
+ jblock = pfn_parse(dax_sb, ndns, path, flags);
+ if (jblock)
+ json_object_array_add(jblocks, jblock);
+ }
+
+ return 0;
+}
+
+static int file_read_infoblock(const char *path, struct ndctl_namespace *ndns,
+ struct read_infoblock_ctx *ri_ctx)
+{
+ const char *devname = ndns ? ndctl_namespace_get_devname(ndns) : "";
+ const char *cmd = "read-info-block";
+ void *buf = NULL;
+ int fd = -1, rc;
+
+ buf = calloc(1, INFOBLOCK_SZ);
+ if (!buf)
+ return -ENOMEM;
+
+ fd = open(path, O_RDONLY|O_EXCL);
+ if (fd < 0) {
+ pr_verbose("%s: %s failed to open %s: %s\n",
+ cmd, devname, path, strerror(errno));
+ rc = -errno;
+ goto out;
+ }
+
+ rc = read(fd, buf, INFOBLOCK_SZ);
+ if (rc < 0) {
+ pr_verbose("%s: %s failed to read %s: %s\n",
+ cmd, devname, path, strerror(errno));
+ rc = -errno;
+ goto out;
+ }
+
+ rc = parse_namespace_infoblock(buf, ndns, path, ri_ctx);
+out:
+ free(buf);
+ if (fd >= 0)
+ close(fd);
+ return rc;
+}
+
+static int namespace_read_infoblock(struct ndctl_namespace *ndns,
+ struct read_infoblock_ctx *ri_ctx)
+{
+ int rc;
+ char path[50];
+ const char *cmd = "read-info-block";
+ const char *devname = ndctl_namespace_get_devname(ndns);
+
+ if (ndctl_namespace_is_active(ndns)) {
+ pr_verbose("%s: %s enabled, must be disabled\n", cmd, devname);
+ return -EBUSY;
+ }
+
+ ndctl_namespace_set_raw_mode(ndns, 1);
+ rc = ndctl_namespace_enable(ndns);
+ if (rc < 0) {
+ pr_verbose("%s: %s failed to enable\n", cmd, devname);
+ goto out;
+ }
+
+ sprintf(path, "/dev/%s", ndctl_namespace_get_block_device(ndns));
+ rc = file_read_infoblock(path, ndns, ri_ctx);
+
+out:
+ ndctl_namespace_set_raw_mode(ndns, 0);
+ ndctl_namespace_disable_invalidate(ndns);
+ return rc;
+}
+
static int do_xaction_namespace(const char *namespace,
enum device_action action, struct ndctl_ctx *ctx,
int *processed)
{
+ struct read_infoblock_ctx ri_ctx = { 0 };
struct ndctl_namespace *ndns, *_n;
int rc = -ENXIO, saved_rc = 0;
struct ndctl_region *region;
@@ -1389,6 +1742,26 @@ static int do_xaction_namespace(const char *namespace,
*processed = 0;
+ if (action == ACTION_READ_INFOBLOCK) {
+ if (!param.outfile)
+ ri_ctx.f_out = stdout;
+ else {
+ ri_ctx.f_out = fopen(param.outfile, "w+");
+ if (!ri_ctx.f_out) {
+ fprintf(stderr, "failed to open: %s: (%s)\n",
+ param.outfile, strerror(errno));
+ return -errno;
+ }
+ }
+
+ if (param.infile) {
+ rc = file_read_infoblock(param.infile, NULL, &ri_ctx);
+ if (ri_ctx.jblocks)
+ util_display_json_array(ri_ctx.f_out, ri_ctx.jblocks, 0);
+ return rc;
+ }
+ }
+
if (!namespace && action != ACTION_CREATE)
return rc;
@@ -1494,6 +1867,11 @@ static int do_xaction_namespace(const char *namespace,
if (rc == 0)
*processed = 1;
return rc;
+ case ACTION_READ_INFOBLOCK:
+ rc = namespace_read_infoblock(ndns, &ri_ctx);
+ if (rc == 0)
+ (*processed)++;
+ break;
default:
rc = -EINVAL;
break;
@@ -1502,6 +1880,12 @@ static int do_xaction_namespace(const char *namespace,
}
}
+ if (ri_ctx.jblocks)
+ util_display_json_array(ri_ctx.f_out, ri_ctx.jblocks, 0);
+
+ if (ri_ctx.f_out && ri_ctx.f_out != stdout)
+ fclose(ri_ctx.f_out);
+
if (action == ACTION_CREATE && rc == -EAGAIN) {
/*
* Namespace creation searched through all candidate
@@ -1634,3 +2018,19 @@ int cmd_clear_errors(int argc , const char **argv, struct ndctl_ctx *ctx)
cleared == 1 ? "" : "s");
return rc;
}
+
+int cmd_read_infoblock(int argc, const char **argv, struct ndctl_ctx *ctx)
+{
+ char *xable_usage = "ndctl read-info-block <namespace> [<options>]";
+ const char *namespace = parse_namespace_options(argc, argv,
+ ACTION_READ_INFOBLOCK, read_infoblock_options,
+ xable_usage);
+ int read, rc;
+
+ rc = do_xaction_namespace(namespace, ACTION_READ_INFOBLOCK, ctx, &read);
+ if (rc < 0)
+ fprintf(stderr, "error checking namespaces: %s\n",
+ strerror(-rc));
+ fprintf(stderr, "read %d namespace%s\n", read, read == 1 ? "" : "s");
+ return rc;
+}
diff --git a/ndctl/namespace.h b/ndctl/namespace.h
index bc210857642f..861dfbfa5127 100644
--- a/ndctl/namespace.h
+++ b/ndctl/namespace.h
@@ -13,7 +13,9 @@
#ifndef __NDCTL_NAMESPACE_H__
#define __NDCTL_NAMESPACE_H__
#include <sys/types.h>
+#include <util/util.h>
#include <util/size.h>
+#include <util/fletcher.h>
#include <ccan/endian/endian.h>
#include <ccan/short_types/short_types.h>
@@ -202,4 +204,53 @@ struct arena_map {
struct btt_sb *info2;
size_t info2_len;
};
+
+#define PFN_SIG_LEN 16
+#define PFN_SIG "NVDIMM_PFN_INFO\0"
+#define DAX_SIG "NVDIMM_DAX_INFO\0"
+
+struct pfn_sb {
+ u8 signature[PFN_SIG_LEN];
+ u8 uuid[16];
+ u8 parent_uuid[16];
+ le32 flags;
+ le16 version_major;
+ le16 version_minor;
+ le64 dataoff; /* relative to namespace_base + start_pad */
+ le64 npfns;
+ le32 mode;
+ /* minor-version-1 additions for section alignment */
+ le32 start_pad;
+ le32 end_trunc;
+ /* minor-version-2 record the base alignment of the mapping */
+ le32 align;
+ u8 padding[4000];
+ le64 checksum;
+};
+
+union info_block {
+ struct pfn_sb pfn_sb;
+ struct btt_sb btt_sb;
+};
+
+static inline bool verify_infoblock_checksum(union info_block *sb)
+{
+ uint64_t sum;
+ le64 sum_save;
+
+ BUILD_BUG_ON(sizeof(union info_block) != SZ_4K);
+
+ /* all infoblocks share the btt_sb layout for checksum */
+ sum_save = sb->btt_sb.checksum;
+ sb->btt_sb.checksum = 0;
+ sum = fletcher64(&sb->btt_sb, sizeof(*sb), 1);
+ if (sum != sum_save)
+ return false;
+ /* restore the checksum in the buffer */
+ sb->btt_sb.checksum = sum_save;
+
+ return true;
+}
+
+
#endif /* __NDCTL_NAMESPACE_H__ */
diff --git a/ndctl/ndctl.c b/ndctl/ndctl.c
index 6c4975c9f841..5c9c424dcae6 100644
--- a/ndctl/ndctl.c
+++ b/ndctl/ndctl.c
@@ -73,6 +73,7 @@ static struct cmd_struct commands[] = {
{ "disable-namespace", { cmd_disable_namespace } },
{ "create-namespace", { cmd_create_namespace } },
{ "destroy-namespace", { cmd_destroy_namespace } },
+ { "read-infoblock", { cmd_read_infoblock } },
{ "check-namespace", { cmd_check_namespace } },
{ "clear-errors", { cmd_clear_errors } },
{ "enable-region", { cmd_enable_region } },
diff --git a/util/fletcher.h b/util/fletcher.h
index 54e2ecf5d6ed..8fccac4ec758 100644
--- a/util/fletcher.h
+++ b/util/fletcher.h
@@ -1,6 +1,7 @@
#ifndef _NDCTL_FLETCHER_H_
#define _NDCTL_FLETCHER_H_
+#include <stdbool.h>
#include <ccan/endian/endian.h>
#include <ccan/short_types/short_types.h>
diff --git a/util/size.h b/util/size.h
index 2f36c2c85ca7..2138989b42ac 100644
--- a/util/size.h
+++ b/util/size.h
@@ -17,6 +17,7 @@
#define SZ_1K 0x00000400
#define SZ_4K 0x00001000
+#define SZ_8K 0x00002000
#define SZ_1M 0x00100000
#define SZ_2M 0x00200000
#define SZ_4M 0x00400000
_______________________________________________
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-02-29 20:37 UTC|newest]
Thread overview: 44+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-02-29 20:20 [ndctl PATCH 00/36] Multiple topics / backlog for v68 Dan Williams
2020-02-29 20:20 ` [ndctl PATCH 01/36] ndctl/list: Add 'target_node' to region and namespace verbose listings Dan Williams
2020-02-29 20:20 ` [ndctl PATCH 02/36] ndctl/docs: Fix mailing list sign-up link Dan Williams
2020-02-29 20:20 ` [ndctl PATCH 03/36] ndctl/list: Drop named list objects from verbose listing Dan Williams
2020-02-29 20:20 ` [ndctl PATCH 04/36] daxctl/list: Avoid memory operations without resource data Dan Williams
2020-02-29 20:20 ` [ndctl PATCH 05/36] ndctl/build: Fix distcheck Dan Williams
2020-02-29 20:20 ` [ndctl PATCH 06/36] ndctl/namespace: Fix destroy-namespace accounting relative to seed devices Dan Williams
2020-02-29 20:20 ` [ndctl PATCH 07/36] ndctl/region: Support ndctl_region_{get, set}_align() Dan Williams
2020-02-29 20:20 ` [ndctl PATCH 08/36] ndctl/namespace: Emit better errors on failure Dan Williams
2020-02-29 20:20 ` [ndctl PATCH 09/36] ndctl/namespace: Check for region alignment violations Dan Williams
2020-02-29 20:20 ` [ndctl PATCH 10/36] ndctl/util: Up-level is_power_of_2() and introduce IS_ALIGNED Dan Williams
2020-02-29 20:21 ` [ndctl PATCH 11/36] ndctl/namespace: Validate resource alignment for dax-mode namespaces Dan Williams
2020-02-29 20:21 ` Dan Williams [this message]
2020-02-29 20:21 ` [ndctl PATCH 13/36] ndctl/test: Update dax-dev to handle multiple e820 ranges Dan Williams
2020-02-29 20:21 ` [ndctl PATCH 14/36] ndctl/namespace: Always zero info-blocks Dan Williams
2020-02-29 20:21 ` [ndctl PATCH 15/36] ndctl/namespace: Disable autorecovery of create-namespace failures Dan Williams
2020-02-29 20:21 ` [ndctl PATCH 16/36] ndctl/build: Fix EXTRA_DIST already defined errors Dan Williams
2020-02-29 20:21 ` [ndctl PATCH 17/36] ndctl/test: Checkout device-mapper + dax operation Dan Williams
2020-02-29 20:21 ` [ndctl PATCH 18/36] ndctl/test: Exercise sub-section sized namespace creation/deletion Dan Williams
2020-02-29 20:21 ` [ndctl PATCH 19/36] ndctl/namespace: Kill off the legacy mode names Dan Williams
2020-02-29 20:21 ` [ndctl PATCH 20/36] ndctl/namespace: Introduce mode-to-name and name-to-mode helpers Dan Williams
2020-02-29 20:21 ` [ndctl PATCH 21/36] ndctl/namespace: Validate namespace size within validate_namespace_options() Dan Williams
2020-02-29 20:22 ` [ndctl PATCH 22/36] ndctl/namespace: Clarify 16M minimum size requirement Dan Williams
2020-02-29 20:22 ` [ndctl PATCH 23/36] ndctl/test: Regression test 'failed to track' Dan Williams
2020-02-29 20:22 ` [ndctl PATCH 24/36] ndctl/dimm: Rework dimm command status reporting Dan Williams
2020-02-29 20:22 ` [ndctl PATCH 25/36] ndctl/dimm: Rework iteration to drop unaligned pointers Dan Williams
2020-02-29 20:22 ` [ndctl PATCH 26/36] ndctl/test: Fix typos / loss of tpm.handle in security test Dan Williams
2020-02-29 20:22 ` [ndctl PATCH 27/36] ndctl/test: Relax dax_pmem_compat requirement Dan Williams
2020-03-03 13:28 ` Jan Kara
2020-03-03 21:05 ` Dan Williams
2020-03-03 22:58 ` [ndctl PATCH v2 1/2] ndctl/test: Cleanup test-vs-production nvdimm module detection Dan Williams
2020-03-04 12:44 ` Jan Kara
2020-03-03 22:58 ` [ndctl PATCH v2 2/2] ndctl/test: Relax dax_pmem_compat requirement Dan Williams
2020-03-04 12:44 ` Jan Kara
2020-02-29 20:22 ` [ndctl PATCH 28/36] ndctl/namespace: Fix namespace-action vs namespace-mode confusion Dan Williams
2020-02-29 20:22 ` [ndctl PATCH 29/36] ndctl/namespace: Update 'pfn' infoblock definition Dan Williams
2020-02-29 20:22 ` [ndctl PATCH 30/36] ndctl/util: Return 0 for NULL arguments to parse_size64() Dan Williams
2020-02-29 20:22 ` [ndctl PATCH 31/36] ndctl/namespace: Fix read-info-block vs read-infoblock Dan Williams
2020-02-29 20:22 ` [ndctl PATCH 32/36] ndctl/namespace: Parse infoblocks from stdin Dan Williams
2020-02-29 20:23 ` [ndctl PATCH 33/36] ndctl/namespace: Add write-infoblock command Dan Williams
2020-02-29 20:23 ` [ndctl PATCH 34/36] ndctl/list: Add option to list configured + disabled namespaces Dan Williams
2020-02-29 20:23 ` [ndctl PATCH 35/36] ndctl/lib/namespace: Fix resource retrieval after size change Dan Williams
2020-02-29 20:23 ` [ndctl PATCH 36/36] ndctl/test: Regression test misaligned namespaces Dan Williams
2020-03-19 4:13 ` [ndctl PATCH 00/36] Multiple topics / backlog for v68 Verma, Vishal L
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=158300766814.2141307.3604583129159405889.stgit@dwillia2-desk3.amr.corp.intel.com \
--to=dan.j.williams@intel.com \
--cc=linux-nvdimm@lists.01.org \
--cc=vishal.l.verma@intel.com \
/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).