From: Vishal Verma <vishal.l.verma@intel.com> To: <linux-cxl@vger.kernel.org> Cc: Dan Williams <dan.j.williams@intel.com>, Ben Widawsky <ben.widawsky@intel.com>, <nvdimm@lists.linux.dev>, Vishal Verma <vishal.l.verma@intel.com> Subject: [ndctl PATCH v4 13/17] cxl: add commands to read, write, and zero labels Date: Thu, 7 Oct 2021 02:21:35 -0600 [thread overview] Message-ID: <20211007082139.3088615-14-vishal.l.verma@intel.com> (raw) In-Reply-To: <20211007082139.3088615-1-vishal.l.verma@intel.com> Add the following cxl-cli commands: read-labels, write-labels, zero-labels. They operate on a CXL memdev, or a set of memdevs, and allow interacting with the label storage area (LSA) on the device. Add man pages for the above cxl-cli commands. Cc: Dan Williams <dan.j.williams@intel.com> Signed-off-by: Vishal Verma <vishal.l.verma@intel.com> --- Documentation/cxl/cxl-read-labels.txt | 33 +++ Documentation/cxl/cxl-write-labels.txt | 32 +++ Documentation/cxl/cxl-zero-labels.txt | 29 +++ Documentation/cxl/labels-description.txt | 8 + Documentation/cxl/labels-options.txt | 17 ++ Documentation/cxl/memdev-option.txt | 4 + cxl/builtin.h | 5 + cxl/cxl.c | 3 + cxl/memdev.c | 314 +++++++++++++++++++++++ Documentation/cxl/Makefile.am | 5 +- cxl/Makefile.am | 1 + 11 files changed, 450 insertions(+), 1 deletion(-) create mode 100644 Documentation/cxl/cxl-read-labels.txt create mode 100644 Documentation/cxl/cxl-write-labels.txt create mode 100644 Documentation/cxl/cxl-zero-labels.txt create mode 100644 Documentation/cxl/labels-description.txt create mode 100644 Documentation/cxl/labels-options.txt create mode 100644 Documentation/cxl/memdev-option.txt create mode 100644 cxl/memdev.c diff --git a/Documentation/cxl/cxl-read-labels.txt b/Documentation/cxl/cxl-read-labels.txt new file mode 100644 index 0000000..143f296 --- /dev/null +++ b/Documentation/cxl/cxl-read-labels.txt @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0 + +cxl-read-labels(1) +================== + +NAME +---- +cxl-read-labels - read out the label area on a CXL memdev + +SYNOPSIS +-------- +[verse] +'cxl read-labels' <mem0> [<mem1>..<memN>] [<options>] + +include::labels-description.txt[] +This command dumps the raw binary data in a memdev's label area to stdout or a +file. In the multi-memdev case the data is concatenated. + +OPTIONS +------- +include::labels-options.txt[] + +-o:: +--output:: + output file + +include::../copyright.txt[] + +SEE ALSO +-------- +linkcxl:cxl-write-labels[1], +linkcxl:cxl-zero-labels[1], +CXL-2.0 9.13.2 diff --git a/Documentation/cxl/cxl-write-labels.txt b/Documentation/cxl/cxl-write-labels.txt new file mode 100644 index 0000000..c4592b3 --- /dev/null +++ b/Documentation/cxl/cxl-write-labels.txt @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 + +cxl-write-labels(1) +=================== + +NAME +---- +cxl-write-labels - write data to the label area on a memdev + +SYNOPSIS +-------- +[verse] +'cxl write-labels <mem> [-i <filename>]' + +include::labels-description.txt[] +Read data from the input filename, or stdin, and write it to the given +<mem> device. Note that the device must not be active in any region, +otherwise the kernel will not allow write access to the device's label +data area. + +OPTIONS +------- +include::labels-options.txt[] +-i:: +--input:: + input file + +SEE ALSO +-------- +linkcxl:cxl-read-labels[1], +linkcxl:cxl-zero-labels[1], +CXL-2.0 9.13.2 diff --git a/Documentation/cxl/cxl-zero-labels.txt b/Documentation/cxl/cxl-zero-labels.txt new file mode 100644 index 0000000..bf95b24 --- /dev/null +++ b/Documentation/cxl/cxl-zero-labels.txt @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 + +cxl-zero-labels(1) +================== + +NAME +---- +cxl-zero-labels - zero out the label area on a set of memdevs + +SYNOPSIS +-------- +[verse] +'cxl zero-labels' <mem0> [<mem1>..<memN>] [<options>] + +include::labels-description.txt[] +This command resets the device to its default state by +deleting all labels. + +OPTIONS +------- +include::labels-options.txt[] + +include::../copyright.txt[] + +SEE ALSO +-------- +linkcxl:cxl-read-labels[1], +linkcxl:cxl-write-labels[1], +CXL-2.0 9.13.2 diff --git a/Documentation/cxl/labels-description.txt b/Documentation/cxl/labels-description.txt new file mode 100644 index 0000000..f60bd5d --- /dev/null +++ b/Documentation/cxl/labels-description.txt @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 + +DESCRIPTION +----------- +The region label area is a small persistent partition of capacity +available on some CXL memory devices. The label area is used to +and configure or determine the set of memory devices participating +in different interleave sets. diff --git a/Documentation/cxl/labels-options.txt b/Documentation/cxl/labels-options.txt new file mode 100644 index 0000000..06fbac3 --- /dev/null +++ b/Documentation/cxl/labels-options.txt @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0 + +<memory device(s)>:: +include::memdev-option.txt[] + +-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. + +-v:: + Turn on verbose debug messages in the library (if libcxl was built with + logging and debug enabled). diff --git a/Documentation/cxl/memdev-option.txt b/Documentation/cxl/memdev-option.txt new file mode 100644 index 0000000..e778582 --- /dev/null +++ b/Documentation/cxl/memdev-option.txt @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 +A 'memX' device name, or a memdev id number. Restrict the operation to +the specified memdev(s). The keyword 'all' can be specified to indicate +the lack of any restriction. diff --git a/cxl/builtin.h b/cxl/builtin.h index 3797f98..78eca6e 100644 --- a/cxl/builtin.h +++ b/cxl/builtin.h @@ -5,4 +5,9 @@ struct cxl_ctx; int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_write_labels(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_read_labels(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_zero_labels(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_init_labels(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_check_labels(int argc, const char **argv, struct cxl_ctx *ctx); #endif /* _CXL_BUILTIN_H_ */ diff --git a/cxl/cxl.c b/cxl/cxl.c index a7725f8..4b1661d 100644 --- a/cxl/cxl.c +++ b/cxl/cxl.c @@ -61,6 +61,9 @@ static struct cmd_struct commands[] = { { "version", .c_fn = cmd_version }, { "list", .c_fn = cmd_list }, { "help", .c_fn = cmd_help }, + { "zero-labels", .c_fn = cmd_zero_labels }, + { "read-labels", .c_fn = cmd_read_labels }, + { "write-labels", .c_fn = cmd_write_labels }, }; int main(int argc, const char **argv) diff --git a/cxl/memdev.c b/cxl/memdev.c new file mode 100644 index 0000000..ffc66df --- /dev/null +++ b/cxl/memdev.c @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2020-2021 Intel Corporation. All rights reserved. */ +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#include <util/log.h> +#include <util/filter.h> +#include <cxl/libcxl.h> +#include <util/parse-options.h> +#include <ccan/minmax/minmax.h> +#include <ccan/array_size/array_size.h> + +struct action_context { + FILE *f_out; + FILE *f_in; +}; + +static struct parameters { + const char *outfile; + const char *infile; + unsigned len; + unsigned offset; + bool verbose; +} param; + +#define fail(fmt, ...) \ +do { \ + fprintf(stderr, "cxl-%s:%s:%d: " fmt, \ + VERSION, __func__, __LINE__, ##__VA_ARGS__); \ +} while (0) + +#define BASE_OPTIONS() \ +OPT_BOOLEAN('v',"verbose", ¶m.verbose, "turn on debug") + +#define READ_OPTIONS() \ +OPT_STRING('o', "output", ¶m.outfile, "output-file", \ + "filename to write label area contents") + +#define WRITE_OPTIONS() \ +OPT_STRING('i', "input", ¶m.infile, "input-file", \ + "filename to read label area data") + +#define LABEL_OPTIONS() \ +OPT_UINTEGER('s', "size", ¶m.len, "number of label bytes to operate"), \ +OPT_UINTEGER('O', "offset", ¶m.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 int action_zero(struct cxl_memdev *memdev, struct action_context *actx) +{ + int rc; + + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort label write\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + rc = cxl_memdev_zero_label(memdev); + if (rc < 0) + fprintf(stderr, "%s: label zeroing failed: %s\n", + cxl_memdev_get_devname(memdev), strerror(-rc)); + + return rc; +} + +static int action_write(struct cxl_memdev *memdev, struct action_context *actx) +{ + size_t size = param.len, read_len; + unsigned char *buf; + int rc; + + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s is active, abort label write\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + if (!size) { + size_t label_size = cxl_memdev_get_label_size(memdev); + + fseek(actx->f_in, 0L, SEEK_END); + size = ftell(actx->f_in); + fseek(actx->f_in, 0L, SEEK_SET); + + if (size > label_size) { + fprintf(stderr, + "File size (%zu) greater than label area size (%zu), aborting\n", + size, label_size); + return -EINVAL; + } + } + + buf = calloc(1, size); + if (!buf) + return -ENOMEM; + + read_len = fread(buf, 1, size, actx->f_in); + if (read_len != size) { + rc = -ENXIO; + goto out; + } + + rc = cxl_memdev_write_label(memdev, buf, size, param.offset); + if (rc < 0) + fprintf(stderr, "%s: label write failed: %s\n", + cxl_memdev_get_devname(memdev), strerror(-rc)); + +out: + free(buf); + return rc; +} + +static int action_read(struct cxl_memdev *memdev, struct action_context *actx) +{ + size_t size = param.len, write_len; + char *buf; + int rc; + + if (!size) + size = cxl_memdev_get_label_size(memdev); + + buf = calloc(1, size); + if (!buf) + return -ENOMEM; + + rc = cxl_memdev_read_label(memdev, buf, size, param.offset); + if (rc < 0) { + fprintf(stderr, "%s: label read failed: %s\n", + cxl_memdev_get_devname(memdev), strerror(-rc)); + goto out; + } + + write_len = fwrite(buf, 1, size, actx->f_out); + if (write_len != size) { + rc = -ENXIO; + goto out; + } + fflush(actx->f_out); + +out: + free(buf); + return rc; +} + +static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx, + int (*action)(struct cxl_memdev *memdev, struct action_context *actx), + const struct option *options, const char *usage) +{ + struct cxl_memdev *memdev, *single = NULL; + struct action_context actx = { 0 }; + int i, rc = 0, count = 0, err = 0; + const char * const u[] = { + usage, + NULL + }; + unsigned long id; + + argc = parse_options(argc, argv, options, u, 0); + + if (argc == 0) + usage_with_options(u, options); + for (i = 0; i < argc; i++) { + if (strcmp(argv[i], "all") == 0) { + argv[0] = "all"; + argc = 1; + break; + } + + if (sscanf(argv[i], "mem%lu", &id) != 1) { + fprintf(stderr, "'%s' is not a valid memdev name\n", + argv[i]); + err++; + } + } + + if (err == argc) { + usage_with_options(u, options); + return -EINVAL; + } + + if (!param.outfile) + actx.f_out = stdout; + else { + actx.f_out = fopen(param.outfile, "w+"); + if (!actx.f_out) { + fprintf(stderr, "failed to open: %s: (%s)\n", + param.outfile, strerror(errno)); + rc = -errno; + goto out; + } + } + + if (!param.infile) { + actx.f_in = stdin; + } else { + actx.f_in = fopen(param.infile, "r"); + if (!actx.f_in) { + fprintf(stderr, "failed to open: %s: (%s)\n", + param.infile, strerror(errno)); + rc = -errno; + goto out_close_fout; + } + } + + if (param.verbose) + cxl_set_log_priority(ctx, LOG_DEBUG); + + rc = 0; + err = 0; + count = 0; + + for (i = 0; i < argc; i++) { + if (sscanf(argv[i], "mem%lu", &id) != 1 + && strcmp(argv[i], "all") != 0) + continue; + + cxl_memdev_foreach (ctx, memdev) { + if (!util_cxl_memdev_filter(memdev, argv[i])) + continue; + + if (action == action_write) { + single = memdev; + rc = 0; + } else + rc = action(memdev, &actx); + + if (rc == 0) + count++; + else if (rc && !err) + err = rc; + } + } + rc = err; + + if (action == action_write) { + if (count > 1) { + error("write-labels only supports writing a single memdev\n"); + usage_with_options(u, options); + return -EINVAL; + } else if (single) { + rc = action(single, &actx); + if (rc) + count = 0; + } + } + + if (actx.f_in != stdin) + fclose(actx.f_in); + + out_close_fout: + if (actx.f_out != stdout) + fclose(actx.f_out); + + out: + /* + * count if some actions succeeded, 0 if none were attempted, + * negative error code otherwise. + */ + if (count > 0) + return count; + return rc; +} + +int cmd_write_labels(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int count = memdev_action(argc, argv, ctx, action_write, write_options, + "cxl write-labels <memdev> [-i <filename>]"); + + fprintf(stderr, "wrote %d mem%s\n", count >= 0 ? count : 0, + count > 1 ? "s" : ""); + return count >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_read_labels(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int count = memdev_action(argc, argv, ctx, action_read, read_options, + "cxl read-labels <mem0> [<mem1>..<memN>] [-o <filename>]"); + + fprintf(stderr, "read %d mem%s\n", count >= 0 ? count : 0, + count > 1 ? "s" : ""); + return count >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_zero_labels(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int count = memdev_action(argc, argv, ctx, action_zero, zero_options, + "cxl zero-labels <mem0> [<mem1>..<memN>] [<options>]"); + + fprintf(stderr, "zeroed %d mem%s\n", count >= 0 ? count : 0, + count > 1 ? "s" : ""); + return count >= 0 ? 0 : EXIT_FAILURE; +} diff --git a/Documentation/cxl/Makefile.am b/Documentation/cxl/Makefile.am index db98dd7..efabaa3 100644 --- a/Documentation/cxl/Makefile.am +++ b/Documentation/cxl/Makefile.am @@ -19,7 +19,10 @@ endif man1_MANS = \ cxl.1 \ - cxl-list.1 + cxl-list.1 \ + cxl-read-labels.1 \ + cxl-write-labels.1 \ + cxl-zero-labels.1 EXTRA_DIST = $(man1_MANS) diff --git a/cxl/Makefile.am b/cxl/Makefile.am index 98606b9..da9f91d 100644 --- a/cxl/Makefile.am +++ b/cxl/Makefile.am @@ -10,6 +10,7 @@ config.h: $(srcdir)/Makefile.am cxl_SOURCES =\ cxl.c \ list.c \ + memdev.c \ ../util/json.c \ builtin.h -- 2.31.1
next prev parent reply other threads:[~2021-10-07 8:22 UTC|newest] Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top 2021-10-07 8:21 [ndctl PATCH v4 00/17] Initial CXL support Vishal Verma 2021-10-07 8:21 ` [ndctl PATCH v4 01/17] ndctl: add .clang-format Vishal Verma 2021-10-07 8:21 ` [ndctl PATCH v4 02/17] cxl: add a cxl utility and libcxl library Vishal Verma 2021-10-07 8:21 ` [ndctl PATCH v4 03/17] cxl: add a local copy of the cxl_mem UAPI header Vishal Verma 2021-10-07 8:21 ` [ndctl PATCH v4 04/17] util: add the struct_size() helper from the kernel Vishal Verma 2021-10-14 2:40 ` Dan Williams 2021-10-07 8:21 ` [ndctl PATCH v4 05/17] libcxl: add support for command query and submission Vishal Verma 2021-10-14 2:53 ` Dan Williams 2021-10-07 8:21 ` [ndctl PATCH v4 06/17] libcxl: add support for the 'Identify Device' command Vishal Verma 2021-10-07 8:21 ` [ndctl PATCH v4 07/17] libcxl: add GET_HEALTH_INFO mailbox command and accessors Vishal Verma 2021-10-14 16:01 ` Dan Williams 2021-11-02 20:22 ` Verma, Vishal L 2021-11-02 20:27 ` Dan Williams 2021-10-07 8:21 ` [ndctl PATCH v4 08/17] libcxl: add support for the 'GET_LSA' command Vishal Verma 2021-10-14 16:35 ` Dan Williams 2021-10-14 20:06 ` Verma, Vishal L 2021-10-14 20:55 ` Dan Williams 2021-10-07 8:21 ` [ndctl PATCH v4 09/17] util/hexdump: Add a util helper to print a buffer in hex Vishal Verma 2021-10-14 16:48 ` Dan Williams 2021-10-14 20:33 ` Verma, Vishal L 2021-10-14 22:39 ` Dan Williams 2021-11-02 20:25 ` Verma, Vishal L 2021-10-07 8:21 ` [ndctl PATCH v4 10/17] libcxl: add label_size to cxl_memdev, and an API to retrieve it Vishal Verma 2021-10-14 18:24 ` Dan Williams 2021-10-14 21:50 ` Verma, Vishal L 2021-10-07 8:21 ` [ndctl PATCH v4 11/17] libcxl: add a stub interface to determine whether a memdev is active Vishal Verma 2021-10-14 19:59 ` Dan Williams 2021-10-07 8:21 ` [ndctl PATCH v4 12/17] libcxl: add interfaces for label operations Vishal Verma 2021-10-14 21:27 ` Dan Williams 2021-10-14 22:18 ` Verma, Vishal L 2021-10-14 22:24 ` Verma, Vishal L 2021-10-14 22:45 ` Dan Williams 2021-10-07 8:21 ` Vishal Verma [this message] 2021-10-14 22:34 ` [ndctl PATCH v4 13/17] cxl: add commands to read, write, and zero labels Dan Williams 2021-10-07 8:21 ` [ndctl PATCH v4 14/17] Documentation/cxl: add library API documentation Vishal Verma 2021-10-14 23:31 ` Dan Williams 2021-11-05 18:58 ` Dan Williams 2021-10-07 8:21 ` [ndctl PATCH v4 15/17] ndctl: Add CXL packages to the RPM spec Vishal Verma 2021-10-14 23:33 ` Dan Williams 2021-10-07 8:21 ` [ndctl PATCH v4 16/17] cxl-cli: add bash completion Vishal Verma 2021-10-14 23:34 ` Dan Williams 2021-10-07 8:21 ` [ndctl PATCH v4 17/17] cxl: add health information to cxl-list Vishal Verma 2021-10-11 22:07 ` Verma, Vishal L 2021-10-15 0:09 ` Dan Williams 2021-10-14 23:42 ` Verma, Vishal L 2021-10-15 21:15 ` Dan Williams
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=20211007082139.3088615-14-vishal.l.verma@intel.com \ --to=vishal.l.verma@intel.com \ --cc=ben.widawsky@intel.com \ --cc=dan.j.williams@intel.com \ --cc=linux-cxl@vger.kernel.org \ --cc=nvdimm@lists.linux.dev \ --subject='Re: [ndctl PATCH v4 13/17] cxl: add commands to read, write, and zero labels' \ /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
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).