[PATCH net] net: mana: fix reset work race with device removal
Fan Wu <[email protected]> Wed, 5 Aug 2026 14:19:37 +0000
| Newsgroups | org.kernel.vger.linux-hyperv,org.kernel.vger.linux-kernel,org.kernel.vger.netdev,org.kernel.vger.stable |
|---|---|
| Message-ID | <[email protected]> |
The reset service work runs on the system workqueue and obtains the
GDMA context through PCI drvdata. It can race with device removal
(mana_gd_remove()), which frees the context. A reset work that runs
after removal can therefore dereference the freed context.
Serialize mana_serv_reset() with device removal by taking the PCI
device lock across its drvdata access and reset sequence. The driver
core holds the same lock while invoking the remove callback, so remove
waits for an in-progress reset. Work that runs after remove observes
the drvdata cleared before the context is freed.
Drop the lock before rescanning, since the rescan path may remove the
device and acquire the device lock again. Also clear GC_IN_SERVICE
before rescanning after a failed resume, so this exit follows the same
service-state cleanup as the other reset exits.
This issue was found by an in-house static analysis tool.
Fixes: fbe346ce9d62 ("net: mana: Handle Reset Request from MANA NIC")
Cc: [email protected]
Assisted-by: Codex:gpt-5.6
Signed-off-by: Fan Wu <[email protected]>
---
drivers/net/ethernet/microsoft/mana/gdma_main.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
index e8b7ffb47eb9..ae03d7a53 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
@@ -591,15 +591,16 @@ static void mana_serv_fpga(struct pci_dev *pdev)
static void mana_serv_reset(struct pci_dev *pdev)
{
- struct gdma_context *gc = pci_get_drvdata(pdev);
+ struct gdma_context *gc;
struct hw_channel_context *hwc;
int ret;
+ device_lock(&pdev->dev);
+ gc = pci_get_drvdata(pdev);
if (!gc) {
/* Perform PCI rescan on device if GC is not set up */
dev_err(&pdev->dev, "MANA service: GC not setup, rescanning\n");
- mana_serv_rescan(pdev);
- return;
+ goto rescan;
}
hwc = gc->hwc.driver_data;
@@ -621,8 +622,8 @@ static void mana_serv_reset(struct pci_dev *pdev)
if (ret == -ETIMEDOUT || ret == -EPROTO) {
/* Perform PCI rescan on device if we failed on HWC */
dev_err(&pdev->dev, "MANA service: resume failed, rescanning\n");
- mana_serv_rescan(pdev);
- return;
+ clear_bit(GC_IN_SERVICE, &gc->flags);
+ goto rescan;
}
if (ret)
@@ -632,6 +633,12 @@ static void mana_serv_reset(struct pci_dev *pdev)
out:
clear_bit(GC_IN_SERVICE, &gc->flags);
+ device_unlock(&pdev->dev);
+ return;
+
+rescan:
+ device_unlock(&pdev->dev);
+ mana_serv_rescan(pdev);
}
static void mana_do_service(enum gdma_eqe_type type, struct pci_dev *pdev)
@@ -2436,6 +2443,7 @@ static void mana_gd_remove(struct pci_dev *pdev)
pci_iounmap(pdev, gc->bar0_va);
+ pci_set_drvdata(pdev, NULL);
vfree(gc);
pci_release_regions(pdev);
--
2.34.1