Commit 747ffe11 authored by Dan Williams's avatar Dan Williams

libnvdimm, tools/testing/nvdimm: fix 'ars_status' output buffer sizing

Use the output length specified in the command to size the receive
buffer rather than the arbitrary 4K limit.

This bug was hiding the fact that the ndctl implementation of
ndctl_bus_cmd_new_ars_status() was not specifying an output buffer size.

Cc: <stable@vger.kernel.org>
Cc: Vishal Verma <vishal.l.verma@intel.com>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 6697b2cf
...@@ -1516,13 +1516,13 @@ static int ars_do_start(struct nvdimm_bus_descriptor *nd_desc, ...@@ -1516,13 +1516,13 @@ static int ars_do_start(struct nvdimm_bus_descriptor *nd_desc,
} }
static int ars_get_status(struct nvdimm_bus_descriptor *nd_desc, static int ars_get_status(struct nvdimm_bus_descriptor *nd_desc,
struct nd_cmd_ars_status *cmd) struct nd_cmd_ars_status *cmd, u32 size)
{ {
int rc; int rc;
while (1) { while (1) {
rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_STATUS, cmd, rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_STATUS, cmd,
sizeof(*cmd)); size);
if (rc || cmd->status & 0xffff) if (rc || cmd->status & 0xffff)
return -ENXIO; return -ENXIO;
...@@ -1580,6 +1580,7 @@ static int acpi_nfit_find_poison(struct acpi_nfit_desc *acpi_desc, ...@@ -1580,6 +1580,7 @@ static int acpi_nfit_find_poison(struct acpi_nfit_desc *acpi_desc,
struct nd_cmd_ars_start *ars_start = NULL; struct nd_cmd_ars_start *ars_start = NULL;
struct nd_cmd_ars_cap *ars_cap = NULL; struct nd_cmd_ars_cap *ars_cap = NULL;
u64 start, len, cur, remaining; u64 start, len, cur, remaining;
u32 ars_status_size;
int rc; int rc;
ars_cap = kzalloc(sizeof(*ars_cap), GFP_KERNEL); ars_cap = kzalloc(sizeof(*ars_cap), GFP_KERNEL);
...@@ -1609,14 +1610,14 @@ static int acpi_nfit_find_poison(struct acpi_nfit_desc *acpi_desc, ...@@ -1609,14 +1610,14 @@ static int acpi_nfit_find_poison(struct acpi_nfit_desc *acpi_desc,
* Check if a full-range ARS has been run. If so, use those results * Check if a full-range ARS has been run. If so, use those results
* without having to start a new ARS. * without having to start a new ARS.
*/ */
ars_status = kzalloc(ars_cap->max_ars_out + sizeof(*ars_status), ars_status_size = ars_cap->max_ars_out;
GFP_KERNEL); ars_status = kzalloc(ars_status_size, GFP_KERNEL);
if (!ars_status) { if (!ars_status) {
rc = -ENOMEM; rc = -ENOMEM;
goto out; goto out;
} }
rc = ars_get_status(nd_desc, ars_status); rc = ars_get_status(nd_desc, ars_status, ars_status_size);
if (rc) if (rc)
goto out; goto out;
...@@ -1646,7 +1647,7 @@ static int acpi_nfit_find_poison(struct acpi_nfit_desc *acpi_desc, ...@@ -1646,7 +1647,7 @@ static int acpi_nfit_find_poison(struct acpi_nfit_desc *acpi_desc,
if (rc) if (rc)
goto out; goto out;
rc = ars_get_status(nd_desc, ars_status); rc = ars_get_status(nd_desc, ars_status, ars_status_size);
if (rc) if (rc)
goto out; goto out;
......
...@@ -392,8 +392,8 @@ static const struct nd_cmd_desc __nd_cmd_bus_descs[] = { ...@@ -392,8 +392,8 @@ static const struct nd_cmd_desc __nd_cmd_bus_descs[] = {
.out_sizes = { 4, }, .out_sizes = { 4, },
}, },
[ND_CMD_ARS_STATUS] = { [ND_CMD_ARS_STATUS] = {
.out_num = 2, .out_num = 3,
.out_sizes = { 4, UINT_MAX, }, .out_sizes = { 4, 4, UINT_MAX, },
}, },
}; };
...@@ -442,8 +442,8 @@ u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd, ...@@ -442,8 +442,8 @@ u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd,
return in_field[1]; return in_field[1];
else if (nvdimm && cmd == ND_CMD_VENDOR && idx == 2) else if (nvdimm && cmd == ND_CMD_VENDOR && idx == 2)
return out_field[1]; return out_field[1];
else if (!nvdimm && cmd == ND_CMD_ARS_STATUS && idx == 1) else if (!nvdimm && cmd == ND_CMD_ARS_STATUS && idx == 2)
return ND_CMD_ARS_STATUS_MAX; return out_field[1] - 8;
return UINT_MAX; return UINT_MAX;
} }
......
...@@ -28,7 +28,6 @@ enum { ...@@ -28,7 +28,6 @@ enum {
ND_IOCTL_MAX_BUFLEN = SZ_4M, ND_IOCTL_MAX_BUFLEN = SZ_4M,
ND_CMD_MAX_ELEM = 4, ND_CMD_MAX_ELEM = 4,
ND_CMD_MAX_ENVELOPE = 16, ND_CMD_MAX_ENVELOPE = 16,
ND_CMD_ARS_STATUS_MAX = SZ_4K,
ND_MAX_MAPPINGS = 32, ND_MAX_MAPPINGS = 32,
/* region flag indicating to direct-map persistent memory by default */ /* region flag indicating to direct-map persistent memory by default */
......
...@@ -217,13 +217,16 @@ static int nfit_test_cmd_set_config_data(struct nd_cmd_set_config_hdr *nd_cmd, ...@@ -217,13 +217,16 @@ static int nfit_test_cmd_set_config_data(struct nd_cmd_set_config_hdr *nd_cmd,
return rc; return rc;
} }
#define NFIT_TEST_ARS_RECORDS 4
static int nfit_test_cmd_ars_cap(struct nd_cmd_ars_cap *nd_cmd, static int nfit_test_cmd_ars_cap(struct nd_cmd_ars_cap *nd_cmd,
unsigned int buf_len) unsigned int buf_len)
{ {
if (buf_len < sizeof(*nd_cmd)) if (buf_len < sizeof(*nd_cmd))
return -EINVAL; return -EINVAL;
nd_cmd->max_ars_out = 256; nd_cmd->max_ars_out = sizeof(struct nd_cmd_ars_status)
+ NFIT_TEST_ARS_RECORDS * sizeof(struct nd_ars_record);
nd_cmd->status = (ND_ARS_PERSISTENT | ND_ARS_VOLATILE) << 16; nd_cmd->status = (ND_ARS_PERSISTENT | ND_ARS_VOLATILE) << 16;
return 0; return 0;
...@@ -246,7 +249,8 @@ static int nfit_test_cmd_ars_status(struct nd_cmd_ars_status *nd_cmd, ...@@ -246,7 +249,8 @@ static int nfit_test_cmd_ars_status(struct nd_cmd_ars_status *nd_cmd,
if (buf_len < sizeof(*nd_cmd)) if (buf_len < sizeof(*nd_cmd))
return -EINVAL; return -EINVAL;
nd_cmd->out_length = 256; nd_cmd->out_length = sizeof(struct nd_cmd_ars_status);
/* TODO: emit error records */
nd_cmd->num_records = 0; nd_cmd->num_records = 0;
nd_cmd->address = 0; nd_cmd->address = 0;
nd_cmd->length = -1ULL; nd_cmd->length = -1ULL;
......
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