diff options
author | Dan Williams <dan.j.williams@intel.com> | 2016-02-23 06:50:31 +0100 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2016-03-05 21:24:06 +0100 |
commit | 87bf572e19a092cc9cc77d5a00d543a2b628c142 (patch) | |
tree | ae275e80641400bccfbf39c168dbfc5178b44159 /drivers/acpi | |
parent | nfit: scrub and register regions in a workqueue (diff) | |
download | linux-87bf572e19a092cc9cc77d5a00d543a2b628c142.tar.xz linux-87bf572e19a092cc9cc77d5a00d543a2b628c142.zip |
nfit: disable userspace initiated ars during scrub
While the nfit driver is issuing address range scrub commands and
reaping the results do not permit an ars_start command issued from
userspace. The scrub thread assumes that all ars completions are for
scrubs initiated by platform firmware at boot, or by the nfit driver.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/nfit.c | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index 3646501b01d7..0def4ebf5d43 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c @@ -2186,6 +2186,28 @@ static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc) return wait_for_completion_interruptible(&flush.cmp); } +static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc, + struct nvdimm *nvdimm, unsigned int cmd) +{ + struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc); + + if (nvdimm) + return 0; + if (cmd != ND_CMD_ARS_START) + return 0; + + /* + * The kernel and userspace may race to initiate a scrub, but + * the scrub thread is prepared to lose that initial race. It + * just needs guarantees that any ars it initiates are not + * interrupted by any intervening start reqeusts from userspace. + */ + if (work_busy(&acpi_desc->work)) + return -EBUSY; + + return 0; +} + void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev) { struct nvdimm_bus_descriptor *nd_desc; @@ -2197,6 +2219,7 @@ void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev) nd_desc->provider_name = "ACPI.NFIT"; nd_desc->ndctl = acpi_nfit_ctl; nd_desc->flush_probe = acpi_nfit_flush_probe; + nd_desc->clear_to_send = acpi_nfit_clear_to_send; nd_desc->attr_groups = acpi_nfit_attribute_groups; INIT_LIST_HEAD(&acpi_desc->spa_maps); |