Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Thumshirn <jthumshirn@suse.de>2018-10-31 10:48:30 +0100
committerJohannes Thumshirn <jthumshirn@suse.de>2018-10-31 10:49:14 +0100
commit0ed4307f7cf774a0c3c5befff0e6e7e0a16c4e54 (patch)
tree41557e35ef97dd37e8f6c8ae3fa427267568dff0
parentcd87e2ee73991b535e3f9a68d2a3686ad50948a7 (diff)
nvdimm: Split label init out from the logic for getting config
data (bsc#1111921, bsc#1113408, FATE#326765).
-rw-r--r--patches.fixes/nvdimm-split-label-init-out-from-the-logic-for-getting-config-data.patch199
-rw-r--r--series.conf1
2 files changed, 200 insertions, 0 deletions
diff --git a/patches.fixes/nvdimm-split-label-init-out-from-the-logic-for-getting-config-data.patch b/patches.fixes/nvdimm-split-label-init-out-from-the-logic-for-getting-config-data.patch
new file mode 100644
index 0000000000..1299dec448
--- /dev/null
+++ b/patches.fixes/nvdimm-split-label-init-out-from-the-logic-for-getting-config-data.patch
@@ -0,0 +1,199 @@
+From: Alexander Duyck <alexander.h.duyck@linux.intel.com>
+Date: Wed, 10 Oct 2018 16:39:20 -0700
+Subject: nvdimm: Split label init out from the logic for getting config data
+Git-commit: 2d657d17f72d2ae70c02f0d0ea6a04ad0f016b57
+Patch-mainline: v4.20-rc1
+References: bsc#1111921, bsc#1113408, FATE#326765
+
+This patch splits the initialization of the label data into two functions.
+One for doing the init, and another for reading the actual configuration
+data. The idea behind this is that by doing this we create a symmetry
+between the getting and setting of config data in that we have a function
+for both. In addition it will make it easier for us to identify the bits
+that are related to init versus the pieces that are a wrapper for reading
+data from the ACPI interface.
+
+So for example by splitting things out like this it becomes much more
+obvious that we were performing checks that weren't necessarily related to
+the set/get operations such as relying on ndd->data being present when the
+set and get ops should not care about a locally cached copy of the label
+area.
+
+Reviewed-by: Toshi Kani <toshi.kani@hpe.com>
+Signed-off-by: Alexander Duyck <alexander.h.duyck@linux.intel.com>
+Signed-off-by: Dan Williams <dan.j.williams@intel.com>
+Acked-by: Johannes Thumshirn <jthumshirn@suse.de>
+---
+ drivers/nvdimm/dimm.c | 2 -
+ drivers/nvdimm/dimm_devs.c | 49 +++++++++++++++++----------------------------
+ drivers/nvdimm/label.c | 38 ++++++++++++++++++++++++++++++++++
+ drivers/nvdimm/label.h | 1
+ drivers/nvdimm/nd.h | 2 +
+ 5 files changed, 61 insertions(+), 31 deletions(-)
+
+--- a/drivers/nvdimm/dimm.c
++++ b/drivers/nvdimm/dimm.c
+@@ -54,7 +54,7 @@ static int nvdimm_probe(struct device *d
+ if (rc)
+ goto err;
+
+- rc = nvdimm_init_config_data(ndd);
++ rc = nd_label_data_init(ndd);
+ if (rc == -EACCES)
+ nvdimm_set_locked(dev);
+ if (rc)
+--- a/drivers/nvdimm/dimm_devs.c
++++ b/drivers/nvdimm/dimm_devs.c
+@@ -84,55 +84,47 @@ int nvdimm_init_nsarea(struct nvdimm_drv
+ return cmd_rc;
+ }
+
+-int nvdimm_init_config_data(struct nvdimm_drvdata *ndd)
++int nvdimm_get_config_data(struct nvdimm_drvdata *ndd, void *buf,
++ size_t offset, size_t len)
+ {
+ struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(ndd->dev);
++ struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc;
+ int rc = validate_dimm(ndd), cmd_rc = 0;
+ struct nd_cmd_get_config_data_hdr *cmd;
+- struct nvdimm_bus_descriptor *nd_desc;
+- u32 max_cmd_size, config_size;
+- size_t offset;
++ size_t max_cmd_size, buf_offset;
+
+ if (rc)
+ return rc;
+
+- if (ndd->data)
+- return 0;
+-
+- if (ndd->nsarea.status || ndd->nsarea.max_xfer == 0
+- || ndd->nsarea.config_size < ND_LABEL_MIN_SIZE) {
+- dev_dbg(ndd->dev, "failed to init config data area: (%d:%d)\n",
+- ndd->nsarea.max_xfer, ndd->nsarea.config_size);
++ if (offset + len > ndd->nsarea.config_size)
+ return -ENXIO;
+- }
+-
+- ndd->data = kvmalloc(ndd->nsarea.config_size, GFP_KERNEL);
+- if (!ndd->data)
+- return -ENOMEM;
+
+- max_cmd_size = min_t(u32, ndd->nsarea.config_size, ndd->nsarea.max_xfer);
++ max_cmd_size = min_t(u32, len, ndd->nsarea.max_xfer);
+ cmd = kvzalloc(max_cmd_size + sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+- nd_desc = nvdimm_bus->nd_desc;
+- for (config_size = ndd->nsarea.config_size, offset = 0;
+- config_size; config_size -= cmd->in_length,
+- offset += cmd->in_length) {
+- cmd->in_length = min(config_size, max_cmd_size);
+- cmd->in_offset = offset;
++ for (buf_offset = 0; len;
++ len -= cmd->in_length, buf_offset += cmd->in_length) {
++ size_t cmd_size;
++
++ cmd->in_offset = offset + buf_offset;
++ cmd->in_length = min(max_cmd_size, len);
++
++ cmd_size = sizeof(*cmd) + cmd->in_length;
++
+ rc = nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev),
+- ND_CMD_GET_CONFIG_DATA, cmd,
+- cmd->in_length + sizeof(*cmd), &cmd_rc);
++ ND_CMD_GET_CONFIG_DATA, cmd, cmd_size, &cmd_rc);
+ if (rc < 0)
+ break;
+ if (cmd_rc < 0) {
+ rc = cmd_rc;
+ break;
+ }
+- memcpy(ndd->data + offset, cmd->out_buf, cmd->in_length);
++
++ /* out_buf should be valid, copy it into our output buffer */
++ memcpy(buf + buf_offset, cmd->out_buf, cmd->in_length);
+ }
+- dev_dbg(ndd->dev, "%s: len: %zu rc: %d\n", __func__, offset, rc);
+ kvfree(cmd);
+
+ return rc;
+@@ -150,9 +142,6 @@ int nvdimm_set_config_data(struct nvdimm
+ if (rc)
+ return rc;
+
+- if (!ndd->data)
+- return -ENXIO;
+-
+ if (offset + len > ndd->nsarea.config_size)
+ return -ENXIO;
+
+--- a/drivers/nvdimm/label.c
++++ b/drivers/nvdimm/label.c
+@@ -422,6 +422,44 @@ int nd_label_reserve_dpa(struct nvdimm_d
+ return 0;
+ }
+
++int nd_label_data_init(struct nvdimm_drvdata *ndd)
++{
++ size_t config_size, read_size;
++ int rc = 0;
++
++ if (ndd->data)
++ return 0;
++
++ if (ndd->nsarea.status || ndd->nsarea.max_xfer == 0) {
++ dev_dbg(ndd->dev, "failed to init config data area: (%u:%u)\n",
++ ndd->nsarea.max_xfer, ndd->nsarea.config_size);
++ return -ENXIO;
++ }
++
++ /*
++ * We need to determine the maximum index area as this is the section
++ * we must read and validate before we can start processing labels.
++ *
++ * If the area is too small to contain the two indexes and 2 labels
++ * then we abort.
++ *
++ * Start at a label size of 128 as this should result in the largest
++ * possible namespace index size.
++ */
++ ndd->nslabel_size = 128;
++ read_size = sizeof_namespace_index(ndd) * 2;
++ if (!read_size)
++ return -ENXIO;
++
++ /* Allocate config data */
++ config_size = ndd->nsarea.config_size;
++ ndd->data = kvzalloc(config_size, GFP_KERNEL);
++ if (!ndd->data)
++ return -ENOMEM;
++
++ return nvdimm_get_config_data(ndd, ndd->data, 0, config_size);
++}
++
+ int nd_label_active_count(struct nvdimm_drvdata *ndd)
+ {
+ struct nd_namespace_index *nsindex;
+--- a/drivers/nvdimm/label.h
++++ b/drivers/nvdimm/label.h
+@@ -141,6 +141,7 @@ struct nvdimm_drvdata;
+ int nd_label_validate(struct nvdimm_drvdata *ndd);
+ void nd_label_copy(struct nvdimm_drvdata *ndd, struct nd_namespace_index *dst,
+ struct nd_namespace_index *src);
++int nd_label_data_init(struct nvdimm_drvdata *ndd);
+ size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd);
+ int nd_label_active_count(struct nvdimm_drvdata *ndd);
+ struct nd_namespace_label *nd_label_active(struct nvdimm_drvdata *ndd, int n);
+--- a/drivers/nvdimm/nd.h
++++ b/drivers/nvdimm/nd.h
+@@ -247,6 +247,8 @@ struct nvdimm_drvdata *to_ndd(struct nd_
+ int nvdimm_check_config_data(struct device *dev);
+ int nvdimm_init_nsarea(struct nvdimm_drvdata *ndd);
+ int nvdimm_init_config_data(struct nvdimm_drvdata *ndd);
++int nvdimm_get_config_data(struct nvdimm_drvdata *ndd, void *buf,
++ size_t offset, size_t len);
+ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
+ void *buf, size_t len);
+ long nvdimm_clear_poison(struct device *dev, phys_addr_t phys,
diff --git a/series.conf b/series.conf
index 8909d4910a..930a25e863 100644
--- a/series.conf
+++ b/series.conf
@@ -18056,6 +18056,7 @@
patches.fixes/nvdimm-sanity-check-labeloff.patch
patches.fixes/nvdimm-clarify-comment-in-sizeof_namespace_index.patch
patches.fixes/nvdimm-remove-empty-if-statement.patch
+ patches.fixes/nvdimm-split-label-init-out-from-the-logic-for-getting-config-data.patch
# davem/net
patches.fixes/udp-Unbreak-modules-that-rely-on-external-__skb_recv.patch