diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-08 04:17:45 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-08 04:17:45 +0000 |
commit | 41fb2ba1cd2e84f28cd9f5b91d670fef7d982409 (patch) | |
tree | 3518db389445fe1c1e74d64e3598ed34c6e2c59a /drivers/pci/controller/pci-hyperv.c | |
parent | Releasing progress-linux version 4.19.282-1progress5u1. (diff) | |
download | linux-41fb2ba1cd2e84f28cd9f5b91d670fef7d982409.tar.xz linux-41fb2ba1cd2e84f28cd9f5b91d670fef7d982409.zip |
Merging upstream version 4.19.289.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/pci/controller/pci-hyperv.c')
-rw-r--r-- | drivers/pci/controller/pci-hyperv.c | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index 63c79e140..f5f201bfc 100644 --- a/drivers/pci/controller/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c @@ -2445,6 +2445,24 @@ static int hv_pci_query_relations(struct hv_device *hdev) if (!ret) ret = wait_for_response(hdev, &comp); + /* + * In the case of fast device addition/removal, it's possible that + * vmbus_sendpacket() or wait_for_response() returns -ENODEV but we + * already got a PCI_BUS_RELATIONS* message from the host and the + * channel callback already scheduled a work to hbus->wq, which can be + * running pci_devices_present_work() -> survey_child_resources() -> + * complete(&hbus->survey_event), even after hv_pci_query_relations() + * exits and the stack variable 'comp' is no longer valid; as a result, + * a hang or a page fault may happen when the complete() calls + * raw_spin_lock_irqsave(). Flush hbus->wq before we exit from + * hv_pci_query_relations() to avoid the issues. Note: if 'ret' is + * -ENODEV, there can't be any more work item scheduled to hbus->wq + * after the flush_workqueue(): see vmbus_onoffer_rescind() -> + * vmbus_reset_channel_cb(), vmbus_rescind_cleanup() -> + * channel->rescind = true. + */ + flush_workqueue(hbus->wq); + return ret; } |