diff mbox series

[2/2] cxl/memdev: Introduce sanitize-memdev functionality

Message ID 20230423015920.11384-3-dave@stgolabs.net
State Superseded
Headers show
Series cxl: Support memdev sanitation | expand

Commit Message

Davidlohr Bueso April 23, 2023, 1:59 a.m. UTC
Add a new cxl_memdev_sanitize() to libcxl to support triggering memory
device sanitation, in either Sanitize and/or Secure Erase, per the
CXL 3.0 specs.

This is analogous to 'ndctl sanitize-dimm'.

Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
---
 Documentation/cxl/cxl-sanitize-memdev.txt | 65 +++++++++++++++++++++++
 Documentation/cxl/cxl-wait-sanitize.txt   |  4 ++
 Documentation/cxl/lib/libcxl.txt          |  1 +
 Documentation/cxl/meson.build             |  1 +
 cxl/builtin.h                             |  1 +
 cxl/cxl.c                                 |  1 +
 cxl/lib/libcxl.c                          | 16 ++++++
 cxl/lib/libcxl.sym                        |  1 +
 cxl/libcxl.h                              |  1 +
 cxl/memdev.c                              | 47 ++++++++++++++++
 10 files changed, 138 insertions(+)
 create mode 100644 Documentation/cxl/cxl-sanitize-memdev.txt

Comments

Davidlohr Bueso April 25, 2023, 3:52 p.m. UTC | #1
On Sat, 22 Apr 2023, Davidlohr Bueso wrote:

>+int cxl_memdev_sanitize(struct cxl_memdev *memdev, const char *op)
>+{
>+	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
>+	char *path = memdev->dev_buf;
>+	int len = memdev->buf_len;
>+
>+	if (snprintf(path, len,
>+		     "%s/security/%s", memdev->host_path, op)  >= len) {

Bleh I forgot to update this (will do in an eventual v2), s/host_path/dev_path

Thanks,
Davidlohr
diff mbox series

Patch

diff --git a/Documentation/cxl/cxl-sanitize-memdev.txt b/Documentation/cxl/cxl-sanitize-memdev.txt
new file mode 100644
index 000000000000..194a9ad36778
--- /dev/null
+++ b/Documentation/cxl/cxl-sanitize-memdev.txt
@@ -0,0 +1,65 @@ 
+// SPDX-License-Identifier: GPL-2.0
+
+cxl-sanitize-memdev(1)
+======================
+
+NAME
+----
+cxl-sanitize-memdev - Perform a cryptographic destruction or sanitation of
+the contents of the given memdevs.
+
+SYNOPSIS
+--------
+[verse]
+'cxl sanitize-memdev' <mem0> [<mem1>..<memN>] [<options>]
+
+DESCRIPTION
+-----------
+The 'sanitize-memdev' command performs two different methods of
+sanitation, per the CXL 3.0 specification. It is required that
+the memdev be disabled before sanitizing, such that the device
+cannot be actively decoding any HPA ranges at the time.
+
+The default is 'sanitize', but additionally, a 'secure-erase'
+option is available. If both types of operations are supplied,
+then the 'secure-erase' is performed before 'sanitize'.
+
+
+OPTIONS
+-------
+<memdev>::
+include::memdev-option.txt[]
+
+-b::
+--bus=::
+include::bus-option.txt[]
+
+-e::
+--secure-erase::
+	Erase user data by changing the media encryption keys for all user
+	data areas of the device.
+
+-s::
+--sanitize::
+	Sanitize the device to securely re-purpose or decommission it. This is
+	done by ensuring that all user data and meta data, whether it resides
+	in persistent capacity, volatile capacity, or the label storage area,
+	is made permanently unavailable by whatever means is appropriate for
+	the media type.
+
+	With this option, the sanitation request is merely submitted to the
+	kernel, and the completion is asynchronous. Depending on the medium and
+	capacity, sanitize may take tens of minutes to many hours. Subsequently,
+	'cxl wait-sanitize’ can be used to wait for the memdevs that are under
+	the sanitation.
+
+-v::
+--verbose::
+	Emit debug messages.
+
+include::../copyright.txt[]
+
+SEE ALSO
+--------
+linkcxl:cxl-wait-sanitize[1]
+linkcxl:cxl-disable-memdev[1]
diff --git a/Documentation/cxl/cxl-wait-sanitize.txt b/Documentation/cxl/cxl-wait-sanitize.txt
index c2ceae7ade0e..7e56c5a3a0ca 100644
--- a/Documentation/cxl/cxl-wait-sanitize.txt
+++ b/Documentation/cxl/cxl-wait-sanitize.txt
@@ -33,3 +33,7 @@  include::bus-option.txt[]
 	Emit debug messages.
 
 include::../copyright.txt[]
+
+SEE ALSO
+--------
+linkcxl:cxl-sanitize-memdev[1]
diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt
index 9d98865e172c..0aae0537aec8 100644
--- a/Documentation/cxl/lib/libcxl.txt
+++ b/Documentation/cxl/lib/libcxl.txt
@@ -136,6 +136,7 @@  struct cxl_cmd *cxl_cmd_new_get_partition(struct cxl_memdev *memdev);
 struct cxl_cmd *cxl_cmd_new_set_partition(struct cxl_memdev *memdev,
 					  unsigned long long volatile_size);
 int cxl_memdev_wait_sanitize(struct cxl_memdev *memdev);
+int cxl_memdev_sanitize(struct cxl_memdev *memdev, const char *op);
 
 ----
 
diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build
index ebf214ae30df..ba4e4077c09c 100644
--- a/Documentation/cxl/meson.build
+++ b/Documentation/cxl/meson.build
@@ -46,6 +46,7 @@  cxl_manpages = [
   'cxl-enable-region.txt',
   'cxl-destroy-region.txt',
   'cxl-wait-sanitize.txt',
+  'cxl-sanitize-memdev.txt',
   'cxl-monitor.txt',
 ]
 
diff --git a/cxl/builtin.h b/cxl/builtin.h
index 04f613703eac..956a773ffd0e 100644
--- a/cxl/builtin.h
+++ b/cxl/builtin.h
@@ -23,6 +23,7 @@  int cmd_enable_region(int argc, const char **argv, struct cxl_ctx *ctx);
 int cmd_disable_region(int argc, const char **argv, struct cxl_ctx *ctx);
 int cmd_destroy_region(int argc, const char **argv, struct cxl_ctx *ctx);
 int cmd_wait_sanitize(int argc, const char **argv, struct cxl_ctx *ctx);
+int cmd_sanitize_memdev(int argc, const char **argv, struct cxl_ctx *ctx);
 #ifdef ENABLE_LIBTRACEFS
 int cmd_monitor(int argc, const char **argv, struct cxl_ctx *ctx);
 #else
diff --git a/cxl/cxl.c b/cxl/cxl.c
index bf55e8bcb2f7..4520162ae4fc 100644
--- a/cxl/cxl.c
+++ b/cxl/cxl.c
@@ -77,6 +77,7 @@  static struct cmd_struct commands[] = {
 	{ "disable-region", .c_fn = cmd_disable_region },
 	{ "destroy-region", .c_fn = cmd_destroy_region },
 	{ "wait-sanitize", .c_fn = cmd_wait_sanitize },
+	{ "sanitize-memdev", .c_fn = cmd_sanitize_memdev },
 	{ "monitor", .c_fn = cmd_monitor },
 };
 
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index f369f45271d5..129d452ad989 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -3929,6 +3929,22 @@  CXL_EXPORT int cxl_memdev_wait_sanitize(struct cxl_memdev *memdev)
 	return rc;
 }
 
+int cxl_memdev_sanitize(struct cxl_memdev *memdev, const char *op)
+{
+	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+	char *path = memdev->dev_buf;
+	int len = memdev->buf_len;
+
+	if (snprintf(path, len,
+		     "%s/security/%s", memdev->host_path, op)  >= len) {
+		err(ctx, "%s: buffer too small!\n",
+		    cxl_memdev_get_devname(memdev));
+		return -ERANGE;
+	}
+
+	return sysfs_write_attr(ctx, path, "1");
+}
+
 CXL_EXPORT int cxl_cmd_submit(struct cxl_cmd *cmd)
 {
 	struct cxl_memdev *memdev = cmd->memdev;
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index bf7d38f7e6fe..2b8b47fb89e5 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -71,6 +71,7 @@  global:
 	cxl_memdev_write_label;
 	cxl_memdev_read_label;
 	cxl_memdev_wait_sanitize;
+	cxl_memdev_sanitize;
 local:
         *;
 };
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index c9c935126d4a..4f105a0bb3d9 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -413,6 +413,7 @@  unsigned long long cxl_cmd_partition_get_next_persistent_size(struct cxl_cmd *cm
 struct cxl_cmd *cxl_cmd_new_set_partition(struct cxl_memdev *memdev,
 		unsigned long long volatile_size);
 int cxl_memdev_wait_sanitize(struct cxl_memdev *memdev);
+int cxl_memdev_sanitize(struct cxl_memdev *memdev, const char *op);
 
 enum cxl_setpartition_mode {
 	CXL_SETPART_NEXTBOOT,
diff --git a/cxl/memdev.c b/cxl/memdev.c
index 4fc787ffe1e6..e45dd7fc540f 100644
--- a/cxl/memdev.c
+++ b/cxl/memdev.c
@@ -31,6 +31,8 @@  static struct parameters {
 	bool serial;
 	bool force;
 	bool align;
+	bool sanitize;
+	bool secure_erase;
 	const char *type;
 	const char *size;
 	const char *decoder_filter;
@@ -85,6 +87,12 @@  OPT_STRING('t', "type", &param.type, "type",                   \
 OPT_BOOLEAN('f', "force", &param.force,                        \
 	    "Attempt 'expected to fail' operations")
 
+#define SANITIZE_OPTIONS()			      \
+OPT_BOOLEAN('e', "secure-erase", &param.secure_erase, \
+	    "secure erase a memdev"),		      \
+OPT_BOOLEAN('s', "sanitize", &param.sanitize,	      \
+	    "sanitize a memdev")
+
 static const struct option read_options[] = {
 	BASE_OPTIONS(),
 	LABEL_OPTIONS(),
@@ -140,6 +148,12 @@  static const struct option wait_sanitize_options[] = {
 	OPT_END(),
 };
 
+static const struct option sanitize_options[] = {
+	BASE_OPTIONS(),
+	SANITIZE_OPTIONS(),
+	OPT_END(),
+};
+
 enum reserve_dpa_mode {
 	DPA_ALLOC,
 	DPA_FREE,
@@ -668,6 +682,28 @@  static int action_wait_sanitize(struct cxl_memdev *memdev,
 	return cxl_memdev_wait_sanitize(memdev);
 }
 
+static int action_sanitize_memdev(struct cxl_memdev *memdev,
+				  struct action_context *actx)
+{
+	int rc = 0;
+
+	if (cxl_memdev_is_enabled(memdev))
+		return -EBUSY;
+
+	/* let Sanitize be the default */
+	if (!param.secure_erase && !param.sanitize)
+		param.sanitize = true;
+
+	if (param.secure_erase)
+		rc = cxl_memdev_sanitize(memdev, "erase");
+	if (param.sanitize)
+		rc = cxl_memdev_sanitize(memdev, "sanitize");
+	else
+		rc = -EINVAL;
+
+	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),
@@ -919,3 +955,14 @@  int cmd_wait_sanitize(int argc, const char **argv, struct cxl_ctx *ctx)
 
 	return count >= 0 ? 0 : EXIT_FAILURE;
 }
+
+int cmd_sanitize_memdev(int argc, const char **argv, struct cxl_ctx *ctx)
+{
+	int count = memdev_action(argc, argv, ctx, action_sanitize_memdev,
+		sanitize_options,
+		"cxl sanitize-memdev <mem0> [<mem1>..<memn>] [<options>]");
+	log_info(&ml, "sanitation started on %d mem device%s\n",
+		 count >= 0 ? count : 0, count > 1 ? "s" : "");
+
+	return count >= 0 ? 0 : EXIT_FAILURE;
+}