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: 4b27db7e26
("acpi, nfit: add support for the _LSI, _LSR, and...")
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
parent
60cc43fc88
commit
e7c5a571a8
1 changed files with 12 additions and 10 deletions
|
@ -88,9 +88,9 @@ int nvdimm_init_nsarea(struct nvdimm_drvdata *ndd)
|
|||
int nvdimm_init_config_data(struct nvdimm_drvdata *ndd)
|
||||
{
|
||||
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 nvdimm_bus_descriptor *nd_desc;
|
||||
int rc = validate_dimm(ndd);
|
||||
u32 max_cmd_size, config_size;
|
||||
size_t offset;
|
||||
|
||||
|
@ -124,9 +124,11 @@ int nvdimm_init_config_data(struct nvdimm_drvdata *ndd)
|
|||
cmd->in_offset = offset;
|
||||
rc = nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev),
|
||||
ND_CMD_GET_CONFIG_DATA, cmd,
|
||||
cmd->in_length + sizeof(*cmd), NULL);
|
||||
if (rc || cmd->status) {
|
||||
rc = -ENXIO;
|
||||
cmd->in_length + sizeof(*cmd), &cmd_rc);
|
||||
if (rc < 0)
|
||||
break;
|
||||
if (cmd_rc < 0) {
|
||||
rc = cmd_rc;
|
||||
break;
|
||||
}
|
||||
memcpy(ndd->data + offset, cmd->out_buf, cmd->in_length);
|
||||
|
@ -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,
|
||||
void *buf, size_t len)
|
||||
{
|
||||
int rc = validate_dimm(ndd);
|
||||
size_t max_cmd_size, buf_offset;
|
||||
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_descriptor *nd_desc = nvdimm_bus->nd_desc;
|
||||
|
||||
|
@ -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,
|
||||
buf_offset += cmd->in_length) {
|
||||
size_t cmd_size;
|
||||
u32 *status;
|
||||
|
||||
cmd->in_offset = offset + buf_offset;
|
||||
cmd->in_length = min(max_cmd_size, len);
|
||||
|
@ -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 */
|
||||
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),
|
||||
ND_CMD_SET_CONFIG_DATA, cmd, cmd_size, NULL);
|
||||
if (rc || *status) {
|
||||
rc = rc ? rc : -ENXIO;
|
||||
ND_CMD_SET_CONFIG_DATA, cmd, cmd_size, &cmd_rc);
|
||||
if (rc < 0)
|
||||
break;
|
||||
if (cmd_rc < 0) {
|
||||
rc = cmd_rc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue