On Mon, Apr 24, 2017 at 3:36 PM, Jerry Hoemann <jerry.hoemann(a)hpe.com> wrote:
nd_cmd_out_size is called by __nd_ioctl to size the buffer passed to
acpi_nfit_ctl. If the DSM function being called has a variable
sized output, nd_cmd_out_size will look at the return field to
determine buffer size. However, the DSM call hasn't been made yet,
so output size is core residue.
Have nd_cmd_out_size be bimodal with version "early" to be called
before the DSM call is made. For variable sized output fields
have it return ND_IOCTL_MAX_BUFLEN. __nd_ioctl sees new return
values and adjust buffer size accordingly.
The downside to this approach are:
1) Requires user buffer input size to be ND_IOCTL_MAX_BUFLEN (4 MB) for
calls to DSM with variable return.
2) The needless copyin of 4MB
An alternative approach (not yet prototyped) would move the call
to nd_cmd_out_size until after the return from acpi_nfit_ctl. Here,
the call has been made and return size would be known.
The size of the buffer allocated in would always be ND_IOCTL_MAX_BUFLEN.
Signed-off-by: Jerry Hoemann <jerry.hoemann(a)hpe.com>
---
drivers/nvdimm/bus.c | 30 ++++++++++++++++++++++++------
1 file changed, 24 insertions(+), 6 deletions(-)
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 23d4a17..50f8cc6 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -713,9 +713,9 @@ u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd,
}
EXPORT_SYMBOL_GPL(nd_cmd_in_size);
-u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd,
+u32 nd_cmd_out_size_early(struct nvdimm *nvdimm, int cmd,
const struct nd_cmd_desc *desc, int idx, const u32 *in_field,
- const u32 *out_field, unsigned long remainder)
+ const u32 *out_field, unsigned long remainder, int early)
{
if (idx >= desc->out_num)
return UINT_MAX;
@@ -725,9 +725,13 @@ u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd,
if (nvdimm && cmd == ND_CMD_GET_CONFIG_DATA && idx == 1)
return in_field[1];
- else if (nvdimm && cmd == ND_CMD_VENDOR && idx == 2)
+ else if (nvdimm && cmd == ND_CMD_VENDOR && idx == 2) {
+ if (early)
+ return ND_IOCTL_MAX_BUFLEN;
return out_field[1];
Are you using ndctl_dimm_cmd_new_vendor_specific() to submit a vendor
specific command? It already pre-populates out_field[1] with the
initial output size.