anitazha / rpms / ndctl

Forked from rpms/ndctl a year ago
Clone

Blame SOURCES/0027-ndctl-dimm-Fix-label-index-block-calculations.patch

e0018b
From 7e98977c10ad5f4baf5e3bc4d5b4b2fd733a8b7e Mon Sep 17 00:00:00 2001
e0018b
From: Jingqi Liu <jingqi.liu@intel.com>
e0018b
Date: Thu, 8 Jul 2021 16:14:46 +0800
e0018b
Subject: [PATCH 027/217] ndctl/dimm: Fix label index block calculations
e0018b
e0018b
The following bug is caused by setting the size of Label Index Block
e0018b
to a fixed 256 bytes.
e0018b
e0018b
Use the following Qemu command to start a Guest with 2MB label-size:
e0018b
	-object memory-backend-file,id=mem1,share=on,mem-path=/dev/dax1.1,size=14G,align=2M
e0018b
	-device nvdimm,memdev=mem1,id=nv1,label-size=2M
e0018b
e0018b
There is a namespace in the Guest as follows:
e0018b
	$ ndctl list
e0018b
	[
e0018b
	  {
e0018b
	    "dev":"namespace0.0",
e0018b
	    "mode":"devdax",
e0018b
	    "map":"dev",
e0018b
	    "size":14780727296,
e0018b
	    "uuid":"58ad5282-5a16-404f-b8ee-e28b4c784eb8",
e0018b
	    "chardev":"dax0.0",
e0018b
	    "align":2097152,
e0018b
	    "name":"namespace0.0"
e0018b
	  }
e0018b
	]
e0018b
e0018b
Fail to read labels. The result is as follows:
e0018b
	$ ndctl read-labels -u nmem0
e0018b
	[
e0018b
	]
e0018b
	read 0 nmem
e0018b
e0018b
If using the following Qemu command to start the Guest with 128K
e0018b
label-size, this label can be read correctly.
e0018b
	-object memory-backend-file,id=mem1,share=on,mem-path=/dev/dax1.1,size=14G,align=2M
e0018b
	-device nvdimm,memdev=mem1,id=nv1,label-size=128K
e0018b
e0018b
The size of a Label Index Block depends on how many label slots fit into
e0018b
the label storage area. The minimum size of an index block is 256 bytes
e0018b
and the size must be a multiple of 256 bytes. For a storage area of 128KB,
e0018b
the corresponding Label Index Block size is 256 bytes. But if the label
e0018b
storage area is not 128KB, the Label Index Block size should not be 256 bytes.
e0018b
e0018b
Namespace Label Index Block appears twice at the top of the label storage area.
e0018b
Following the two index blocks, an array for storing labels takes up the
e0018b
remainder of the label storage area.
e0018b
e0018b
For obtaining the size of Namespace Index Block, we also cannot rely on
e0018b
the field of 'mysize' in this index block since it might be corrupted.
e0018b
Similar to the linux kernel, we use sizeof_namespace_index() to get the size
e0018b
of Namespace Index Block. Then we can also correctly calculate the starting
e0018b
offset of the following namespace labels.
e0018b
e0018b
Link: https://lore.kernel.org/r/20210708081446.14323-1-jingqi.liu@intel.com
e0018b
Suggested-by: Dan Williams <dan.j.williams@intel.com>
e0018b
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
e0018b
Reviewed-by: Vishal Verma <vishal.l.verma@intel.com>
e0018b
Signed-off-by: Jingqi Liu <jingqi.liu@intel.com>
e0018b
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
e0018b
---
e0018b
 ndctl/dimm.c           | 19 +++++++++++++++----
e0018b
 ndctl/lib/dimm.c       |  5 +++++
e0018b
 ndctl/lib/libndctl.sym |  1 +
e0018b
 ndctl/libndctl.h       |  1 +
e0018b
 4 files changed, 22 insertions(+), 4 deletions(-)
e0018b
e0018b
diff --git a/ndctl/dimm.c b/ndctl/dimm.c
e0018b
index 09ce49e..1d2d9a2 100644
e0018b
--- a/ndctl/dimm.c
e0018b
+++ b/ndctl/dimm.c
e0018b
@@ -94,13 +94,18 @@ static struct json_object *dump_label_json(struct ndctl_dimm *dimm,
e0018b
 	struct json_object *jarray = json_object_new_array();
e0018b
 	struct json_object *jlabel = NULL;
e0018b
 	struct namespace_label nslabel;
e0018b
+	unsigned int nsindex_size;
e0018b
 	unsigned int slot = -1;
e0018b
 	ssize_t offset;
e0018b
 
e0018b
 	if (!jarray)
e0018b
 		return NULL;
e0018b
 
e0018b
-	for (offset = NSINDEX_ALIGN * 2; offset < size;
e0018b
+	nsindex_size = ndctl_dimm_sizeof_namespace_index(dimm);
e0018b
+	if (nsindex_size == 0)
e0018b
+		return NULL;
e0018b
+
e0018b
+	for (offset = nsindex_size * 2; offset < size;
e0018b
 			offset += ndctl_dimm_sizeof_namespace_label(dimm)) {
e0018b
 		ssize_t len = min_t(ssize_t,
e0018b
 				ndctl_dimm_sizeof_namespace_label(dimm),
e0018b
@@ -204,17 +209,23 @@ static struct json_object *dump_label_json(struct ndctl_dimm *dimm,
e0018b
 	return jarray;
e0018b
 }
e0018b
 
e0018b
-static struct json_object *dump_index_json(struct ndctl_cmd *cmd_read, ssize_t size)
e0018b
+static struct json_object *dump_index_json(struct ndctl_dimm *dimm,
e0018b
+		struct ndctl_cmd *cmd_read, ssize_t size)
e0018b
 {
e0018b
 	struct json_object *jarray = json_object_new_array();
e0018b
 	struct json_object *jindex = NULL;
e0018b
 	struct namespace_index nsindex;
e0018b
+	unsigned int nsindex_size;
e0018b
 	ssize_t offset;
e0018b
 
e0018b
 	if (!jarray)
e0018b
 		return NULL;
e0018b
 
e0018b
-	for (offset = 0; offset < NSINDEX_ALIGN * 2; offset += NSINDEX_ALIGN) {
e0018b
+	nsindex_size = ndctl_dimm_sizeof_namespace_index(dimm);
e0018b
+	if (nsindex_size == 0)
e0018b
+		return NULL;
e0018b
+
e0018b
+	for (offset = 0; offset < nsindex_size * 2; offset += nsindex_size) {
e0018b
 		ssize_t len = min_t(ssize_t, sizeof(nsindex), size - offset);
e0018b
 		struct json_object *jobj;
e0018b
 
e0018b
@@ -288,7 +299,7 @@ static struct json_object *dump_json(struct ndctl_dimm *dimm,
e0018b
 		goto err;
e0018b
 	json_object_object_add(jdimm, "dev", jobj);
e0018b
 
e0018b
-	jindex = dump_index_json(cmd_read, size);
e0018b
+	jindex = dump_index_json(dimm, cmd_read, size);
e0018b
 	if (!jindex)
e0018b
 		goto err;
e0018b
 	json_object_object_add(jdimm, "index", jindex);
e0018b
diff --git a/ndctl/lib/dimm.c b/ndctl/lib/dimm.c
e0018b
index c045cbe..9e36e28 100644
e0018b
--- a/ndctl/lib/dimm.c
e0018b
+++ b/ndctl/lib/dimm.c
e0018b
@@ -256,6 +256,11 @@ static int __label_validate(struct nvdimm_data *ndd)
e0018b
 	return -EINVAL;
e0018b
 }
e0018b
 
e0018b
+NDCTL_EXPORT unsigned int ndctl_dimm_sizeof_namespace_index(struct ndctl_dimm *dimm)
e0018b
+{
e0018b
+	return sizeof_namespace_index(&dimm->ndd);
e0018b
+}
e0018b
+
e0018b
 /*
e0018b
  * If the dimm labels have not been previously validated this routine
e0018b
  * will make up a default size. Otherwise, it will pick the size based
e0018b
diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym
e0018b
index 58afb74..5ee73b7 100644
e0018b
--- a/ndctl/lib/libndctl.sym
e0018b
+++ b/ndctl/lib/libndctl.sym
e0018b
@@ -454,4 +454,5 @@ LIBNDCTL_25 {
e0018b
 
e0018b
 LIBNDCTL_26 {
e0018b
 	ndctl_bus_nfit_translate_spa;
e0018b
+	ndctl_dimm_sizeof_namespace_index;
e0018b
 } LIBNDCTL_25;
e0018b
diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h
e0018b
index 87d07b7..df109bb 100644
e0018b
--- a/ndctl/libndctl.h
e0018b
+++ b/ndctl/libndctl.h
e0018b
@@ -337,6 +337,7 @@ int ndctl_dimm_init_labels(struct ndctl_dimm *dimm,
e0018b
 		enum ndctl_namespace_version v);
e0018b
 unsigned long ndctl_dimm_get_available_labels(struct ndctl_dimm *dimm);
e0018b
 unsigned int ndctl_dimm_sizeof_namespace_label(struct ndctl_dimm *dimm);
e0018b
+unsigned int ndctl_dimm_sizeof_namespace_index(struct ndctl_dimm *dimm);
e0018b
 unsigned int ndctl_cmd_cfg_size_get_size(struct ndctl_cmd *cfg_size);
e0018b
 ssize_t ndctl_cmd_cfg_read_get_data(struct ndctl_cmd *cfg_read, void *buf,
e0018b
 		unsigned int len, unsigned int offset);
e0018b
-- 
e0018b
2.27.0
e0018b