@@ -2517,7 +2517,7 @@ static void pci_set_msi_domain(struct pci_dev *dev)
dev_set_msi_domain(&dev->dev, d);
}
-void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
+int pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
{
int ret;
@@ -2552,7 +2552,8 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
up_write(&pci_bus_sem);
ret = pcibios_device_add(dev);
- WARN_ON(ret < 0);
+ if (WARN_ON(ret < 0))
+ goto err;
/* Set up MSI IRQ domain */
pci_set_msi_domain(dev);
@@ -2560,7 +2561,16 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
/* Notifier could use PCI capabilities */
dev->match_driver = false;
ret = device_add(&dev->dev);
- WARN_ON(ret < 0);
+ if (WARN_ON(ret < 0))
+ goto err;
+
+ return 0;
+
+err:
+ down_write(&pci_bus_sem);
+ list_del(&dev->bus_list);
+ up_write(&pci_bus_sem);
+ return ret;
}
struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn)
@@ -2577,7 +2587,10 @@ struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn)
if (!dev)
return NULL;
- pci_device_add(dev, bus);
+ if (pci_device_add(dev, bus)) {
+ pci_dev_put(dev);
+ return NULL;
+ }
return dev;
}
@@ -1124,7 +1124,7 @@ static inline void pci_dev_assign_slot(struct pci_dev *dev) { }
#endif
int pci_scan_slot(struct pci_bus *bus, int devfn);
struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn);
-void pci_device_add(struct pci_dev *dev, struct pci_bus *bus);
+int pci_device_add(struct pci_dev *dev, struct pci_bus *bus);
unsigned int pci_scan_child_bus(struct pci_bus *bus);
void pci_bus_add_device(struct pci_dev *dev);
void pci_read_bridge_bases(struct pci_bus *child);
After commit 4f535093cf8f ("PCI: Put pci_dev in device tree as early as possible"), pcibios_add_device() and device_add() are moved to pci_device_add(), and it never return error code in error cases. If pcibios_device_add() or device_add() returns error in pci_device_add(), the 'dev->p' is not set which will lead null-ptr-deref in device_attach() called by pci_bus_add_device(). Change return type of pci_device_add() to int, and handle error in it if pcibios_device_add() or device_add() fails. So callers can check the return value and handle it. Fixes: 4f535093cf8f ("PCI: Put pci_dev in device tree as early as possible") Signed-off-by: Yang Yingliang <yangyingliang@huawei.com> --- drivers/pci/probe.c | 21 +++++++++++++++++---- include/linux/pci.h | 2 +- 2 files changed, 18 insertions(+), 5 deletions(-)