Commit e7c5a571 authored by Dan Williams's avatar Dan Williams

libnvdimm, dimm: handle EACCES failures from label reads

The new support for the standard _LSR and _LSW methods neglected to also
update the nvdimm_init_config_data() and nvdimm_set_config_data() to
return the translated error code from failed commands. This precision is
necessary because the locked status that was previously returned on
ND_CMD_GET_CONFIG_SIZE commands is now returned on
ND_CMD_{GET,SET}_CONFIG_DATA commands.

If the kernel misses this indication it can inadvertently fall back to
label-less mode when it should otherwise avoid all access to locked
regions.

Cc: <stable@vger.kernel.org>
Fixes: 4b27db7e ("acpi, nfit: add support for the _LSI, _LSR, and...")
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 60cc43fc
...@@ -88,9 +88,9 @@ int nvdimm_init_nsarea(struct nvdimm_drvdata *ndd) ...@@ -88,9 +88,9 @@ int nvdimm_init_nsarea(struct nvdimm_drvdata *ndd)
int nvdimm_init_config_data(struct nvdimm_drvdata *ndd) int nvdimm_init_config_data(struct nvdimm_drvdata *ndd)
{ {
struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(ndd->dev); struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(ndd->dev);
int rc = validate_dimm(ndd), cmd_rc = 0;
struct nd_cmd_get_config_data_hdr *cmd; struct nd_cmd_get_config_data_hdr *cmd;
struct nvdimm_bus_descriptor *nd_desc; struct nvdimm_bus_descriptor *nd_desc;
int rc = validate_dimm(ndd);
u32 max_cmd_size, config_size; u32 max_cmd_size, config_size;
size_t offset; size_t offset;
...@@ -124,9 +124,11 @@ int nvdimm_init_config_data(struct nvdimm_drvdata *ndd) ...@@ -124,9 +124,11 @@ int nvdimm_init_config_data(struct nvdimm_drvdata *ndd)
cmd->in_offset = offset; cmd->in_offset = offset;
rc = nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev), rc = nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev),
ND_CMD_GET_CONFIG_DATA, cmd, ND_CMD_GET_CONFIG_DATA, cmd,
cmd->in_length + sizeof(*cmd), NULL); cmd->in_length + sizeof(*cmd), &cmd_rc);
if (rc || cmd->status) { if (rc < 0)
rc = -ENXIO; break;
if (cmd_rc < 0) {
rc = cmd_rc;
break; break;
} }
memcpy(ndd->data + offset, cmd->out_buf, cmd->in_length); memcpy(ndd->data + offset, cmd->out_buf, cmd->in_length);
...@@ -140,9 +142,9 @@ int nvdimm_init_config_data(struct nvdimm_drvdata *ndd) ...@@ -140,9 +142,9 @@ int nvdimm_init_config_data(struct nvdimm_drvdata *ndd)
int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset, int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
void *buf, size_t len) void *buf, size_t len)
{ {
int rc = validate_dimm(ndd);
size_t max_cmd_size, buf_offset; size_t max_cmd_size, buf_offset;
struct nd_cmd_set_config_hdr *cmd; struct nd_cmd_set_config_hdr *cmd;
int rc = validate_dimm(ndd), cmd_rc = 0;
struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(ndd->dev); struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(ndd->dev);
struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc; struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc;
...@@ -164,7 +166,6 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset, ...@@ -164,7 +166,6 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
for (buf_offset = 0; len; len -= cmd->in_length, for (buf_offset = 0; len; len -= cmd->in_length,
buf_offset += cmd->in_length) { buf_offset += cmd->in_length) {
size_t cmd_size; size_t cmd_size;
u32 *status;
cmd->in_offset = offset + buf_offset; cmd->in_offset = offset + buf_offset;
cmd->in_length = min(max_cmd_size, len); cmd->in_length = min(max_cmd_size, len);
...@@ -172,12 +173,13 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset, ...@@ -172,12 +173,13 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
/* status is output in the last 4-bytes of the command buffer */ /* status is output in the last 4-bytes of the command buffer */
cmd_size = sizeof(*cmd) + cmd->in_length + sizeof(u32); cmd_size = sizeof(*cmd) + cmd->in_length + sizeof(u32);
status = ((void *) cmd) + cmd_size - sizeof(u32);
rc = nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev), rc = nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev),
ND_CMD_SET_CONFIG_DATA, cmd, cmd_size, NULL); ND_CMD_SET_CONFIG_DATA, cmd, cmd_size, &cmd_rc);
if (rc || *status) { if (rc < 0)
rc = rc ? rc : -ENXIO; break;
if (cmd_rc < 0) {
rc = cmd_rc;
break; break;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment