diff options
author | Johannes Berg <johannes.berg@intel.com> | 2023-12-07 04:50:11 +0200 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2023-12-12 10:37:00 +0100 |
commit | 47b17879f9837d317a0f9e3203b9231fea82b018 (patch) | |
tree | b9c0c0d3fee92a68e62d3b3f5f2c75e0177633e0 | |
parent | 268712dc3b344f3a835211e5846e6ebfd7a13cbd (diff) |
wifi: iwlwifi: pcie: clean up device removal work
We shouldn't access the device if we don't hold a reference,
and if - after locking - we see that it has no bus, we also
can't do anything, in fact, pci_stop_and_remove_bus_device()
will be a no-op.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://msgid.link/20231207044813.6c0879e695f7.I1d3ce75ecad32a4cbf1b9dad61bfb7bc7821fdd9@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 19 |
1 files changed, 15 insertions, 4 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index a468e5efeecd..31a6e34b33ff 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2107,18 +2107,29 @@ static void iwl_trans_pcie_removal_wk(struct work_struct *wk) container_of(wk, struct iwl_trans_pcie_removal, work); struct pci_dev *pdev = removal->pdev; static char *prop[] = {"EVENT=INACCESSIBLE", NULL}; - struct pci_bus *bus = pdev->bus; + struct pci_bus *bus; + + pci_lock_rescan_remove(); + + bus = pdev->bus; + /* in this case, something else already removed the device */ + if (!bus) + goto out; dev_err(&pdev->dev, "Device gone - attempting removal\n"); + kobject_uevent_env(&pdev->dev.kobj, KOBJ_CHANGE, prop); - pci_lock_rescan_remove(); - pci_dev_put(pdev); + pci_stop_and_remove_bus_device(pdev); - if (removal->rescan && bus) { + pci_dev_put(pdev); + + if (removal->rescan) { if (bus->parent) bus = bus->parent; pci_rescan_bus(bus); } + +out: pci_unlock_rescan_remove(); kfree(removal); |