nvdimm.lists.linux.dev archive mirror
 help / color / mirror / Atom feed
* [ndctl PATCH 0/4] Error injection reworks
@ 2018-05-01 18:00 Vishal Verma
  2018-05-01 18:00 ` [ndctl PATCH 1/4] libndctl, ars: add an API to retrieve clear_err_unit Vishal Verma
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Vishal Verma @ 2018-05-01 18:00 UTC (permalink / raw)
  To: linux-nvdimm

Updates to the error injection facilities in libndctl and ndctl that:
1. Inject fewer bytes per injected block:
  It is sufficient to inject even a single byte (cache line) for Linux
  to mark the entire block as a badblock. Reduce the number of injected
  bytes per block to the unit reported by clear_err_unit

2. Provide a --saturate option:
  If the old behavior of injecting the whole block for every block is
  desired, provide a --saturate option to get that.


Vishal Verma (4):
  libndctl, ars: add an API to retrieve clear_err_unit
  libndctl, inject: inject fewer bytes per block by default
  libndctl, inject: add 'v2' APIs for inject and uninject
  ndctl, inject-error: add a --saturate option

 Documentation/ndctl/ndctl-inject-error.txt |  14 ++
 ndctl/inject-error.c                       |  40 +++---
 ndctl/lib/ars.c                            |  15 +++
 ndctl/lib/inject.c                         | 201 ++++++++++++++++++++++-------
 ndctl/lib/libndctl.sym                     |   7 +
 ndctl/libndctl.h                           |  11 ++
 6 files changed, 222 insertions(+), 66 deletions(-)

-- 
2.14.3

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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [ndctl PATCH 1/4] libndctl, ars: add an API to retrieve clear_err_unit
  2018-05-01 18:00 [ndctl PATCH 0/4] Error injection reworks Vishal Verma
@ 2018-05-01 18:00 ` Vishal Verma
  2018-05-01 18:00 ` [ndctl PATCH 2/4] libndctl, inject: inject fewer bytes per block by default Vishal Verma
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Vishal Verma @ 2018-05-01 18:00 UTC (permalink / raw)
  To: linux-nvdimm

The ars_cap command contains a field called clear_err_unit which is the
unit in which internal ARS related operations are carried out. In
preparation for the error injection reworks, provide an API to expose
this value to users.

Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 ndctl/lib/ars.c        | 15 +++++++++++++++
 ndctl/lib/libndctl.sym |  5 +++++
 ndctl/libndctl.h       |  1 +
 3 files changed, 21 insertions(+)

diff --git a/ndctl/lib/ars.c b/ndctl/lib/ars.c
index d53d898..1ff6cf7 100644
--- a/ndctl/lib/ars.c
+++ b/ndctl/lib/ars.c
@@ -180,6 +180,21 @@ NDCTL_EXPORT int ndctl_cmd_ars_cap_get_range(struct ndctl_cmd *ars_cap,
 	return -EINVAL;
 }
 
+NDCTL_EXPORT unsigned int ndctl_cmd_ars_cap_get_clear_unit(
+		struct ndctl_cmd *ars_cap)
+{
+	struct ndctl_ctx *ctx = ndctl_bus_get_ctx(cmd_to_bus(ars_cap));
+
+	if (ars_cap->type == ND_CMD_ARS_CAP && ars_cap->status == 0) {
+		dbg(ctx, "clear_err_unit: %d\n",
+			ars_cap->ars_cap->clear_err_unit);
+		return ars_cap->ars_cap->clear_err_unit;
+	}
+
+	dbg(ctx, "invalid ars_cap\n");
+	return 0;
+}
+
 NDCTL_EXPORT int ndctl_cmd_ars_in_progress(struct ndctl_cmd *cmd)
 {
 	struct ndctl_ctx *ctx = ndctl_bus_get_ctx(cmd_to_bus(cmd));
diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym
index 65e735f..92822be 100644
--- a/ndctl/lib/libndctl.sym
+++ b/ndctl/lib/libndctl.sym
@@ -359,3 +359,8 @@ global:
 	ndctl_bus_start_scrub;
 	ndctl_region_deep_flush;
 } LIBNDCTL_14;
+
+LIBNDCTL_16 {
+global:
+	ndctl_cmd_ars_cap_get_clear_unit;
+} LIBNDCTL_15;
diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h
index 498ae19..74fe0f4 100644
--- a/ndctl/libndctl.h
+++ b/ndctl/libndctl.h
@@ -209,6 +209,7 @@ struct ndctl_cmd *ndctl_bus_cmd_new_clear_error(unsigned long long address,
 		unsigned long long len, struct ndctl_cmd *ars_cap);
 unsigned long long ndctl_cmd_clear_error_get_cleared(
 		struct ndctl_cmd *clear_err);
+unsigned int ndctl_cmd_ars_cap_get_clear_unit(struct ndctl_cmd *ars_cap);
 
 /*
  * Note: ndctl_cmd_smart_get_temperature is an alias for
-- 
2.14.3

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

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [ndctl PATCH 2/4] libndctl, inject: inject fewer bytes per block by default
  2018-05-01 18:00 [ndctl PATCH 0/4] Error injection reworks Vishal Verma
  2018-05-01 18:00 ` [ndctl PATCH 1/4] libndctl, ars: add an API to retrieve clear_err_unit Vishal Verma
@ 2018-05-01 18:00 ` Vishal Verma
  2018-05-01 18:00 ` [ndctl PATCH 3/4] libndctl, inject: add 'v2' APIs for inject and uninject Vishal Verma
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Vishal Verma @ 2018-05-01 18:00 UTC (permalink / raw)
  To: linux-nvdimm

Theoretically a single poisoned byte per block is enough for Linux to
mark it as a badblock. For each block, instead of injecting a range
covering the entire badblock, reduce it to clear_err_unit bytes, which
is obtained from an ars_cap command. If multiple blocks are being
injected, inject the above number of bytes at the start of each block
separately. Make the same changes for uninject as well.

Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 Documentation/ndctl/ndctl-inject-error.txt |   7 ++
 ndctl/lib/inject.c                         | 181 +++++++++++++++++++++--------
 2 files changed, 138 insertions(+), 50 deletions(-)

diff --git a/Documentation/ndctl/ndctl-inject-error.txt b/Documentation/ndctl/ndctl-inject-error.txt
index 94c4e69..07c992a 100644
--- a/Documentation/ndctl/ndctl-inject-error.txt
+++ b/Documentation/ndctl/ndctl-inject-error.txt
@@ -18,6 +18,13 @@ ndctl-inject-error can be used to ask the platform to simulate media errors
 in the NVDIMM address space to aid debugging and development of features
 related to error handling.
 
+By default, injecting an error actually only injects an error to the first 'n'
+bytes of the block, where 'n' is the output of ndctl_cmd_ars_cap_get_size().
+In other words, we only inject one 'ars_unit' per sector. This is sufficient
+for Linux to mark the whole sector as bad, and will show up as such in the
+various 'badblocks' lists in the kernel. If multiple blocks are being injected,
+only the first 'n' bytes of each block specified will be injected as errors.
+
 WARNING: These commands are DANGEROUS and can cause data loss. They are
 only provided for testing and debugging purposes.
 
diff --git a/ndctl/lib/inject.c b/ndctl/lib/inject.c
index 8bfb5c9..2865a7d 100644
--- a/ndctl/lib/inject.c
+++ b/ndctl/lib/inject.c
@@ -89,86 +89,167 @@ static int translate_status(u32 status)
 	return 0;
 }
 
-NDCTL_EXPORT int ndctl_namespace_inject_error(struct ndctl_namespace *ndns,
-		unsigned long long block, unsigned long long count, bool notify)
+static int ndctl_namespace_get_clear_unit(struct ndctl_namespace *ndns)
+{
+	struct ndctl_bus *bus = ndctl_namespace_get_bus(ndns);
+	struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
+	unsigned long long ns_offset, ns_size;
+	unsigned int clear_unit;
+	struct ndctl_cmd *cmd;
+	int rc;
+
+	ndctl_namespace_get_injection_bounds(ndns, &ns_offset,
+		&ns_size);
+	cmd = ndctl_bus_cmd_new_ars_cap(bus, ns_offset, ns_size);
+	rc = ndctl_cmd_submit(cmd);
+	if (rc) {
+		dbg(ctx, "Error submitting ars_cap: %d\n", rc);
+		return rc;
+	}
+	clear_unit = ndctl_cmd_ars_cap_get_clear_unit(cmd);
+	if (clear_unit == 0) {
+		dbg(ctx, "Got an invalid clear_err_unit from ars_cap\n");
+		return -EINVAL;
+	}
+
+	ndctl_cmd_unref(cmd);
+	return clear_unit;
+}
+
+static int ndctl_namespace_inject_one_error(struct ndctl_namespace *ndns,
+		unsigned long long block, bool notify)
 {
 	struct ndctl_bus *bus = ndctl_namespace_get_bus(ndns);
 	struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
 	struct nd_cmd_ars_err_inj *err_inj;
 	struct nd_cmd_pkg *pkg;
 	struct ndctl_cmd *cmd;
-	int rc = -EOPNOTSUPP;
+	u64 offset, length;
+	int rc, clear_unit;
 
-	if (!ndctl_bus_has_error_injection(bus))
-		return -EOPNOTSUPP;
+	rc = block_to_spa_offset(ndns, block, 1, &offset, &length);
+	if (rc)
+		return rc;
 
-	if (ndctl_bus_has_nfit(bus)) {
-		u64 offset, length;
+	clear_unit = ndctl_namespace_get_clear_unit(ndns);
+	if (clear_unit < 0)
+		return clear_unit;
 
-		rc = block_to_spa_offset(ndns, block, count, &offset, &length);
-		if (rc)
-			return rc;
-		cmd = ndctl_bus_cmd_new_err_inj(bus);
-		if (!cmd)
-			return -ENOMEM;
+	/* clamp injection length per block to the clear_unit */
+	if (length > (unsigned int)clear_unit)
+		length = clear_unit;
 
-		pkg = (struct nd_cmd_pkg *)&cmd->cmd_buf[0];
-		err_inj = (struct nd_cmd_ars_err_inj *)&pkg->nd_payload[0];
-		err_inj->err_inj_spa_range_base = offset;
-		err_inj->err_inj_spa_range_length = length;
-		if (notify)
-			err_inj->err_inj_options |=
-				(1 << ND_ARS_ERR_INJ_OPT_NOTIFY);
+	cmd = ndctl_bus_cmd_new_err_inj(bus);
+	if (!cmd)
+		return -ENOMEM;
 
-		rc = ndctl_cmd_submit(cmd);
+	pkg = (struct nd_cmd_pkg *)&cmd->cmd_buf[0];
+	err_inj = (struct nd_cmd_ars_err_inj *)&pkg->nd_payload[0];
+	err_inj->err_inj_spa_range_base = offset;
+	err_inj->err_inj_spa_range_length = length;
+	if (notify)
+		err_inj->err_inj_options |=
+			(1 << ND_ARS_ERR_INJ_OPT_NOTIFY);
+
+	rc = ndctl_cmd_submit(cmd);
+	if (rc) {
+		dbg(ctx, "Error submitting command: %d\n", rc);
+		goto out;
+	}
+	rc = translate_status(err_inj->status);
+ out:
+	ndctl_cmd_unref(cmd);
+	return rc;
+}
+
+NDCTL_EXPORT int ndctl_namespace_inject_error(struct ndctl_namespace *ndns,
+		unsigned long long block, unsigned long long count, bool notify)
+{
+	struct ndctl_bus *bus = ndctl_namespace_get_bus(ndns);
+	struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
+	unsigned long long i;
+	int rc = -EINVAL;
+
+	if (!ndctl_bus_has_error_injection(bus))
+		return -EOPNOTSUPP;
+	if (!ndctl_bus_has_nfit(bus))
+		return -EOPNOTSUPP;
+
+	for (i = 0; i < count; i++) {
+		rc = ndctl_namespace_inject_one_error(ndns, block + i, notify);
 		if (rc) {
-			dbg(ctx, "Error submitting command: %d\n", rc);
-			goto out;
+			err(ctx, "Injection failed at block %llx\n",
+				block + i);
+			return rc;
 		}
-		rc = translate_status(err_inj->status);
- out:
-		ndctl_cmd_unref(cmd);
 	}
 	return rc;
 }
 
-NDCTL_EXPORT int ndctl_namespace_uninject_error(struct ndctl_namespace *ndns,
-		unsigned long long block, unsigned long long count)
+static int ndctl_namespace_uninject_one_error(struct ndctl_namespace *ndns,
+		unsigned long long block)
 {
 	struct ndctl_bus *bus = ndctl_namespace_get_bus(ndns);
 	struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
 	struct nd_cmd_ars_err_inj_clr *err_inj_clr;
 	struct nd_cmd_pkg *pkg;
 	struct ndctl_cmd *cmd;
-	int rc = -EOPNOTSUPP;
+	u64 offset, length;
+	int rc, clear_unit;
 
-	if (!ndctl_bus_has_error_injection(bus))
-		return -EOPNOTSUPP;
+	rc = block_to_spa_offset(ndns, block, 1, &offset, &length);
+	if (rc)
+		return rc;
 
-	if (ndctl_bus_has_nfit(bus)) {
-		u64 offset, length;
+	clear_unit = ndctl_namespace_get_clear_unit(ndns);
+	if (clear_unit < 0)
+		return clear_unit;
 
-		rc = block_to_spa_offset(ndns, block, count, &offset, &length);
-		if (rc)
-			return rc;
-		cmd = ndctl_bus_cmd_new_err_inj_clr(bus);
-		if (!cmd)
-			return -ENOMEM;
+	/* clamp injection length per block to the clear_unit */
+	if (length > (unsigned int)clear_unit)
+		length = clear_unit;
 
-		pkg = (struct nd_cmd_pkg *)&cmd->cmd_buf[0];
-		err_inj_clr =
-			(struct nd_cmd_ars_err_inj_clr *)&pkg->nd_payload[0];
-		err_inj_clr->err_inj_clr_spa_range_base = offset;
-		err_inj_clr->err_inj_clr_spa_range_length = length;
+	cmd = ndctl_bus_cmd_new_err_inj_clr(bus);
+	if (!cmd)
+		return -ENOMEM;
 
-		rc = ndctl_cmd_submit(cmd);
+	pkg = (struct nd_cmd_pkg *)&cmd->cmd_buf[0];
+	err_inj_clr =
+		(struct nd_cmd_ars_err_inj_clr *)&pkg->nd_payload[0];
+	err_inj_clr->err_inj_clr_spa_range_base = offset;
+	err_inj_clr->err_inj_clr_spa_range_length = length;
+
+	rc = ndctl_cmd_submit(cmd);
+	if (rc) {
+		dbg(ctx, "Error submitting command: %d\n", rc);
+		goto out;
+	}
+	rc = translate_status(err_inj_clr->status);
+ out:
+	ndctl_cmd_unref(cmd);
+	return rc;
+}
+
+NDCTL_EXPORT int ndctl_namespace_uninject_error(struct ndctl_namespace *ndns,
+		unsigned long long block, unsigned long long count)
+{
+	struct ndctl_bus *bus = ndctl_namespace_get_bus(ndns);
+	struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
+	unsigned long long i;
+	int rc = -EINVAL;
+
+	if (!ndctl_bus_has_error_injection(bus))
+		return -EOPNOTSUPP;
+	if (!ndctl_bus_has_nfit(bus))
+		return -EOPNOTSUPP;
+
+	for (i = 0; i < count; i++) {
+		rc = ndctl_namespace_uninject_one_error(ndns, block + i);
 		if (rc) {
-			dbg(ctx, "Error submitting command: %d\n", rc);
-			goto out;
+			err(ctx, "Un-injection failed at block %llx\n",
+				block + i);
+			return rc;
 		}
-		rc = translate_status(err_inj_clr->status);
- out:
-		ndctl_cmd_unref(cmd);
 	}
 	return rc;
 }
-- 
2.14.3

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

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [ndctl PATCH 3/4] libndctl, inject: add 'v2' APIs for inject and uninject
  2018-05-01 18:00 [ndctl PATCH 0/4] Error injection reworks Vishal Verma
  2018-05-01 18:00 ` [ndctl PATCH 1/4] libndctl, ars: add an API to retrieve clear_err_unit Vishal Verma
  2018-05-01 18:00 ` [ndctl PATCH 2/4] libndctl, inject: inject fewer bytes per block by default Vishal Verma
@ 2018-05-01 18:00 ` Vishal Verma
  2018-05-01 18:00 ` [ndctl PATCH 4/4] ndctl, inject-error: add a --saturate option Vishal Verma
  2018-05-01 19:54 ` [ndctl PATCH 0/4] Error injection reworks Dave Jiang
  4 siblings, 0 replies; 6+ messages in thread
From: Vishal Verma @ 2018-05-01 18:00 UTC (permalink / raw)
  To: linux-nvdimm

In preparation for adding a saturate option, add two new APIs:

	ndctl_namespace_inject_error2
	ndctl_namespace_uninject_error2

The old APIs included a flag, such as 'notify' as an explicit part of
the API, thus limiting new flags/options. In hindsight, this was a
mistake, and should have been a flags field. Introduce the new v2 APIs
for injection and un-injection that fix this, and have a flags field.

Convert the users of the old API, i.e. ndctl/inject-error.c, to the new
API, and treat 'notify' as a flag everywhere.

Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 ndctl/inject-error.c   | 33 ++++++++++++++++++---------------
 ndctl/lib/inject.c     | 34 +++++++++++++++++++++++++---------
 ndctl/lib/libndctl.sym |  2 ++
 ndctl/libndctl.h       |  9 +++++++++
 4 files changed, 54 insertions(+), 24 deletions(-)

diff --git a/ndctl/inject-error.c b/ndctl/inject-error.c
index 32a58a5..e977136 100644
--- a/ndctl/inject-error.c
+++ b/ndctl/inject-error.c
@@ -54,8 +54,8 @@ static struct inject_ctx {
 	u64 block;
 	u64 count;
 	unsigned int op_mask;
-	unsigned long flags;
-	bool notify;
+	unsigned long json_flags;
+	unsigned int inject_flags;
 } ictx;
 
 #define BASE_OPTIONS() \
@@ -92,9 +92,9 @@ static int inject_init(void)
 {
 	if (!param.clear && !param.status) {
 		ictx.op_mask |= 1 << OP_INJECT;
-		ictx.notify = true;
+		ictx.inject_flags |= (1 << NDCTL_NS_INJECT_NOTIFY);
 		if (param.no_notify)
-			ictx.notify = false;
+			ictx.inject_flags &= ~(1 << NDCTL_NS_INJECT_NOTIFY);
 	}
 	if (param.clear) {
 		if (param.status) {
@@ -144,7 +144,7 @@ static int inject_init(void)
 	}
 
 	if (param.human)
-		ictx.flags |= UTIL_JSON_HUMAN;
+		ictx.json_flags |= UTIL_JSON_HUMAN;
 
 	return 0;
 }
@@ -152,14 +152,15 @@ static int inject_init(void)
 static int ns_errors_to_json(struct ndctl_namespace *ndns,
 		unsigned int start_count)
 {
-	unsigned long flags = ictx.flags | UTIL_JSON_MEDIA_ERRORS;
+	unsigned long json_flags = ictx.json_flags | UTIL_JSON_MEDIA_ERRORS;
 	struct ndctl_bus *bus = ndctl_namespace_get_bus(ndns);
 	struct json_object *jndns;
 	unsigned int count;
 	int rc, tmo = 30;
 
 	/* only wait for scrubs for the inject and notify case */
-	if ((ictx.op_mask & (1 << OP_INJECT)) && ictx.notify) {
+	if ((ictx.op_mask & (1 << OP_INJECT)) &&
+			(ictx.inject_flags & (1 << NDCTL_NS_INJECT_NOTIFY))) {
 		do {
 			/* wait for a scrub to start */
 			count = ndctl_bus_get_scrub_count(bus);
@@ -177,7 +178,7 @@ static int ns_errors_to_json(struct ndctl_namespace *ndns,
 		}
 	}
 
-	jndns = util_namespace_to_json(ndns, flags);
+	jndns = util_namespace_to_json(ndns, json_flags);
 	if (jndns)
 		printf("%s\n", json_object_to_json_string_ext(jndns,
 				JSON_C_TO_STRING_PRETTY));
@@ -185,7 +186,7 @@ static int ns_errors_to_json(struct ndctl_namespace *ndns,
 }
 
 static int inject_error(struct ndctl_namespace *ndns, u64 offset, u64 length,
-		bool notify)
+		unsigned int flags)
 {
 	struct ndctl_bus *bus = ndctl_namespace_get_bus(ndns);
 	unsigned int scrub_count;
@@ -197,7 +198,7 @@ static int inject_error(struct ndctl_namespace *ndns, u64 offset, u64 length,
 		return -ENXIO;
 	}
 
-	rc = ndctl_namespace_inject_error(ndns, offset, length, notify);
+	rc = ndctl_namespace_inject_error2(ndns, offset, length, flags);
 	if (rc) {
 		fprintf(stderr, "Unable to inject error: %s (%d)\n",
 			strerror(abs(rc)), rc);
@@ -207,11 +208,12 @@ static int inject_error(struct ndctl_namespace *ndns, u64 offset, u64 length,
 	return ns_errors_to_json(ndns, scrub_count);
 }
 
-static int uninject_error(struct ndctl_namespace *ndns, u64 offset, u64 length)
+static int uninject_error(struct ndctl_namespace *ndns, u64 offset, u64 length,
+		unsigned int flags)
 {
 	int rc;
 
-	rc = ndctl_namespace_uninject_error(ndns, offset, length);
+	rc = ndctl_namespace_uninject_error2(ndns, offset, length, flags);
 	if (rc) {
 		fprintf(stderr, "Unable to uninject error: %s (%d)\n",
 			strerror(abs(rc)), rc);
@@ -254,7 +256,7 @@ static int injection_status(struct ndctl_namespace *ndns)
 
 		block = ndctl_bb_get_block(bb);
 		count = ndctl_bb_get_count(bb);
-		jbb = util_badblock_rec_to_json(block, count, ictx.flags);
+		jbb = util_badblock_rec_to_json(block, count, ictx.json_flags);
 		if (!jbb)
 			break;
 		json_object_array_add(jbbs, jbb);
@@ -280,13 +282,14 @@ static int err_inject_ns(struct ndctl_namespace *ndns)
 	while (op_mask) {
 		if (op_mask & (1 << OP_INJECT)) {
 			rc = inject_error(ndns, ictx.block, ictx.count,
-				ictx.notify);
+				ictx.inject_flags);
 			if (rc)
 				return rc;
 			op_mask &= ~(1 << OP_INJECT);
 		}
 		if (op_mask & (1 << OP_CLEAR)) {
-			rc = uninject_error(ndns, ictx.block, ictx.count);
+			rc = uninject_error(ndns, ictx.block, ictx.count,
+				ictx.inject_flags);
 			if (rc)
 				return rc;
 			op_mask &= ~(1 << OP_CLEAR);
diff --git a/ndctl/lib/inject.c b/ndctl/lib/inject.c
index 2865a7d..5cffe53 100644
--- a/ndctl/lib/inject.c
+++ b/ndctl/lib/inject.c
@@ -117,7 +117,7 @@ static int ndctl_namespace_get_clear_unit(struct ndctl_namespace *ndns)
 }
 
 static int ndctl_namespace_inject_one_error(struct ndctl_namespace *ndns,
-		unsigned long long block, bool notify)
+		unsigned long long block, unsigned int flags)
 {
 	struct ndctl_bus *bus = ndctl_namespace_get_bus(ndns);
 	struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
@@ -147,7 +147,7 @@ static int ndctl_namespace_inject_one_error(struct ndctl_namespace *ndns,
 	err_inj = (struct nd_cmd_ars_err_inj *)&pkg->nd_payload[0];
 	err_inj->err_inj_spa_range_base = offset;
 	err_inj->err_inj_spa_range_length = length;
-	if (notify)
+	if (flags & (1 << NDCTL_NS_INJECT_NOTIFY))
 		err_inj->err_inj_options |=
 			(1 << ND_ARS_ERR_INJ_OPT_NOTIFY);
 
@@ -162,8 +162,9 @@ static int ndctl_namespace_inject_one_error(struct ndctl_namespace *ndns,
 	return rc;
 }
 
-NDCTL_EXPORT int ndctl_namespace_inject_error(struct ndctl_namespace *ndns,
-		unsigned long long block, unsigned long long count, bool notify)
+NDCTL_EXPORT int ndctl_namespace_inject_error2(struct ndctl_namespace *ndns,
+		unsigned long long block, unsigned long long count,
+		unsigned int flags)
 {
 	struct ndctl_bus *bus = ndctl_namespace_get_bus(ndns);
 	struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
@@ -176,7 +177,7 @@ NDCTL_EXPORT int ndctl_namespace_inject_error(struct ndctl_namespace *ndns,
 		return -EOPNOTSUPP;
 
 	for (i = 0; i < count; i++) {
-		rc = ndctl_namespace_inject_one_error(ndns, block + i, notify);
+		rc = ndctl_namespace_inject_one_error(ndns, block + i, flags);
 		if (rc) {
 			err(ctx, "Injection failed at block %llx\n",
 				block + i);
@@ -186,8 +187,15 @@ NDCTL_EXPORT int ndctl_namespace_inject_error(struct ndctl_namespace *ndns,
 	return rc;
 }
 
+NDCTL_EXPORT int ndctl_namespace_inject_error(struct ndctl_namespace *ndns,
+		unsigned long long block, unsigned long long count, bool notify)
+{
+	return ndctl_namespace_inject_error2(ndns, block, count,
+		notify ? (1 << NDCTL_NS_INJECT_NOTIFY) : 0);
+}
+
 static int ndctl_namespace_uninject_one_error(struct ndctl_namespace *ndns,
-		unsigned long long block)
+		unsigned long long block, unsigned int flags)
 {
 	struct ndctl_bus *bus = ndctl_namespace_get_bus(ndns);
 	struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
@@ -230,8 +238,9 @@ static int ndctl_namespace_uninject_one_error(struct ndctl_namespace *ndns,
 	return rc;
 }
 
-NDCTL_EXPORT int ndctl_namespace_uninject_error(struct ndctl_namespace *ndns,
-		unsigned long long block, unsigned long long count)
+NDCTL_EXPORT int ndctl_namespace_uninject_error2(struct ndctl_namespace *ndns,
+		unsigned long long block, unsigned long long count,
+		unsigned int flags)
 {
 	struct ndctl_bus *bus = ndctl_namespace_get_bus(ndns);
 	struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
@@ -244,7 +253,8 @@ NDCTL_EXPORT int ndctl_namespace_uninject_error(struct ndctl_namespace *ndns,
 		return -EOPNOTSUPP;
 
 	for (i = 0; i < count; i++) {
-		rc = ndctl_namespace_uninject_one_error(ndns, block + i);
+		rc = ndctl_namespace_uninject_one_error(ndns, block + i,
+			flags);
 		if (rc) {
 			err(ctx, "Un-injection failed at block %llx\n",
 				block + i);
@@ -254,6 +264,12 @@ NDCTL_EXPORT int ndctl_namespace_uninject_error(struct ndctl_namespace *ndns,
 	return rc;
 }
 
+NDCTL_EXPORT int ndctl_namespace_uninject_error(struct ndctl_namespace *ndns,
+		unsigned long long block, unsigned long long count)
+{
+	return ndctl_namespace_inject_error2(ndns, block, count, 0);
+}
+
 static int bb_add_record(struct list_head *h, u64 block, u64 count)
 {
 	struct ndctl_bb *bb, *bb_iter, *bb_next, *bb_prev;
diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym
index 92822be..c1228e5 100644
--- a/ndctl/lib/libndctl.sym
+++ b/ndctl/lib/libndctl.sym
@@ -363,4 +363,6 @@ global:
 LIBNDCTL_16 {
 global:
 	ndctl_cmd_ars_cap_get_clear_unit;
+	ndctl_namespace_inject_error2;
+	ndctl_namespace_uninject_error2;
 } LIBNDCTL_15;
diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h
index 74fe0f4..a001271 100644
--- a/ndctl/libndctl.h
+++ b/ndctl/libndctl.h
@@ -479,9 +479,18 @@ int ndctl_namespace_get_numa_node(struct ndctl_namespace *ndns);
 int ndctl_namespace_inject_error(struct ndctl_namespace *ndns,
 		unsigned long long block, unsigned long long count,
 		bool notify);
+int ndctl_namespace_inject_error2(struct ndctl_namespace *ndns,
+		unsigned long long block, unsigned long long count,
+		unsigned int flags);
 int ndctl_namespace_uninject_error(struct ndctl_namespace *ndns,
 		unsigned long long block, unsigned long long count);
+int ndctl_namespace_uninject_error2(struct ndctl_namespace *ndns,
+		unsigned long long block, unsigned long long count,
+		unsigned int flags);
 int ndctl_namespace_injection_status(struct ndctl_namespace *ndns);
+enum ndctl_namespace_inject_flags {
+	NDCTL_NS_INJECT_NOTIFY = 0,
+};
 
 struct ndctl_bb;
 unsigned long long ndctl_bb_get_block(struct ndctl_bb *bb);
-- 
2.14.3

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

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [ndctl PATCH 4/4] ndctl, inject-error: add a --saturate option
  2018-05-01 18:00 [ndctl PATCH 0/4] Error injection reworks Vishal Verma
                   ` (2 preceding siblings ...)
  2018-05-01 18:00 ` [ndctl PATCH 3/4] libndctl, inject: add 'v2' APIs for inject and uninject Vishal Verma
@ 2018-05-01 18:00 ` Vishal Verma
  2018-05-01 19:54 ` [ndctl PATCH 0/4] Error injection reworks Dave Jiang
  4 siblings, 0 replies; 6+ messages in thread
From: Vishal Verma @ 2018-05-01 18:00 UTC (permalink / raw)
  To: linux-nvdimm

Now that error injection by default injects fewer bytes per block,
provide an option to allow it to behave in the old way, i.e. injecting
the entire block.

The downside of these reworks is that where as the old way injected the
entire address range in one command, this now issues an ndctl command
per block, which can be slower. However, since this command is only for
testing and debugging purposes, it is expected that the user will
perform targeted, small injections rather than expansive ones at a time,
so the one-DSM-per-block change shouldn't be a noticeable hit. If this
changes in the future, we can consider adding an optimization for the
--saturate path.

Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 Documentation/ndctl/ndctl-inject-error.txt |  7 +++++++
 ndctl/inject-error.c                       |  7 ++++++-
 ndctl/lib/inject.c                         | 16 ++++++++++------
 ndctl/libndctl.h                           |  1 +
 4 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/Documentation/ndctl/ndctl-inject-error.txt b/Documentation/ndctl/ndctl-inject-error.txt
index 07c992a..744ea50 100644
--- a/Documentation/ndctl/ndctl-inject-error.txt
+++ b/Documentation/ndctl/ndctl-inject-error.txt
@@ -24,6 +24,8 @@ In other words, we only inject one 'ars_unit' per sector. This is sufficient
 for Linux to mark the whole sector as bad, and will show up as such in the
 various 'badblocks' lists in the kernel. If multiple blocks are being injected,
 only the first 'n' bytes of each block specified will be injected as errors.
+This can be overridden by the --saturate option, which will force the entire
+block to be injected as an error.
 
 WARNING: These commands are DANGEROUS and can cause data loss. They are
 only provided for testing and debugging purposes.
@@ -95,6 +97,11 @@ OPTIONS
 	when the location is accessed. If the platform firmware does not
 	support this feature, this will have no effect.
 
+-S::
+--saturate::
+	This option forces error injection or un-injection to cover the entire
+	address range covered by the specified block(s).
+
 -v::
 --verbose::
 	Emit debug messages for the error injection process
diff --git a/ndctl/inject-error.c b/ndctl/inject-error.c
index e977136..2b2fec0 100644
--- a/ndctl/inject-error.c
+++ b/ndctl/inject-error.c
@@ -47,6 +47,7 @@ static struct parameters {
 	bool clear;
 	bool status;
 	bool no_notify;
+	bool saturate;
 	bool human;
 } param;
 
@@ -74,6 +75,8 @@ OPT_BOOLEAN('d', "uninject", &param.clear, \
 	"un-inject a previously injected error"), \
 OPT_BOOLEAN('t', "status", &param.status, "get error injection status"), \
 OPT_BOOLEAN('N', "no-notify", &param.no_notify, "firmware should not notify OS"), \
+OPT_BOOLEAN('S', "saturate", &param.saturate, \
+	"inject full sector, not just 'ars_unit' bytes"), \
 OPT_BOOLEAN('u', "human", &param.human, "use human friendly number formats ")
 
 static const struct option inject_options[] = {
@@ -104,7 +107,7 @@ static int inject_init(void)
 		ictx.op_mask |= 1 << OP_CLEAR;
 	}
 	if (param.status) {
-		if (param.block || param.count) {
+		if (param.block || param.count || param.saturate) {
 			error("status is invalid with inject or uninject\n");
 			return -EINVAL;
 		}
@@ -145,6 +148,8 @@ static int inject_init(void)
 
 	if (param.human)
 		ictx.json_flags |= UTIL_JSON_HUMAN;
+	if (param.saturate)
+		ictx.inject_flags |= 1 << NDCTL_NS_INJECT_SATURATE;
 
 	return 0;
 }
diff --git a/ndctl/lib/inject.c b/ndctl/lib/inject.c
index 5cffe53..848f8a9 100644
--- a/ndctl/lib/inject.c
+++ b/ndctl/lib/inject.c
@@ -135,9 +135,11 @@ static int ndctl_namespace_inject_one_error(struct ndctl_namespace *ndns,
 	if (clear_unit < 0)
 		return clear_unit;
 
-	/* clamp injection length per block to the clear_unit */
-	if (length > (unsigned int)clear_unit)
-		length = clear_unit;
+	if (!(flags & (1 << NDCTL_NS_INJECT_SATURATE))) {
+		/* clamp injection length per block to the clear_unit */
+		if (length > (unsigned int)clear_unit)
+			length = clear_unit;
+	}
 
 	cmd = ndctl_bus_cmd_new_err_inj(bus);
 	if (!cmd)
@@ -213,9 +215,11 @@ static int ndctl_namespace_uninject_one_error(struct ndctl_namespace *ndns,
 	if (clear_unit < 0)
 		return clear_unit;
 
-	/* clamp injection length per block to the clear_unit */
-	if (length > (unsigned int)clear_unit)
-		length = clear_unit;
+	if (!(flags & (1 << NDCTL_NS_INJECT_SATURATE))) {
+		/* clamp injection length per block to the clear_unit */
+		if (length > (unsigned int)clear_unit)
+			length = clear_unit;
+	}
 
 	cmd = ndctl_bus_cmd_new_err_inj_clr(bus);
 	if (!cmd)
diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h
index a001271..be997ac 100644
--- a/ndctl/libndctl.h
+++ b/ndctl/libndctl.h
@@ -490,6 +490,7 @@ int ndctl_namespace_uninject_error2(struct ndctl_namespace *ndns,
 int ndctl_namespace_injection_status(struct ndctl_namespace *ndns);
 enum ndctl_namespace_inject_flags {
 	NDCTL_NS_INJECT_NOTIFY = 0,
+	NDCTL_NS_INJECT_SATURATE,
 };
 
 struct ndctl_bb;
-- 
2.14.3

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

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [ndctl PATCH 0/4] Error injection reworks
  2018-05-01 18:00 [ndctl PATCH 0/4] Error injection reworks Vishal Verma
                   ` (3 preceding siblings ...)
  2018-05-01 18:00 ` [ndctl PATCH 4/4] ndctl, inject-error: add a --saturate option Vishal Verma
@ 2018-05-01 19:54 ` Dave Jiang
  4 siblings, 0 replies; 6+ messages in thread
From: Dave Jiang @ 2018-05-01 19:54 UTC (permalink / raw)
  To: Vishal Verma, linux-nvdimm


On 5/1/2018 11:00 AM, Vishal Verma wrote:
> Updates to the error injection facilities in libndctl and ndctl that:
> 1. Inject fewer bytes per injected block:
>    It is sufficient to inject even a single byte (cache line) for Linux
>    to mark the entire block as a badblock. Reduce the number of injected
>    bytes per block to the unit reported by clear_err_unit
>
> 2. Provide a --saturate option:
>    If the old behavior of injecting the whole block for every block is
>    desired, provide a --saturate option to get that.
>
>
> Vishal Verma (4):
>    libndctl, ars: add an API to retrieve clear_err_unit
>    libndctl, inject: inject fewer bytes per block by default
>    libndctl, inject: add 'v2' APIs for inject and uninject
>    ndctl, inject-error: add a --saturate option
>
>   Documentation/ndctl/ndctl-inject-error.txt |  14 ++
>   ndctl/inject-error.c                       |  40 +++---
>   ndctl/lib/ars.c                            |  15 +++
>   ndctl/lib/inject.c                         | 201 ++++++++++++++++++++++-------
>   ndctl/lib/libndctl.sym                     |   7 +
>   ndctl/libndctl.h                           |  11 ++
>   6 files changed, 222 insertions(+), 66 deletions(-)


Reviewed-by: Dave Jiang <dave.jiang@intel.com>

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

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2018-05-01 19:54 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-01 18:00 [ndctl PATCH 0/4] Error injection reworks Vishal Verma
2018-05-01 18:00 ` [ndctl PATCH 1/4] libndctl, ars: add an API to retrieve clear_err_unit Vishal Verma
2018-05-01 18:00 ` [ndctl PATCH 2/4] libndctl, inject: inject fewer bytes per block by default Vishal Verma
2018-05-01 18:00 ` [ndctl PATCH 3/4] libndctl, inject: add 'v2' APIs for inject and uninject Vishal Verma
2018-05-01 18:00 ` [ndctl PATCH 4/4] ndctl, inject-error: add a --saturate option Vishal Verma
2018-05-01 19:54 ` [ndctl PATCH 0/4] Error injection reworks Dave Jiang

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).