diff options
author | Dan Williams <dan.j.williams@intel.com> | 2017-02-02 13:31:00 -0500 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2017-02-03 14:47:36 -0500 |
commit | e471486c13b82b1338d49c798f78bb62b1ed0a9e (patch) | |
tree | e3e0fd302d607f12a0fb34db5058e80449accd2e | |
parent | 9d032f4201d39e5cf43a8709a047e481f5723fdc (diff) |
acpi, nfit: fix acpi_nfit_flush_probe() crash
We queue an on-stack work item to 'nfit_wq' and wait for it to complete
as part of a 'flush_probe' request. However, if the user cancels the
wait we need to make sure the item is flushed from the queue otherwise
we are leaving an out-of-scope stack address on the work list.
BUG: unable to handle kernel paging request at ffffbcb3c72f7cd0
IP: [<ffffffffa9413a7b>] __list_add+0x1b/0xb0
[..]
RIP: 0010:[<ffffffffa9413a7b>] [<ffffffffa9413a7b>] __list_add+0x1b/0xb0
RSP: 0018:ffffbcb3c7ba7c00 EFLAGS: 00010046
[..]
Call Trace:
[<ffffffffa90bb11a>] insert_work+0x3a/0xc0
[<ffffffffa927fdda>] ? seq_open+0x5a/0xa0
[<ffffffffa90bb30a>] __queue_work+0x16a/0x460
[<ffffffffa90bbb08>] queue_work_on+0x38/0x40
[<ffffffffc0cf2685>] acpi_nfit_flush_probe+0x95/0xc0 [nfit]
[<ffffffffc0cf25d0>] ? nfit_visible+0x40/0x40 [nfit]
[<ffffffffa9571495>] wait_probe_show+0x25/0x60
[<ffffffffa9546b30>] dev_attr_show+0x20/0x50
Fixes: 7ae0fa439faf ("nfit, libnvdimm: async region scrub workqueue")
Cc: <stable@vger.kernel.org>
Reviewed-by: Vishal Verma <vishal.l.verma@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r-- | drivers/acpi/nfit/core.c | 6 |
1 files changed, 5 insertions, 1 deletions
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 2f82b8eba360..7361d00818e2 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c | |||
@@ -2704,6 +2704,7 @@ static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc) | |||
2704 | struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc); | 2704 | struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc); |
2705 | struct device *dev = acpi_desc->dev; | 2705 | struct device *dev = acpi_desc->dev; |
2706 | struct acpi_nfit_flush_work flush; | 2706 | struct acpi_nfit_flush_work flush; |
2707 | int rc; | ||
2707 | 2708 | ||
2708 | /* bounce the device lock to flush acpi_nfit_add / acpi_nfit_notify */ | 2709 | /* bounce the device lock to flush acpi_nfit_add / acpi_nfit_notify */ |
2709 | device_lock(dev); | 2710 | device_lock(dev); |
@@ -2716,7 +2717,10 @@ static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc) | |||
2716 | INIT_WORK_ONSTACK(&flush.work, flush_probe); | 2717 | INIT_WORK_ONSTACK(&flush.work, flush_probe); |
2717 | COMPLETION_INITIALIZER_ONSTACK(flush.cmp); | 2718 | COMPLETION_INITIALIZER_ONSTACK(flush.cmp); |
2718 | queue_work(nfit_wq, &flush.work); | 2719 | queue_work(nfit_wq, &flush.work); |
2719 | return wait_for_completion_interruptible(&flush.cmp); | 2720 | |
2721 | rc = wait_for_completion_interruptible(&flush.cmp); | ||
2722 | cancel_work_sync(&flush.work); | ||
2723 | return rc; | ||
2720 | } | 2724 | } |
2721 | 2725 | ||
2722 | static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc, | 2726 | static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc, |