Allow for more precision in label utilities, i.e. stop operating over
the entire label area.

Signed-off-by: Dan Williams <dan.j.willi...@intel.com>
---
 Documentation/ndctl/labels-options.txt |    9 ++++++
 ndctl/dimm.c                           |   45 ++++++++++++++++++++++++--------
 ndctl/lib/dimm.c                       |   36 +++++++++++++++++++++-----
 ndctl/lib/libndctl.sym                 |    2 +
 ndctl/lib/private.h                    |    3 --
 ndctl/libndctl.h                       |    4 +++
 util/util.h                            |    4 +++
 7 files changed, 83 insertions(+), 20 deletions(-)

diff --git a/Documentation/ndctl/labels-options.txt 
b/Documentation/ndctl/labels-options.txt
index 539ace079557..4aee37969fd5 100644
--- a/Documentation/ndctl/labels-options.txt
+++ b/Documentation/ndctl/labels-options.txt
@@ -5,6 +5,15 @@
        operate on every dimm in the system, optionally filtered by bus id (see
         --bus= option).
 
+-s::
+--size=::
+       Limit the operation to the given number of bytes. A size of 0
+       indicates to operate over the entire label capacity.
+
+-O::
+--offset=::
+       Begin the operation at the given offset into the label area.
+
 -b::
 --bus=::
        Limit operation to memory devices (dimms) that are on the given bus.
diff --git a/ndctl/dimm.c b/ndctl/dimm.c
index 5edada678c9c..478e0fea3afc 100644
--- a/ndctl/dimm.c
+++ b/ndctl/dimm.c
@@ -47,6 +47,8 @@ static struct parameters {
        const char *infile;
        const char *labelversion;
        const char *kek;
+       unsigned len;
+       unsigned offset;
        bool crypto_erase;
        bool overwrite;
        bool master_pass;
@@ -76,7 +78,7 @@ static int action_enable(struct ndctl_dimm *dimm, struct 
action_context *actx)
 
 static int action_zero(struct ndctl_dimm *dimm, struct action_context *actx)
 {
-       return ndctl_dimm_zero_labels(dimm);
+       return ndctl_dimm_zero_label_extent(dimm, param.len, param.offset);
 }
 
 static struct json_object *dump_label_json(struct ndctl_dimm *dimm,
@@ -298,15 +300,17 @@ static struct json_object *dump_json(struct ndctl_dimm 
*dimm,
        return NULL;
 }
 
-static int rw_bin(FILE *f, struct ndctl_cmd *cmd, ssize_t size, int rw)
+static int rw_bin(FILE *f, struct ndctl_cmd *cmd, ssize_t size,
+               unsigned int start_offset, int rw)
 {
        char buf[4096];
        ssize_t offset, write = 0;
 
-       for (offset = 0; offset < size; offset += sizeof(buf)) {
+       for (offset = start_offset; offset < start_offset + size;
+                       offset += sizeof(buf)) {
                ssize_t len = min_t(ssize_t, sizeof(buf), size - offset), rc;
 
-               if (rw) {
+               if (rw == WRITE) {
                        len = fread(buf, 1, len, f);
                        if (len == 0)
                                break;
@@ -342,9 +346,9 @@ static int action_write(struct ndctl_dimm *dimm, struct 
action_context *actx)
                return -EBUSY;
        }
 
-       cmd_read = ndctl_dimm_read_labels(dimm);
+       cmd_read = ndctl_dimm_read_label_extent(dimm, param.len, param.offset);
        if (!cmd_read)
-               return -ENXIO;
+               return -EINVAL;
 
        cmd_write = ndctl_dimm_cmd_new_cfg_write(cmd_read);
        if (!cmd_write) {
@@ -353,7 +357,7 @@ static int action_write(struct ndctl_dimm *dimm, struct 
action_context *actx)
        }
 
        size = ndctl_cmd_cfg_read_get_size(cmd_read);
-       rc = rw_bin(actx->f_in, cmd_write, size, 1);
+       rc = rw_bin(actx->f_in, cmd_write, size, param.offset, WRITE);
 
        /*
         * If the dimm is already disabled the kernel is not holding a cached
@@ -380,9 +384,9 @@ static int action_read(struct ndctl_dimm *dimm, struct 
action_context *actx)
        ssize_t size;
        int rc = 0;
 
-       cmd_read = ndctl_dimm_read_labels(dimm);
+       cmd_read = ndctl_dimm_read_label_extent(dimm, param.len, param.offset);
        if (!cmd_read)
-               return -ENXIO;
+               return -EINVAL;
 
        size = ndctl_cmd_cfg_read_get_size(cmd_read);
        if (actx->jdimms) {
@@ -393,7 +397,7 @@ static int action_read(struct ndctl_dimm *dimm, struct 
action_context *actx)
                else
                        rc = -ENOMEM;
        } else
-               rc = rw_bin(actx->f_out, cmd_read, size, 0);
+               rc = rw_bin(actx->f_out, cmd_read, size, param.offset, READ);
 
        ndctl_cmd_unref(cmd_read);
 
@@ -1072,18 +1076,31 @@ OPT_BOOLEAN('o', "overwrite", &param.overwrite, \
 OPT_BOOLEAN('m', "master-passphrase", &param.master_pass, \
                "use master passphrase")
 
+#define LABEL_OPTIONS() \
+OPT_UINTEGER('s', "size", &param.len, "number of label bytes to operate"), \
+OPT_UINTEGER('O', "offset", &param.offset, \
+       "offset into the label area to start operation")
+
 static const struct option read_options[] = {
        BASE_OPTIONS(),
+       LABEL_OPTIONS(),
        READ_OPTIONS(),
        OPT_END(),
 };
 
 static const struct option write_options[] = {
        BASE_OPTIONS(),
+       LABEL_OPTIONS(),
        WRITE_OPTIONS(),
        OPT_END(),
 };
 
+static const struct option zero_options[] = {
+       BASE_OPTIONS(),
+       LABEL_OPTIONS(),
+       OPT_END(),
+};
+
 static const struct option update_options[] = {
        BASE_OPTIONS(),
        UPDATE_OPTIONS(),
@@ -1150,6 +1167,12 @@ static int dimm_action(int argc, const char **argv, 
struct ndctl_ctx *ctx,
                return -EINVAL;
        }
 
+       if (action == action_read && param.json && (param.len || param.offset)) 
{
+               fprintf(stderr, "--size and --offset are incompatible with 
--json\n");
+               usage_with_options(u, options);
+               return -EINVAL;
+       }
+
        if (param.json) {
                actx.jdimms = json_object_new_array();
                if (!actx.jdimms)
@@ -1284,7 +1307,7 @@ int cmd_read_labels(int argc, const char **argv, struct 
ndctl_ctx *ctx)
 
 int cmd_zero_labels(int argc, const char **argv, struct ndctl_ctx *ctx)
 {
-       int count = dimm_action(argc, argv, ctx, action_zero, base_options,
+       int count = dimm_action(argc, argv, ctx, action_zero, zero_options,
                        "ndctl zero-labels <nmem0> [<nmem1>..<nmemN>] 
[<options>]");
 
        fprintf(stderr, "zeroed %d nmem%s\n", count >= 0 ? count : 0,
diff --git a/ndctl/lib/dimm.c b/ndctl/lib/dimm.c
index 9c5a34e542c3..28b1dfb0bdfa 100644
--- a/ndctl/lib/dimm.c
+++ b/ndctl/lib/dimm.c
@@ -537,7 +537,8 @@ NDCTL_EXPORT struct ndctl_cmd 
*ndctl_dimm_read_label_index(struct ndctl_dimm *di
         return NULL;
 }
 
-NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_read_labels(struct ndctl_dimm *dimm)
+NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_read_label_extent(
+               struct ndctl_dimm *dimm, unsigned int len, unsigned int offset)
 {
         struct ndctl_bus *bus = ndctl_dimm_get_bus(dimm);
         struct ndctl_cmd *cmd_size, *cmd_read;
@@ -557,13 +558,25 @@ NDCTL_EXPORT struct ndctl_cmd 
*ndctl_dimm_read_labels(struct ndctl_dimm *dimm)
         cmd_read = ndctl_dimm_cmd_new_cfg_read(cmd_size);
         if (!cmd_read)
                 goto out_size;
+
+       /*
+        * For ndctl_read_labels() compat, enable subsequent calls that
+        * will manipulate labels
+        */
+       if (len == 0 && offset == 0)
+               init_ndd(&dimm->ndd, cmd_read, cmd_size);
+
+       if (len == 0)
+               len = cmd_size->get_size->config_size;
+       rc = ndctl_cmd_cfg_read_set_extent(cmd_read, len, offset);
+       if (rc < 0)
+               goto out_size;
+
         rc = ndctl_cmd_submit_xlat(cmd_read);
         if (rc < 0)
                 goto out_read;
        ndctl_cmd_unref(cmd_size);
 
-       init_ndd(&dimm->ndd, cmd_read, cmd_size);
-
        return cmd_read;
 
  out_read:
@@ -573,15 +586,21 @@ NDCTL_EXPORT struct ndctl_cmd 
*ndctl_dimm_read_labels(struct ndctl_dimm *dimm)
         return NULL;
 }
 
-NDCTL_EXPORT int ndctl_dimm_zero_labels(struct ndctl_dimm *dimm)
+NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_read_labels(struct ndctl_dimm *dimm)
+{
+       return ndctl_dimm_read_label_extent(dimm, 0, 0);
+}
+
+NDCTL_EXPORT int ndctl_dimm_zero_label_extent(struct ndctl_dimm *dimm,
+               unsigned int len, unsigned int offset)
 {
        struct ndctl_ctx *ctx = ndctl_dimm_get_ctx(dimm);
        struct ndctl_cmd *cmd_read, *cmd_write;
        int rc;
 
-       cmd_read = ndctl_dimm_read_labels(dimm);
+       cmd_read = ndctl_dimm_read_label_extent(dimm, len, offset);
        if (!cmd_read)
-               return -ENXIO;
+               return -EINVAL;
 
        if (ndctl_dimm_is_active(dimm)) {
                dbg(ctx, "%s: regions active, abort label write\n",
@@ -623,6 +642,11 @@ NDCTL_EXPORT int ndctl_dimm_zero_labels(struct ndctl_dimm 
*dimm)
        return rc;
 }
 
+NDCTL_EXPORT int ndctl_dimm_zero_labels(struct ndctl_dimm *dimm)
+{
+       return ndctl_dimm_zero_label_extent(dimm, 0, 0);
+}
+
 NDCTL_EXPORT unsigned long ndctl_dimm_get_available_labels(
                struct ndctl_dimm *dimm)
 {
diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym
index 3cd431a90e55..895fb358c43a 100644
--- a/ndctl/lib/libndctl.sym
+++ b/ndctl/lib/libndctl.sym
@@ -412,4 +412,6 @@ global:
        ndctl_cmd_cfg_read_set_extent;
        ndctl_cmd_cfg_write_set_extent;
        ndctl_dimm_read_label_index;
+       ndctl_dimm_read_label_extent;
+       ndctl_dimm_zero_label_extent;
 } LIBNDCTL_19;
diff --git a/ndctl/lib/private.h b/ndctl/lib/private.h
index 5a17f0b63b80..1304017d5e3b 100644
--- a/ndctl/lib/private.h
+++ b/ndctl/lib/private.h
@@ -241,9 +241,6 @@ struct ndctl_namespace {
  *
  * A command may only specify one of @source, or @iter.total_buf, not both.
  */
-enum {
-       READ, WRITE,
-};
 struct ndctl_cmd {
        struct ndctl_dimm *dimm;
        struct ndctl_bus *bus;
diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h
index 8aa4b8bbe6c2..c9d0dc120d3b 100644
--- a/ndctl/libndctl.h
+++ b/ndctl/libndctl.h
@@ -307,8 +307,12 @@ struct ndctl_cmd *ndctl_dimm_cmd_new_cfg_size(struct 
ndctl_dimm *dimm);
 struct ndctl_cmd *ndctl_dimm_cmd_new_cfg_read(struct ndctl_cmd *cfg_size);
 struct ndctl_cmd *ndctl_dimm_cmd_new_cfg_write(struct ndctl_cmd *cfg_read);
 int ndctl_dimm_zero_labels(struct ndctl_dimm *dimm);
+int ndctl_dimm_zero_label_extent(struct ndctl_dimm *dimm,
+               unsigned int len, unsigned int offset);
 struct ndctl_cmd *ndctl_dimm_read_labels(struct ndctl_dimm *dimm);
 struct ndctl_cmd *ndctl_dimm_read_label_index(struct ndctl_dimm *dimm);
+struct ndctl_cmd *ndctl_dimm_read_label_extent(struct ndctl_dimm *dimm,
+               unsigned int len, unsigned int offset);
 int ndctl_dimm_validate_labels(struct ndctl_dimm *dimm);
 enum ndctl_namespace_version {
        NDCTL_NS_VERSION_1_1,
diff --git a/util/util.h b/util/util.h
index 001707e8b159..54c6ef18b6d7 100644
--- a/util/util.h
+++ b/util/util.h
@@ -73,6 +73,10 @@
 #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
 #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
 
+enum {
+       READ, WRITE,
+};
+
 static inline const char *skip_prefix(const char *str, const char *prefix)
 {
         size_t len = strlen(prefix);

_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm

Reply via email to