* [RFC PATCH 0/5] PCI: introduce hotplug safe bus searching interfaces @ 2012-03-11 17:48 Jiang Liu 2012-03-11 17:48 ` [PATCH 1/5] Fix device reference count leakage in pci_dev_present() Jiang Liu ` (4 more replies) 0 siblings, 5 replies; 11+ messages in thread From: Jiang Liu @ 2012-03-11 17:48 UTC (permalink / raw) To: Yinghai Lu, Jesse Barnes, Bjorn Helgaas Cc: Jiang Liu, Ashok Raj, Suresh Siddha, Youquan Song, linux-pci, linux-kernel, chenkeping This patchset is based on Yinghai's pci root bus hotplug v2, please refer to: http://www.spinics.net/lists/linux-pci/msg14194.html. The first three patches are minor bug fixes against the pci root bus hotplug code. The forth/fifth is a proposal to introduce a series of pci hotplug safe interfaces to search pci buses. This is aimed to solve possible race conditions when doing pci root bus/pci bus hotplug. The proposal is here to show the idea, and hasn't been fully tested yet. If it's on the right way, I will refine it and do thorough tests. Jiang Liu (5): Fix device reference count leakage in pci_dev_present() Correctly clean up pci root buses in function pci_remove_bus() Fix an access-after-free issue in function pci_stop_and_remove_bus() Introduce hotplug-safe pci bus searching interfaces Replace old pci bus searching function calls with hotplug safe ones arch/frv/mb93090-mb00/pci-vdk.c | 2 +- arch/x86/pci/common.c | 9 +- arch/x86/pci/irq.c | 2 +- arch/x86/pci/legacy.c | 2 +- drivers/acpi/pci_root.c | 2 +- drivers/acpi/pci_root_hp.c | 2 +- drivers/acpi/pci_slot.c | 6 +- drivers/acpi/reboot.c | 3 +- drivers/edac/i7core_edac.c | 2 +- drivers/gpu/vga/vgaarb.c | 3 +- drivers/iommu/dmar.c | 6 +- drivers/pci/bus.c | 20 ++++- drivers/pci/hotplug/cpci_hotplug_pci.c | 4 +- drivers/pci/hotplug/ibmphp_core.c | 8 +- drivers/pci/hotplug/sgi_hotplug.c | 3 +- drivers/pci/hotplug/shpchp_pci.c | 4 +- drivers/pci/hotplug/shpchp_sysfs.c | 2 +- drivers/pci/iov.c | 6 +- drivers/pci/pci-sysfs.c | 2 +- drivers/pci/pci.c | 2 +- drivers/pci/pcie/pme.c | 16 +--- drivers/pci/probe.c | 11 ++- drivers/pci/remove.c | 15 ++-- drivers/pci/search.c | 168 ++++++++++++++++++++++++++----- drivers/pci/xen-pcifront.c | 6 +- include/linux/pci.h | 8 ++ 26 files changed, 230 insertions(+), 84 deletions(-) -- 1.7.5.4 ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/5] Fix device reference count leakage in pci_dev_present() 2012-03-11 17:48 [RFC PATCH 0/5] PCI: introduce hotplug safe bus searching interfaces Jiang Liu @ 2012-03-11 17:48 ` Jiang Liu 2012-03-11 17:48 ` [PATCH 2/5] Correctly clean up pci root buses in function pci_remove_bus() Jiang Liu ` (3 subsequent siblings) 4 siblings, 0 replies; 11+ messages in thread From: Jiang Liu @ 2012-03-11 17:48 UTC (permalink / raw) To: Yinghai Lu, Jesse Barnes, Bjorn Helgaas Cc: Jiang Liu, Ashok Raj, Suresh Siddha, Youquan Song, linux-pci, linux-kernel, chenkeping This patch fixes a pci device reference count leakage issue in function pci_dev_present(). Signed-off-by: Jiang Liu <jiang.liu@huawei.com> --- drivers/pci/search.c | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 9d75dc8..b572730 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -338,13 +338,13 @@ int pci_dev_present(const struct pci_device_id *ids) WARN_ON(in_interrupt()); while (ids->vendor || ids->subvendor || ids->class_mask) { found = pci_get_dev_by_id(ids, NULL); - if (found) - goto exit; + if (found) { + pci_dev_put(found); + return 1; + } ids++; } -exit: - if (found) - return 1; + return 0; } EXPORT_SYMBOL(pci_dev_present); -- 1.7.5.4 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/5] Correctly clean up pci root buses in function pci_remove_bus() 2012-03-11 17:48 [RFC PATCH 0/5] PCI: introduce hotplug safe bus searching interfaces Jiang Liu 2012-03-11 17:48 ` [PATCH 1/5] Fix device reference count leakage in pci_dev_present() Jiang Liu @ 2012-03-11 17:48 ` Jiang Liu 2012-03-13 6:24 ` Yinghai Lu 2012-03-11 17:48 ` [PATCH 3/5] Fix an access-after-free issue in function pci_stop_and_remove_bus() Jiang Liu ` (2 subsequent siblings) 4 siblings, 1 reply; 11+ messages in thread From: Jiang Liu @ 2012-03-11 17:48 UTC (permalink / raw) To: Yinghai Lu, Jesse Barnes, Bjorn Helgaas Cc: Jiang Liu, Ashok Raj, Suresh Siddha, Youquan Song, linux-pci, linux-kernel, chenkeping The function pci_create_root_bus() allocates the pci bus structure, registers the bus device and creates the legacy files for a pci root bus, but returns without setting the is_added flag. The is_added flag for a pci root bus will be set by function pci_scan_child_bus(). If a pci root bus is destroyed before calling pci_scan_child_bus(), the is_added flag will not be set. So teach function pci_remove_bus() to detect such a case and correctly clean up pci root buses. Signed-off-by: Jiang Liu <jiang.liu@huawei.com> --- drivers/pci/remove.c | 9 ++++----- 1 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 9ffc071..75b0092 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -70,11 +70,10 @@ void pci_remove_bus(struct pci_bus *pci_bus) list_del(&pci_bus->node); pci_bus_release_busn_res(pci_bus); up_write(&pci_bus_sem); - if (!pci_bus->is_added) - return; - - pci_remove_legacy_files(pci_bus); - device_unregister(&pci_bus->dev); + if (pci_bus->is_added || pci_is_root_bus(pci_bus)) { + pci_remove_legacy_files(pci_bus); + device_unregister(&pci_bus->dev); + } } EXPORT_SYMBOL(pci_remove_bus); -- 1.7.5.4 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 2/5] Correctly clean up pci root buses in function pci_remove_bus() 2012-03-11 17:48 ` [PATCH 2/5] Correctly clean up pci root buses in function pci_remove_bus() Jiang Liu @ 2012-03-13 6:24 ` Yinghai Lu 2012-03-13 7:23 ` Jiang Liu 0 siblings, 1 reply; 11+ messages in thread From: Yinghai Lu @ 2012-03-13 6:24 UTC (permalink / raw) To: Jiang Liu Cc: Jesse Barnes, Bjorn Helgaas, Jiang Liu, Ashok Raj, Suresh Siddha, Youquan Song, linux-pci, linux-kernel, chenkeping On Sun, Mar 11, 2012 at 10:48 AM, Jiang Liu <liuj97@gmail.com> wrote: > The function pci_create_root_bus() allocates the pci bus structure, > registers the bus device and creates the legacy files for a pci root > bus, but returns without setting the is_added flag. The is_added flag > for a pci root bus will be set by function pci_scan_child_bus(). > If a pci root bus is destroyed before calling pci_scan_child_bus(), > the is_added flag will not be set. how that can be met? Do we have pci_remove_rescan_mutex around them? Yinghai ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/5] Correctly clean up pci root buses in function pci_remove_bus() 2012-03-13 6:24 ` Yinghai Lu @ 2012-03-13 7:23 ` Jiang Liu 0 siblings, 0 replies; 11+ messages in thread From: Jiang Liu @ 2012-03-13 7:23 UTC (permalink / raw) To: Yinghai Lu Cc: Jiang Liu, Jesse Barnes, Bjorn Helgaas, Ashok Raj, Suresh Siddha, Youquan Song, linux-pci, linux-kernel, chenkeping Hi Yinghai, Good points! It's safe with current implementation because all root bus hotplug operations are under protection of pci_remove_rescan_mutex. On 2012-3-13 14:24, Yinghai Lu wrote: > On Sun, Mar 11, 2012 at 10:48 AM, Jiang Liu<liuj97@gmail.com> wrote: >> The function pci_create_root_bus() allocates the pci bus structure, >> registers the bus device and creates the legacy files for a pci root >> bus, but returns without setting the is_added flag. The is_added flag >> for a pci root bus will be set by function pci_scan_child_bus(). > >> If a pci root bus is destroyed before calling pci_scan_child_bus(), >> the is_added flag will not be set. > > how that can be met? > > Do we have pci_remove_rescan_mutex around them? > > Yinghai > > ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 3/5] Fix an access-after-free issue in function pci_stop_and_remove_bus() 2012-03-11 17:48 [RFC PATCH 0/5] PCI: introduce hotplug safe bus searching interfaces Jiang Liu 2012-03-11 17:48 ` [PATCH 1/5] Fix device reference count leakage in pci_dev_present() Jiang Liu 2012-03-11 17:48 ` [PATCH 2/5] Correctly clean up pci root buses in function pci_remove_bus() Jiang Liu @ 2012-03-11 17:48 ` Jiang Liu 2012-03-13 3:47 ` Bjorn Helgaas 2012-03-11 17:48 ` [RFC PATCH 4/5] PCI: Introduce hotplug-safe pci bus searching interfaces Jiang Liu 2012-03-11 17:48 ` [RFC PATCH 5/5] PCI: Replace old pci bus searching function calls with hotplug safe ones Jiang Liu 4 siblings, 1 reply; 11+ messages in thread From: Jiang Liu @ 2012-03-11 17:48 UTC (permalink / raw) To: Yinghai Lu, Jesse Barnes, Bjorn Helgaas Cc: Jiang Liu, Ashok Raj, Suresh Siddha, Youquan Song, linux-pci, linux-kernel, chenkeping If pci_stop_and_remove_bus() is called to remove a pci root bus, the host_bridge structure may have already been freed after returning from pci_remove_bus(), so don't access the structure any more. Signed-off-by: Jiang Liu <jiang.liu@huawei.com> --- drivers/pci/remove.c | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 75b0092..25f368e 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -194,9 +194,6 @@ void pci_stop_and_remove_bus(struct pci_bus *bus) pci_remove_bus(bus); - if (host_bridge) - host_bridge->bus = NULL; - if (pci_bridge) pci_bridge->subordinate = NULL; } -- 1.7.5.4 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 3/5] Fix an access-after-free issue in function pci_stop_and_remove_bus() 2012-03-11 17:48 ` [PATCH 3/5] Fix an access-after-free issue in function pci_stop_and_remove_bus() Jiang Liu @ 2012-03-13 3:47 ` Bjorn Helgaas 0 siblings, 0 replies; 11+ messages in thread From: Bjorn Helgaas @ 2012-03-13 3:47 UTC (permalink / raw) To: Jiang Liu Cc: Yinghai Lu, Jesse Barnes, Jiang Liu, Ashok Raj, Suresh Siddha, Youquan Song, linux-pci, linux-kernel, chenkeping On Sun, Mar 11, 2012 at 11:48 AM, Jiang Liu <liuj97@gmail.com> wrote: > If pci_stop_and_remove_bus() is called to remove a pci root bus, > the host_bridge structure may have already been freed after returning > from pci_remove_bus(), so don't access the structure any more. pci_stop_and_remove_bus() hasn't been merged yet, so any fixes should be incorporated into Yinghai's patch that adds it. > Signed-off-by: Jiang Liu <jiang.liu@huawei.com> > --- > drivers/pci/remove.c | 3 --- > 1 files changed, 0 insertions(+), 3 deletions(-) > > diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c > index 75b0092..25f368e 100644 > --- a/drivers/pci/remove.c > +++ b/drivers/pci/remove.c > @@ -194,9 +194,6 @@ void pci_stop_and_remove_bus(struct pci_bus *bus) > > pci_remove_bus(bus); > > - if (host_bridge) > - host_bridge->bus = NULL; > - > if (pci_bridge) > pci_bridge->subordinate = NULL; > } > -- > 1.7.5.4 > ^ permalink raw reply [flat|nested] 11+ messages in thread
* [RFC PATCH 4/5] PCI: Introduce hotplug-safe pci bus searching interfaces 2012-03-11 17:48 [RFC PATCH 0/5] PCI: introduce hotplug safe bus searching interfaces Jiang Liu ` (2 preceding siblings ...) 2012-03-11 17:48 ` [PATCH 3/5] Fix an access-after-free issue in function pci_stop_and_remove_bus() Jiang Liu @ 2012-03-11 17:48 ` Jiang Liu 2012-03-13 3:49 ` Bjorn Helgaas 2012-03-11 17:48 ` [RFC PATCH 5/5] PCI: Replace old pci bus searching function calls with hotplug safe ones Jiang Liu 4 siblings, 1 reply; 11+ messages in thread From: Jiang Liu @ 2012-03-11 17:48 UTC (permalink / raw) To: Yinghai Lu, Jesse Barnes, Bjorn Helgaas Cc: Jiang Liu, Ashok Raj, Suresh Siddha, Youquan Song, linux-pci, linux-kernel, chenkeping By design, pci_find_bus() and pci_find_next_bus() should be used at boot time only. But currently these two interfaces have been used at runtime by other components. With the introduction of pci root bus hotplug, the situation becomes more serious. So introduce several hotplug-safe pci bus searching interfaces to be used at runtime. The new interfaces use rculist instead of the pci_bus_sem to protect themselves from dynamic changes. The proposed interfaces are straight-forward replacement of the old ones: pci_bus_get()/put(), pci_get_bus(), pci_get_next_bus() and pci_bus_present(). And the old interface may be deprecated or marked as __init in future. Signed-off-by: Jiang Liu <jiang.liu@huawei.com> --- drivers/pci/bus.c | 20 ++++++- drivers/pci/probe.c | 5 +- drivers/pci/remove.c | 5 +- drivers/pci/search.c | 165 ++++++++++++++++++++++++++++++++++++++++++-------- include/linux/pci.h | 8 +++ 5 files changed, 173 insertions(+), 30 deletions(-) diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 1eb7944..0543d47 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -15,6 +15,7 @@ #include <linux/proc_fs.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/rculist.h> #include "pci.h" @@ -238,7 +239,7 @@ void pci_bus_add_devices(const struct pci_bus *bus) continue; if (list_empty(&child->node)) { down_write(&pci_bus_sem); - list_add_tail(&child->node, &dev->bus->children); + list_add_tail_rcu(&child->node, &dev->bus->children); up_write(&pci_bus_sem); } pci_bus_add_devices(child); @@ -277,7 +278,7 @@ void pci_bus_add_single_device(struct pci_dev *dev) if (child) { if (list_empty(&child->node)) { down_write(&pci_bus_sem); - list_add_tail(&child->node, &dev->bus->children); + list_add_tail_rcu(&child->node, &dev->bus->children); up_write(&pci_bus_sem); } pci_bus_add_devices(child); @@ -364,6 +365,21 @@ void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), } EXPORT_SYMBOL_GPL(pci_walk_bus); +struct pci_bus *pci_bus_get(struct pci_bus *bus) +{ + if (bus) + get_device(&bus->dev); + return bus; +} +EXPORT_SYMBOL(pci_bus_get); + +void pci_bus_put(struct pci_bus *bus) +{ + if (bus) + put_device(&bus->dev); +} +EXPORT_SYMBOL(pci_bus_put); + EXPORT_SYMBOL(pci_bus_alloc_resource); EXPORT_SYMBOL_GPL(pci_bus_add_device); EXPORT_SYMBOL(pci_bus_add_devices); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 0ca213c..273c387 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -10,6 +10,7 @@ #include <linux/module.h> #include <linux/cpumask.h> #include <linux/pci-aspm.h> +#include <linux/rculist.h> #include "pci.h" #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ @@ -633,7 +634,7 @@ struct pci_bus *__ref pci_add_new_bus(struct pci_bus *parent, struct pci_dev *de child = pci_alloc_child_bus(parent, dev, busnr); if (child) { down_write(&pci_bus_sem); - list_add_tail(&child->node, &parent->children); + list_add_tail_rcu(&child->node, &parent->children); up_write(&pci_bus_sem); } return child; @@ -1889,7 +1890,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, } down_write(&pci_bus_sem); - list_add_tail(&b->node, &pci_root_buses); + list_add_tail_rcu(&b->node, &pci_root_buses); up_write(&pci_bus_sem); return b; diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 25f368e..120bee9 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -1,6 +1,7 @@ #include <linux/pci.h> #include <linux/module.h> #include <linux/pci-aspm.h> +#include <linux/rculist.h> #include "pci.h" static void pci_free_resources(struct pci_dev *dev) @@ -67,9 +68,11 @@ void pci_remove_bus(struct pci_bus *pci_bus) pci_proc_detach_bus(pci_bus); down_write(&pci_bus_sem); - list_del(&pci_bus->node); + list_del_rcu(&pci_bus->node); pci_bus_release_busn_res(pci_bus); up_write(&pci_bus_sem); + synchronize_rcu(); + if (pci_bus->is_added || pci_is_root_bus(pci_bus)) { pci_remove_legacy_files(pci_bus); device_unregister(&pci_bus->dev); diff --git a/drivers/pci/search.c b/drivers/pci/search.c index b572730..de31957 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -12,6 +12,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/interrupt.h> +#include <linux/rculist.h> #include "pci.h" DECLARE_RWSEM(pci_bus_sem); @@ -52,20 +53,63 @@ pci_find_upstream_pcie_bridge(struct pci_dev *pdev) static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr) { - struct pci_bus* child; - struct list_head *tmp; + struct pci_bus *child; + struct pci_bus *tmp_bus; if(bus->number == busnr) return bus; - list_for_each(tmp, &bus->children) { - child = pci_do_find_bus(pci_bus_b(tmp), busnr); - if(child) - return child; + list_for_each_entry_rcu(child, &bus->children, node) { + tmp_bus = pci_do_find_bus(child, busnr); + if(tmp_bus) + return tmp_bus; } return NULL; } +static struct pci_bus *__pci_find_bus(int domain, int busnr) +{ + struct pci_bus *bus; + struct pci_bus *tmp_bus; + + list_for_each_entry_rcu(bus, &pci_root_buses, node) { + if (pci_domain_nr(bus) != domain) + continue; + tmp_bus = pci_do_find_bus(bus, busnr); + if (tmp_bus) + return tmp_bus; + } + + return NULL; +} + +static struct pci_bus *__pci_find_next_bus(const struct pci_bus *from) +{ + struct list_head *n; + struct pci_bus *b = NULL; + + /* First search, start from the pci root bus list */ + if (from == NULL) { + n = rcu_dereference(list_next_rcu(&pci_root_buses)); + if (n != &pci_root_buses) + b = pci_bus_b(n); + /* Continue on the pci root bus list */ + } else if (pci_is_root_bus((struct pci_bus *)from)) { + n = rcu_dereference(list_next_rcu(&from->node)); + if (n != &pci_root_buses) + b = pci_bus_b(n); + /* Continue on other non pci root bus list */ + } else { + struct pci_bus *parent = from->self->bus; + + n = rcu_dereference(list_next_rcu(&from->node)); + if (n != &parent->children) + b = pci_bus_b(n); + } + + return b; +} + /** * pci_find_bus - locate PCI bus from a given domain and bus number * @domain: number of PCI domain to search @@ -74,20 +118,19 @@ static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr) * Given a PCI bus number and domain number, the desired PCI bus is located * in the global list of PCI buses. If the bus is found, a pointer to its * data structure is returned. If no bus is found, %NULL is returned. + * + * TODO: By design, this function should only be called at boot time. + * So either mark it as __init or deprecate it. */ struct pci_bus * pci_find_bus(int domain, int busnr) { - struct pci_bus *bus = NULL; - struct pci_bus *tmp_bus; + struct pci_bus *bus; - while ((bus = pci_find_next_bus(bus)) != NULL) { - if (pci_domain_nr(bus) != domain) - continue; - tmp_bus = pci_do_find_bus(bus, busnr); - if (tmp_bus) - return tmp_bus; - } - return NULL; + rcu_read_lock(); + bus = __pci_find_bus(domain, busnr); + rcu_read_unlock(); + + return bus; } /** @@ -98,21 +141,93 @@ struct pci_bus * pci_find_bus(int domain, int busnr) * initiated by passing %NULL as the @from argument. Otherwise if * @from is not %NULL, searches continue from next device on the * global list. + * + * TODO: By design, this function should only be called at boot time. + * So either mark it as __init or deprecate it. */ struct pci_bus * pci_find_next_bus(const struct pci_bus *from) { - struct list_head *n; - struct pci_bus *b = NULL; + struct pci_bus *bus; - WARN_ON(in_interrupt()); - down_read(&pci_bus_sem); - n = from ? from->node.next : pci_root_buses.next; - if (n != &pci_root_buses) - b = pci_bus_b(n); - up_read(&pci_bus_sem); - return b; + rcu_read_lock(); + bus = __pci_find_next_bus(from); + rcu_read_unlock(); + + return bus; +} + +/** + * pci_get_bus - locate PCI bus from a given domain and bus number + * @domain: number of PCI domain to search + * @busnr: number of desired PCI bus + * + * Given a PCI bus number and domain number, the desired PCI bus is located + * in the global list of PCI buses. If the bus is found, a pointer to its + * data structure is returned, and the reference count to the bus is increased. + * Otherwise, %NULL is returned. + */ +struct pci_bus * +pci_get_bus(int domain, int busnr) +{ + struct pci_bus *bus; + + rcu_read_lock(); + bus = pci_bus_get(__pci_find_bus(domain, busnr)); + rcu_read_unlock(); + + return bus; +} +EXPORT_SYMBOL(pci_get_bus); + +/** + * pci_get_next_bus - begin or continue searching for a PCI bus + * @from: Previous PCI bus found, or %NULL for new search. + * + * Iterates through the list of known PCI busses. A new search is + * initiated by passing %NULL as the @from argument. Otherwise if + * @from is not %NULL, searches continue from next device on the + * global list. If a bus is found, a pointer to its data structure + * is returned, and the reference count to the bus is increased. + * Otherwise, %NULL is returned. + * The reference count for @from is always decremented if it is not %NULL. + */ +struct pci_bus * +pci_get_next_bus(struct pci_bus *from) +{ + struct pci_bus *bus; + + rcu_read_lock(); + bus = pci_bus_get(__pci_find_next_bus(from)); + rcu_read_unlock(); + + return bus; +} +EXPORT_SYMBOL(pci_get_next_bus); + +/** + * pci_bus_present - Returns true if a bus with the (@domain, @busnr) + * is present, false if not. + * @domain: number of PCI domain to search + * @busnr: number of desired PCI bus + * + * Obvious fact: You do not have a reference to any bus that might be found + * by this function, so if that bus is removed from the system right after + * this function is finished, the value will be stale. Use this function to + * find buses that are usually built into a system, or for a general hint as + * to if another device happens to be present at this specific moment in time. + */ +bool pci_bus_present(int domain, int busnr) +{ + struct pci_bus *bus; + + rcu_read_lock(); + bus = __pci_find_bus(domain, busnr); + rcu_read_unlock(); + + return !!bus; } +EXPORT_SYMBOL(pci_bus_present); /** * pci_get_slot - locate PCI device for a given PCI slot diff --git a/include/linux/pci.h b/include/linux/pci.h index ec8c4cf..222bc88 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -731,6 +731,11 @@ int pci_find_ht_capability(struct pci_dev *dev, int ht_cap); int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap); struct pci_bus *pci_find_next_bus(const struct pci_bus *from); +struct pci_bus *pci_bus_get(struct pci_bus *bus); +void pci_bus_put(struct pci_bus *bus); +struct pci_bus *pci_get_bus(int domain, int busnr); +struct pci_bus *pci_get_next_bus(struct pci_bus *from); +bool pci_bus_present(int domain, int busnr); struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from); struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device, @@ -1321,6 +1326,9 @@ static inline void pci_unblock_cfg_access(struct pci_dev *dev) static inline struct pci_bus *pci_find_next_bus(const struct pci_bus *from) { return NULL; } +static inline struct pci_bus *pci_get_next_bus(const struct pci_bus *from) +{ return NULL; } + static inline struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn) { return NULL; } -- 1.7.5.4 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [RFC PATCH 4/5] PCI: Introduce hotplug-safe pci bus searching interfaces 2012-03-11 17:48 ` [RFC PATCH 4/5] PCI: Introduce hotplug-safe pci bus searching interfaces Jiang Liu @ 2012-03-13 3:49 ` Bjorn Helgaas 2012-03-13 8:13 ` Jiang Liu 0 siblings, 1 reply; 11+ messages in thread From: Bjorn Helgaas @ 2012-03-13 3:49 UTC (permalink / raw) To: Jiang Liu Cc: Yinghai Lu, Jesse Barnes, Jiang Liu, Ashok Raj, Suresh Siddha, Youquan Song, linux-pci, linux-kernel, chenkeping On Sun, Mar 11, 2012 at 11:48 AM, Jiang Liu <liuj97@gmail.com> wrote: > By design, pci_find_bus() and pci_find_next_bus() should be used at boot > time only. But currently these two interfaces have been used at runtime > by other components. With the introduction of pci root bus hotplug, > the situation becomes more serious. So introduce several hotplug-safe pci > bus searching interfaces to be used at runtime. The new interfaces use > rculist instead of the pci_bus_sem to protect themselves from dynamic changes. > The proposed interfaces are straight-forward replacement of the old ones: > pci_bus_get()/put(), pci_get_bus(), pci_get_next_bus() and pci_bus_present(). > And the old interface may be deprecated or marked as __init in future. This looks like a lot of work to fix something that shouldn't need to be fixed. I don't think we should be doing any of this blind probing at hotplug-time. If we do blind probing at all, it should only be done at boot-time. > Signed-off-by: Jiang Liu <jiang.liu@huawei.com> > --- > drivers/pci/bus.c | 20 ++++++- > drivers/pci/probe.c | 5 +- > drivers/pci/remove.c | 5 +- > drivers/pci/search.c | 165 ++++++++++++++++++++++++++++++++++++++++++-------- > include/linux/pci.h | 8 +++ > 5 files changed, 173 insertions(+), 30 deletions(-) > > diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c > index 1eb7944..0543d47 100644 > --- a/drivers/pci/bus.c > +++ b/drivers/pci/bus.c > @@ -15,6 +15,7 @@ > #include <linux/proc_fs.h> > #include <linux/init.h> > #include <linux/slab.h> > +#include <linux/rculist.h> > > #include "pci.h" > > @@ -238,7 +239,7 @@ void pci_bus_add_devices(const struct pci_bus *bus) > continue; > if (list_empty(&child->node)) { > down_write(&pci_bus_sem); > - list_add_tail(&child->node, &dev->bus->children); > + list_add_tail_rcu(&child->node, &dev->bus->children); > up_write(&pci_bus_sem); > } > pci_bus_add_devices(child); > @@ -277,7 +278,7 @@ void pci_bus_add_single_device(struct pci_dev *dev) > if (child) { > if (list_empty(&child->node)) { > down_write(&pci_bus_sem); > - list_add_tail(&child->node, &dev->bus->children); > + list_add_tail_rcu(&child->node, &dev->bus->children); > up_write(&pci_bus_sem); > } > pci_bus_add_devices(child); > @@ -364,6 +365,21 @@ void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), > } > EXPORT_SYMBOL_GPL(pci_walk_bus); > > +struct pci_bus *pci_bus_get(struct pci_bus *bus) > +{ > + if (bus) > + get_device(&bus->dev); > + return bus; > +} > +EXPORT_SYMBOL(pci_bus_get); > + > +void pci_bus_put(struct pci_bus *bus) > +{ > + if (bus) > + put_device(&bus->dev); > +} > +EXPORT_SYMBOL(pci_bus_put); > + > EXPORT_SYMBOL(pci_bus_alloc_resource); > EXPORT_SYMBOL_GPL(pci_bus_add_device); > EXPORT_SYMBOL(pci_bus_add_devices); > diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c > index 0ca213c..273c387 100644 > --- a/drivers/pci/probe.c > +++ b/drivers/pci/probe.c > @@ -10,6 +10,7 @@ > #include <linux/module.h> > #include <linux/cpumask.h> > #include <linux/pci-aspm.h> > +#include <linux/rculist.h> > #include "pci.h" > > #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ > @@ -633,7 +634,7 @@ struct pci_bus *__ref pci_add_new_bus(struct pci_bus *parent, struct pci_dev *de > child = pci_alloc_child_bus(parent, dev, busnr); > if (child) { > down_write(&pci_bus_sem); > - list_add_tail(&child->node, &parent->children); > + list_add_tail_rcu(&child->node, &parent->children); > up_write(&pci_bus_sem); > } > return child; > @@ -1889,7 +1890,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, > } > > down_write(&pci_bus_sem); > - list_add_tail(&b->node, &pci_root_buses); > + list_add_tail_rcu(&b->node, &pci_root_buses); > up_write(&pci_bus_sem); > > return b; > diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c > index 25f368e..120bee9 100644 > --- a/drivers/pci/remove.c > +++ b/drivers/pci/remove.c > @@ -1,6 +1,7 @@ > #include <linux/pci.h> > #include <linux/module.h> > #include <linux/pci-aspm.h> > +#include <linux/rculist.h> > #include "pci.h" > > static void pci_free_resources(struct pci_dev *dev) > @@ -67,9 +68,11 @@ void pci_remove_bus(struct pci_bus *pci_bus) > pci_proc_detach_bus(pci_bus); > > down_write(&pci_bus_sem); > - list_del(&pci_bus->node); > + list_del_rcu(&pci_bus->node); > pci_bus_release_busn_res(pci_bus); > up_write(&pci_bus_sem); > + synchronize_rcu(); > + > if (pci_bus->is_added || pci_is_root_bus(pci_bus)) { > pci_remove_legacy_files(pci_bus); > device_unregister(&pci_bus->dev); > diff --git a/drivers/pci/search.c b/drivers/pci/search.c > index b572730..de31957 100644 > --- a/drivers/pci/search.c > +++ b/drivers/pci/search.c > @@ -12,6 +12,7 @@ > #include <linux/slab.h> > #include <linux/module.h> > #include <linux/interrupt.h> > +#include <linux/rculist.h> > #include "pci.h" > > DECLARE_RWSEM(pci_bus_sem); > @@ -52,20 +53,63 @@ pci_find_upstream_pcie_bridge(struct pci_dev *pdev) > > static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr) > { > - struct pci_bus* child; > - struct list_head *tmp; > + struct pci_bus *child; > + struct pci_bus *tmp_bus; > > if(bus->number == busnr) > return bus; > > - list_for_each(tmp, &bus->children) { > - child = pci_do_find_bus(pci_bus_b(tmp), busnr); > - if(child) > - return child; > + list_for_each_entry_rcu(child, &bus->children, node) { > + tmp_bus = pci_do_find_bus(child, busnr); > + if(tmp_bus) > + return tmp_bus; > } > return NULL; > } > > +static struct pci_bus *__pci_find_bus(int domain, int busnr) > +{ > + struct pci_bus *bus; > + struct pci_bus *tmp_bus; > + > + list_for_each_entry_rcu(bus, &pci_root_buses, node) { > + if (pci_domain_nr(bus) != domain) > + continue; > + tmp_bus = pci_do_find_bus(bus, busnr); > + if (tmp_bus) > + return tmp_bus; > + } > + > + return NULL; > +} > + > +static struct pci_bus *__pci_find_next_bus(const struct pci_bus *from) > +{ > + struct list_head *n; > + struct pci_bus *b = NULL; > + > + /* First search, start from the pci root bus list */ > + if (from == NULL) { > + n = rcu_dereference(list_next_rcu(&pci_root_buses)); > + if (n != &pci_root_buses) > + b = pci_bus_b(n); > + /* Continue on the pci root bus list */ > + } else if (pci_is_root_bus((struct pci_bus *)from)) { > + n = rcu_dereference(list_next_rcu(&from->node)); > + if (n != &pci_root_buses) > + b = pci_bus_b(n); > + /* Continue on other non pci root bus list */ > + } else { > + struct pci_bus *parent = from->self->bus; > + > + n = rcu_dereference(list_next_rcu(&from->node)); > + if (n != &parent->children) > + b = pci_bus_b(n); > + } > + > + return b; > +} > + > /** > * pci_find_bus - locate PCI bus from a given domain and bus number > * @domain: number of PCI domain to search > @@ -74,20 +118,19 @@ static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr) > * Given a PCI bus number and domain number, the desired PCI bus is located > * in the global list of PCI buses. If the bus is found, a pointer to its > * data structure is returned. If no bus is found, %NULL is returned. > + * > + * TODO: By design, this function should only be called at boot time. > + * So either mark it as __init or deprecate it. > */ > struct pci_bus * pci_find_bus(int domain, int busnr) > { > - struct pci_bus *bus = NULL; > - struct pci_bus *tmp_bus; > + struct pci_bus *bus; > > - while ((bus = pci_find_next_bus(bus)) != NULL) { > - if (pci_domain_nr(bus) != domain) > - continue; > - tmp_bus = pci_do_find_bus(bus, busnr); > - if (tmp_bus) > - return tmp_bus; > - } > - return NULL; > + rcu_read_lock(); > + bus = __pci_find_bus(domain, busnr); > + rcu_read_unlock(); > + > + return bus; > } > > /** > @@ -98,21 +141,93 @@ struct pci_bus * pci_find_bus(int domain, int busnr) > * initiated by passing %NULL as the @from argument. Otherwise if > * @from is not %NULL, searches continue from next device on the > * global list. > + * > + * TODO: By design, this function should only be called at boot time. > + * So either mark it as __init or deprecate it. > */ > struct pci_bus * > pci_find_next_bus(const struct pci_bus *from) > { > - struct list_head *n; > - struct pci_bus *b = NULL; > + struct pci_bus *bus; > > - WARN_ON(in_interrupt()); > - down_read(&pci_bus_sem); > - n = from ? from->node.next : pci_root_buses.next; > - if (n != &pci_root_buses) > - b = pci_bus_b(n); > - up_read(&pci_bus_sem); > - return b; > + rcu_read_lock(); > + bus = __pci_find_next_bus(from); > + rcu_read_unlock(); > + > + return bus; > +} > + > +/** > + * pci_get_bus - locate PCI bus from a given domain and bus number > + * @domain: number of PCI domain to search > + * @busnr: number of desired PCI bus > + * > + * Given a PCI bus number and domain number, the desired PCI bus is located > + * in the global list of PCI buses. If the bus is found, a pointer to its > + * data structure is returned, and the reference count to the bus is increased. > + * Otherwise, %NULL is returned. > + */ > +struct pci_bus * > +pci_get_bus(int domain, int busnr) > +{ > + struct pci_bus *bus; > + > + rcu_read_lock(); > + bus = pci_bus_get(__pci_find_bus(domain, busnr)); > + rcu_read_unlock(); > + > + return bus; > +} > +EXPORT_SYMBOL(pci_get_bus); > + > +/** > + * pci_get_next_bus - begin or continue searching for a PCI bus > + * @from: Previous PCI bus found, or %NULL for new search. > + * > + * Iterates through the list of known PCI busses. A new search is > + * initiated by passing %NULL as the @from argument. Otherwise if > + * @from is not %NULL, searches continue from next device on the > + * global list. If a bus is found, a pointer to its data structure > + * is returned, and the reference count to the bus is increased. > + * Otherwise, %NULL is returned. > + * The reference count for @from is always decremented if it is not %NULL. > + */ > +struct pci_bus * > +pci_get_next_bus(struct pci_bus *from) > +{ > + struct pci_bus *bus; > + > + rcu_read_lock(); > + bus = pci_bus_get(__pci_find_next_bus(from)); > + rcu_read_unlock(); > + > + return bus; > +} > +EXPORT_SYMBOL(pci_get_next_bus); > + > +/** > + * pci_bus_present - Returns true if a bus with the (@domain, @busnr) > + * is present, false if not. > + * @domain: number of PCI domain to search > + * @busnr: number of desired PCI bus > + * > + * Obvious fact: You do not have a reference to any bus that might be found > + * by this function, so if that bus is removed from the system right after > + * this function is finished, the value will be stale. Use this function to > + * find buses that are usually built into a system, or for a general hint as > + * to if another device happens to be present at this specific moment in time. > + */ > +bool pci_bus_present(int domain, int busnr) > +{ > + struct pci_bus *bus; > + > + rcu_read_lock(); > + bus = __pci_find_bus(domain, busnr); > + rcu_read_unlock(); > + > + return !!bus; > } > +EXPORT_SYMBOL(pci_bus_present); > > /** > * pci_get_slot - locate PCI device for a given PCI slot > diff --git a/include/linux/pci.h b/include/linux/pci.h > index ec8c4cf..222bc88 100644 > --- a/include/linux/pci.h > +++ b/include/linux/pci.h > @@ -731,6 +731,11 @@ int pci_find_ht_capability(struct pci_dev *dev, int ht_cap); > int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap); > struct pci_bus *pci_find_next_bus(const struct pci_bus *from); > > +struct pci_bus *pci_bus_get(struct pci_bus *bus); > +void pci_bus_put(struct pci_bus *bus); > +struct pci_bus *pci_get_bus(int domain, int busnr); > +struct pci_bus *pci_get_next_bus(struct pci_bus *from); > +bool pci_bus_present(int domain, int busnr); > struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, > struct pci_dev *from); > struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device, > @@ -1321,6 +1326,9 @@ static inline void pci_unblock_cfg_access(struct pci_dev *dev) > static inline struct pci_bus *pci_find_next_bus(const struct pci_bus *from) > { return NULL; } > > +static inline struct pci_bus *pci_get_next_bus(const struct pci_bus *from) > +{ return NULL; } > + > static inline struct pci_dev *pci_get_slot(struct pci_bus *bus, > unsigned int devfn) > { return NULL; } > -- > 1.7.5.4 > ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RFC PATCH 4/5] PCI: Introduce hotplug-safe pci bus searching interfaces 2012-03-13 3:49 ` Bjorn Helgaas @ 2012-03-13 8:13 ` Jiang Liu 0 siblings, 0 replies; 11+ messages in thread From: Jiang Liu @ 2012-03-13 8:13 UTC (permalink / raw) To: Bjorn Helgaas Cc: Jiang Liu, Yinghai Lu, Jesse Barnes, Ashok Raj, Suresh Siddha, Youquan Song, linux-pci, linux-kernel, chenkeping Hi Bjorn, As you have mentioned, for most cases they are safe to use pci_find_bus()/pci_find_next_bus(), as in following cases: 1) invoked by platform specific code during boot because it's single-threaded. 2) invoked by hotplug driver because hotplug driver has serialization mechanism. 3) invoked by driver has platform specific knowledge After scanning the kernel source code, I have fount two cases which can't be covered by above scenario. The first case is that PCIe PME driver invokes pci_find_bus() when handling PME events. The second case is that i7core_edac driver invokes pci_find_next_bus() from its probe method. AFAICT there's no mechanism to protect these two cases from hotplug operations currently. Bjorn, you are right. I'm a little over-reacting here. The better solution here should be keeping the original pci_find_bus/pci_find_next_bus usage model and only introducing new mechanism to protect the above two cases. By that way, the code change will be much more smaller. Thanks! On 2012-3-13 11:49, Bjorn Helgaas wrote: > On Sun, Mar 11, 2012 at 11:48 AM, Jiang Liu<liuj97@gmail.com> wrote: >> By design, pci_find_bus() and pci_find_next_bus() should be used at boot >> time only. But currently these two interfaces have been used at runtime >> by other components. With the introduction of pci root bus hotplug, >> the situation becomes more serious. So introduce several hotplug-safe pci >> bus searching interfaces to be used at runtime. The new interfaces use >> rculist instead of the pci_bus_sem to protect themselves from dynamic changes. >> The proposed interfaces are straight-forward replacement of the old ones: >> pci_bus_get()/put(), pci_get_bus(), pci_get_next_bus() and pci_bus_present(). >> And the old interface may be deprecated or marked as __init in future. > > This looks like a lot of work to fix something that shouldn't need to > be fixed. I don't think we should be doing any of this blind probing > at hotplug-time. If we do blind probing at all, it should only be > done at boot-time. > >> Signed-off-by: Jiang Liu<jiang.liu@huawei.com> >> --- >> drivers/pci/bus.c | 20 ++++++- >> drivers/pci/probe.c | 5 +- >> drivers/pci/remove.c | 5 +- >> drivers/pci/search.c | 165 ++++++++++++++++++++++++++++++++++++++++++-------- >> include/linux/pci.h | 8 +++ >> 5 files changed, 173 insertions(+), 30 deletions(-) >> >> diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c >> index 1eb7944..0543d47 100644 >> --- a/drivers/pci/bus.c >> +++ b/drivers/pci/bus.c >> @@ -15,6 +15,7 @@ >> #include<linux/proc_fs.h> >> #include<linux/init.h> >> #include<linux/slab.h> >> +#include<linux/rculist.h> >> >> #include "pci.h" >> >> @@ -238,7 +239,7 @@ void pci_bus_add_devices(const struct pci_bus *bus) >> continue; >> if (list_empty(&child->node)) { >> down_write(&pci_bus_sem); >> - list_add_tail(&child->node,&dev->bus->children); >> + list_add_tail_rcu(&child->node,&dev->bus->children); >> up_write(&pci_bus_sem); >> } >> pci_bus_add_devices(child); >> @@ -277,7 +278,7 @@ void pci_bus_add_single_device(struct pci_dev *dev) >> if (child) { >> if (list_empty(&child->node)) { >> down_write(&pci_bus_sem); >> - list_add_tail(&child->node,&dev->bus->children); >> + list_add_tail_rcu(&child->node,&dev->bus->children); >> up_write(&pci_bus_sem); >> } >> pci_bus_add_devices(child); >> @@ -364,6 +365,21 @@ void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), >> } >> EXPORT_SYMBOL_GPL(pci_walk_bus); >> >> +struct pci_bus *pci_bus_get(struct pci_bus *bus) >> +{ >> + if (bus) >> + get_device(&bus->dev); >> + return bus; >> +} >> +EXPORT_SYMBOL(pci_bus_get); >> + >> +void pci_bus_put(struct pci_bus *bus) >> +{ >> + if (bus) >> + put_device(&bus->dev); >> +} >> +EXPORT_SYMBOL(pci_bus_put); >> + >> EXPORT_SYMBOL(pci_bus_alloc_resource); >> EXPORT_SYMBOL_GPL(pci_bus_add_device); >> EXPORT_SYMBOL(pci_bus_add_devices); >> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c >> index 0ca213c..273c387 100644 >> --- a/drivers/pci/probe.c >> +++ b/drivers/pci/probe.c >> @@ -10,6 +10,7 @@ >> #include<linux/module.h> >> #include<linux/cpumask.h> >> #include<linux/pci-aspm.h> >> +#include<linux/rculist.h> >> #include "pci.h" >> >> #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ >> @@ -633,7 +634,7 @@ struct pci_bus *__ref pci_add_new_bus(struct pci_bus *parent, struct pci_dev *de >> child = pci_alloc_child_bus(parent, dev, busnr); >> if (child) { >> down_write(&pci_bus_sem); >> - list_add_tail(&child->node,&parent->children); >> + list_add_tail_rcu(&child->node,&parent->children); >> up_write(&pci_bus_sem); >> } >> return child; >> @@ -1889,7 +1890,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, >> } >> >> down_write(&pci_bus_sem); >> - list_add_tail(&b->node,&pci_root_buses); >> + list_add_tail_rcu(&b->node,&pci_root_buses); >> up_write(&pci_bus_sem); >> >> return b; >> diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c >> index 25f368e..120bee9 100644 >> --- a/drivers/pci/remove.c >> +++ b/drivers/pci/remove.c >> @@ -1,6 +1,7 @@ >> #include<linux/pci.h> >> #include<linux/module.h> >> #include<linux/pci-aspm.h> >> +#include<linux/rculist.h> >> #include "pci.h" >> >> static void pci_free_resources(struct pci_dev *dev) >> @@ -67,9 +68,11 @@ void pci_remove_bus(struct pci_bus *pci_bus) >> pci_proc_detach_bus(pci_bus); >> >> down_write(&pci_bus_sem); >> - list_del(&pci_bus->node); >> + list_del_rcu(&pci_bus->node); >> pci_bus_release_busn_res(pci_bus); >> up_write(&pci_bus_sem); >> + synchronize_rcu(); >> + >> if (pci_bus->is_added || pci_is_root_bus(pci_bus)) { >> pci_remove_legacy_files(pci_bus); >> device_unregister(&pci_bus->dev); >> diff --git a/drivers/pci/search.c b/drivers/pci/search.c >> index b572730..de31957 100644 >> --- a/drivers/pci/search.c >> +++ b/drivers/pci/search.c >> @@ -12,6 +12,7 @@ >> #include<linux/slab.h> >> #include<linux/module.h> >> #include<linux/interrupt.h> >> +#include<linux/rculist.h> >> #include "pci.h" >> >> DECLARE_RWSEM(pci_bus_sem); >> @@ -52,20 +53,63 @@ pci_find_upstream_pcie_bridge(struct pci_dev *pdev) >> >> static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr) >> { >> - struct pci_bus* child; >> - struct list_head *tmp; >> + struct pci_bus *child; >> + struct pci_bus *tmp_bus; >> >> if(bus->number == busnr) >> return bus; >> >> - list_for_each(tmp,&bus->children) { >> - child = pci_do_find_bus(pci_bus_b(tmp), busnr); >> - if(child) >> - return child; >> + list_for_each_entry_rcu(child,&bus->children, node) { >> + tmp_bus = pci_do_find_bus(child, busnr); >> + if(tmp_bus) >> + return tmp_bus; >> } >> return NULL; >> } >> >> +static struct pci_bus *__pci_find_bus(int domain, int busnr) >> +{ >> + struct pci_bus *bus; >> + struct pci_bus *tmp_bus; >> + >> + list_for_each_entry_rcu(bus,&pci_root_buses, node) { >> + if (pci_domain_nr(bus) != domain) >> + continue; >> + tmp_bus = pci_do_find_bus(bus, busnr); >> + if (tmp_bus) >> + return tmp_bus; >> + } >> + >> + return NULL; >> +} >> + >> +static struct pci_bus *__pci_find_next_bus(const struct pci_bus *from) >> +{ >> + struct list_head *n; >> + struct pci_bus *b = NULL; >> + >> + /* First search, start from the pci root bus list */ >> + if (from == NULL) { >> + n = rcu_dereference(list_next_rcu(&pci_root_buses)); >> + if (n !=&pci_root_buses) >> + b = pci_bus_b(n); >> + /* Continue on the pci root bus list */ >> + } else if (pci_is_root_bus((struct pci_bus *)from)) { >> + n = rcu_dereference(list_next_rcu(&from->node)); >> + if (n !=&pci_root_buses) >> + b = pci_bus_b(n); >> + /* Continue on other non pci root bus list */ >> + } else { >> + struct pci_bus *parent = from->self->bus; >> + >> + n = rcu_dereference(list_next_rcu(&from->node)); >> + if (n !=&parent->children) >> + b = pci_bus_b(n); >> + } >> + >> + return b; >> +} >> + >> /** >> * pci_find_bus - locate PCI bus from a given domain and bus number >> * @domain: number of PCI domain to search >> @@ -74,20 +118,19 @@ static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr) >> * Given a PCI bus number and domain number, the desired PCI bus is located >> * in the global list of PCI buses. If the bus is found, a pointer to its >> * data structure is returned. If no bus is found, %NULL is returned. >> + * >> + * TODO: By design, this function should only be called at boot time. >> + * So either mark it as __init or deprecate it. >> */ >> struct pci_bus * pci_find_bus(int domain, int busnr) >> { >> - struct pci_bus *bus = NULL; >> - struct pci_bus *tmp_bus; >> + struct pci_bus *bus; >> >> - while ((bus = pci_find_next_bus(bus)) != NULL) { >> - if (pci_domain_nr(bus) != domain) >> - continue; >> - tmp_bus = pci_do_find_bus(bus, busnr); >> - if (tmp_bus) >> - return tmp_bus; >> - } >> - return NULL; >> + rcu_read_lock(); >> + bus = __pci_find_bus(domain, busnr); >> + rcu_read_unlock(); >> + >> + return bus; >> } >> >> /** >> @@ -98,21 +141,93 @@ struct pci_bus * pci_find_bus(int domain, int busnr) >> * initiated by passing %NULL as the @from argument. Otherwise if >> * @from is not %NULL, searches continue from next device on the >> * global list. >> + * >> + * TODO: By design, this function should only be called at boot time. >> + * So either mark it as __init or deprecate it. >> */ >> struct pci_bus * >> pci_find_next_bus(const struct pci_bus *from) >> { >> - struct list_head *n; >> - struct pci_bus *b = NULL; >> + struct pci_bus *bus; >> >> - WARN_ON(in_interrupt()); >> - down_read(&pci_bus_sem); >> - n = from ? from->node.next : pci_root_buses.next; >> - if (n !=&pci_root_buses) >> - b = pci_bus_b(n); >> - up_read(&pci_bus_sem); >> - return b; >> + rcu_read_lock(); >> + bus = __pci_find_next_bus(from); >> + rcu_read_unlock(); >> + >> + return bus; >> +} >> + >> +/** >> + * pci_get_bus - locate PCI bus from a given domain and bus number >> + * @domain: number of PCI domain to search >> + * @busnr: number of desired PCI bus >> + * >> + * Given a PCI bus number and domain number, the desired PCI bus is located >> + * in the global list of PCI buses. If the bus is found, a pointer to its >> + * data structure is returned, and the reference count to the bus is increased. >> + * Otherwise, %NULL is returned. >> + */ >> +struct pci_bus * >> +pci_get_bus(int domain, int busnr) >> +{ >> + struct pci_bus *bus; >> + >> + rcu_read_lock(); >> + bus = pci_bus_get(__pci_find_bus(domain, busnr)); >> + rcu_read_unlock(); >> + >> + return bus; >> +} >> +EXPORT_SYMBOL(pci_get_bus); >> + >> +/** >> + * pci_get_next_bus - begin or continue searching for a PCI bus >> + * @from: Previous PCI bus found, or %NULL for new search. >> + * >> + * Iterates through the list of known PCI busses. A new search is >> + * initiated by passing %NULL as the @from argument. Otherwise if >> + * @from is not %NULL, searches continue from next device on the >> + * global list. If a bus is found, a pointer to its data structure >> + * is returned, and the reference count to the bus is increased. >> + * Otherwise, %NULL is returned. >> + * The reference count for @from is always decremented if it is not %NULL. >> + */ >> +struct pci_bus * >> +pci_get_next_bus(struct pci_bus *from) >> +{ >> + struct pci_bus *bus; >> + >> + rcu_read_lock(); >> + bus = pci_bus_get(__pci_find_next_bus(from)); >> + rcu_read_unlock(); >> + >> + return bus; >> +} >> +EXPORT_SYMBOL(pci_get_next_bus); >> + >> +/** >> + * pci_bus_present - Returns true if a bus with the (@domain, @busnr) >> + * is present, false if not. >> + * @domain: number of PCI domain to search >> + * @busnr: number of desired PCI bus >> + * >> + * Obvious fact: You do not have a reference to any bus that might be found >> + * by this function, so if that bus is removed from the system right after >> + * this function is finished, the value will be stale. Use this function to >> + * find buses that are usually built into a system, or for a general hint as >> + * to if another device happens to be present at this specific moment in time. >> + */ >> +bool pci_bus_present(int domain, int busnr) >> +{ >> + struct pci_bus *bus; >> + >> + rcu_read_lock(); >> + bus = __pci_find_bus(domain, busnr); >> + rcu_read_unlock(); >> + >> + return !!bus; >> } >> +EXPORT_SYMBOL(pci_bus_present); >> >> /** >> * pci_get_slot - locate PCI device for a given PCI slot >> diff --git a/include/linux/pci.h b/include/linux/pci.h >> index ec8c4cf..222bc88 100644 >> --- a/include/linux/pci.h >> +++ b/include/linux/pci.h >> @@ -731,6 +731,11 @@ int pci_find_ht_capability(struct pci_dev *dev, int ht_cap); >> int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap); >> struct pci_bus *pci_find_next_bus(const struct pci_bus *from); >> >> +struct pci_bus *pci_bus_get(struct pci_bus *bus); >> +void pci_bus_put(struct pci_bus *bus); >> +struct pci_bus *pci_get_bus(int domain, int busnr); >> +struct pci_bus *pci_get_next_bus(struct pci_bus *from); >> +bool pci_bus_present(int domain, int busnr); >> struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, >> struct pci_dev *from); >> struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device, >> @@ -1321,6 +1326,9 @@ static inline void pci_unblock_cfg_access(struct pci_dev *dev) >> static inline struct pci_bus *pci_find_next_bus(const struct pci_bus *from) >> { return NULL; } >> >> +static inline struct pci_bus *pci_get_next_bus(const struct pci_bus *from) >> +{ return NULL; } >> + >> static inline struct pci_dev *pci_get_slot(struct pci_bus *bus, >> unsigned int devfn) >> { return NULL; } >> -- >> 1.7.5.4 >> > > . > ^ permalink raw reply [flat|nested] 11+ messages in thread
* [RFC PATCH 5/5] PCI: Replace old pci bus searching function calls with hotplug safe ones 2012-03-11 17:48 [RFC PATCH 0/5] PCI: introduce hotplug safe bus searching interfaces Jiang Liu ` (3 preceding siblings ...) 2012-03-11 17:48 ` [RFC PATCH 4/5] PCI: Introduce hotplug-safe pci bus searching interfaces Jiang Liu @ 2012-03-11 17:48 ` Jiang Liu 4 siblings, 0 replies; 11+ messages in thread From: Jiang Liu @ 2012-03-11 17:48 UTC (permalink / raw) To: Yinghai Lu, Jesse Barnes, Bjorn Helgaas Cc: Jiang Liu, Ashok Raj, Suresh Siddha, Youquan Song, linux-pci, linux-kernel, chenkeping First round of scan to replace hotplug unsafe function calls with proposed new interfaces. It's here to make the patchset easy to be understood. It should be merge with the previous patch if accepted. Signed-off-by: Jiang Liu <jiang.liu@huawei.com> --- arch/frv/mb93090-mb00/pci-vdk.c | 2 +- arch/x86/pci/common.c | 9 ++++----- arch/x86/pci/irq.c | 2 +- arch/x86/pci/legacy.c | 2 +- drivers/acpi/pci_root.c | 2 +- drivers/acpi/pci_root_hp.c | 2 +- drivers/acpi/pci_slot.c | 6 ++++-- drivers/acpi/reboot.c | 3 ++- drivers/edac/i7core_edac.c | 2 +- drivers/gpu/vga/vgaarb.c | 3 ++- drivers/iommu/dmar.c | 6 ++++-- drivers/pci/hotplug/cpci_hotplug_pci.c | 4 ++-- drivers/pci/hotplug/ibmphp_core.c | 8 +++++--- drivers/pci/hotplug/sgi_hotplug.c | 3 ++- drivers/pci/hotplug/shpchp_pci.c | 4 ++-- drivers/pci/hotplug/shpchp_sysfs.c | 2 +- drivers/pci/iov.c | 6 ++++-- drivers/pci/pci-sysfs.c | 2 +- drivers/pci/pci.c | 2 +- drivers/pci/pcie/pme.c | 16 ++++------------ drivers/pci/probe.c | 6 +++++- drivers/pci/xen-pcifront.c | 6 ++++-- 22 files changed, 53 insertions(+), 45 deletions(-) diff --git a/arch/frv/mb93090-mb00/pci-vdk.c b/arch/frv/mb93090-mb00/pci-vdk.c index 6b0b82f..6ec3526 100644 --- a/arch/frv/mb93090-mb00/pci-vdk.c +++ b/arch/frv/mb93090-mb00/pci-vdk.c @@ -235,7 +235,7 @@ static void __init pcibios_fixup_peer_bridges(void) return; printk("PCI: Peer bridge fixup\n"); for (n=0; n <= pcibios_last_bus; n++) { - if (pci_find_bus(0, n)) + if (pci_bus_present(0, n)) continue; bus.number = n; bus.ops = pci_root_ops; diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 0ec860f..25ab0b0 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -433,11 +433,10 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum) { struct pci_bus *bus = NULL; - while ((bus = pci_find_next_bus(bus)) != NULL) { - if (bus->number == busnum) { - /* Already scanned */ - return bus; - } + bus = pci_get_bus(0, busnum); + if (bus) { + pci_bus_put(bus); + return bus; } return pci_scan_bus_on_node(busnum, &pci_root_ops, diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index 372e9b8..9ba77b6 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c @@ -137,7 +137,7 @@ static void __init pirq_peer_trick(void) } for (i = 1; i < 256; i++) { int node; - if (!busmap[i] || pci_find_bus(0, i)) + if (!busmap[i] || pci_bus_present(0, i)) continue; node = get_mp_bus_to_node(i); if (pci_scan_bus_on_node(i, &pci_root_ops, node)) diff --git a/arch/x86/pci/legacy.c b/arch/x86/pci/legacy.c index 251f838..be3865a 100644 --- a/arch/x86/pci/legacy.c +++ b/arch/x86/pci/legacy.c @@ -56,7 +56,7 @@ static __devinit struct pci_bus *__pcibios_scan_specific_bus(int busn, } void __devinit pcibios_scan_specific_bus(int busn) { - if (pci_find_bus(0, busn)) + if (pci_bus_present(0, busn)) return; __pcibios_scan_specific_bus(busn, true); diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index b38e347..571519b 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -644,7 +644,7 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type) struct acpi_pci_root *root = acpi_driver_data(device); /* that root bus could be removed already */ - if (!pci_find_bus(root->segment, root->secondary.start)) { + if (!pci_bus_present(root->segment, root->secondary.start)) { dev_printk(KERN_DEBUG, &device->dev, "freeing acpi_pci_root, but pci root bus was removed before"); goto out; diff --git a/drivers/acpi/pci_root_hp.c b/drivers/acpi/pci_root_hp.c index ca73d51..7fbf7cb 100644 --- a/drivers/acpi/pci_root_hp.c +++ b/drivers/acpi/pci_root_hp.c @@ -101,7 +101,7 @@ static void handle_root_bridge_insertion(acpi_handle handle) if (!acpi_bus_get_device(handle, &device)) { /* check if pci root_bus is removed */ struct acpi_pci_root *root = acpi_driver_data(device); - if (pci_find_bus(root->segment, root->secondary.start)) + if (pci_bus_present(root->segment, root->secondary.start)) return; printk(KERN_DEBUG "bus exists... trim\n"); diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index e50e31a..c606e58 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c @@ -268,7 +268,7 @@ walk_root_bridge(acpi_handle handle, acpi_walk_callback user_function) status = acpi_evaluate_integer(handle, "_BBN", NULL, &tmp); bus = ACPI_SUCCESS(status) ? tmp : 0; - pci_bus = pci_find_bus(seg, bus); + pci_bus = pci_get_bus(seg, bus); if (!pci_bus) return 0; @@ -280,12 +280,14 @@ walk_root_bridge(acpi_handle handle, acpi_walk_callback user_function) status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, user_function, NULL, &context, NULL); if (ACPI_FAILURE(status)) - return status; + goto out; status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, walk_p2p_bridge, NULL, &context, NULL); if (ACPI_FAILURE(status)) err("%s: walk_p2p_bridge failure - %d\n", __func__, status); +out: + pci_bus_put(pci_bus); return status; } diff --git a/drivers/acpi/reboot.c b/drivers/acpi/reboot.c index a6c77e8b..532dd6d 100644 --- a/drivers/acpi/reboot.c +++ b/drivers/acpi/reboot.c @@ -33,7 +33,7 @@ void acpi_reboot(void) switch (rr->space_id) { case ACPI_ADR_SPACE_PCI_CONFIG: /* The reset register can only live on bus 0. */ - bus0 = pci_find_bus(0, 0); + bus0 = pci_get_bus(0, 0); if (!bus0) return; /* Form PCI device/function pair. */ @@ -43,6 +43,7 @@ void acpi_reboot(void) /* Write the value that resets us. */ pci_bus_write_config_byte(bus0, devfn, (rr->address & 0xffff), reset_value); + pci_bus_put(bus0); break; case ACPI_ADR_SPACE_SYSTEM_MEMORY: diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 8568d9b..be060c1 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1327,7 +1327,7 @@ static unsigned i7core_pci_lastbus(void) int last_bus = 0, bus; struct pci_bus *b = NULL; - while ((b = pci_find_next_bus(b)) != NULL) { + while ((b = pci_get_next_bus(b)) != NULL) { bus = b->number; debugf0("Found bus %d\n", bus); if (bus > last_bus) diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index 111d956..4cdc414 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -1076,7 +1076,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, pr_debug("vgaarb: %s ==> %x:%x:%x.%x\n", curr_pos, domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); - pbus = pci_find_bus(domain, bus); + pbus = pci_get_bus(domain, bus); pr_debug("vgaarb: pbus %p\n", pbus); if (pbus == NULL) { pr_err("vgaarb: invalid PCI domain and/or bus address %x:%x\n", @@ -1085,6 +1085,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, goto done; } pdev = pci_get_slot(pbus, devfn); + pci_bus_put(pbus); pr_debug("vgaarb: pdev %p\n", pdev); if (!pdev) { pr_err("vgaarb: invalid PCI address %x:%x\n", diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 35c1e17..521980c 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -64,12 +64,12 @@ static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd) static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope, struct pci_dev **dev, u16 segment) { - struct pci_bus *bus; + struct pci_bus *bus, *cbus; struct pci_dev *pdev = NULL; struct acpi_dmar_pci_path *path; int count; - bus = pci_find_bus(segment, scope->bus); + cbus = bus = pci_get_bus(segment, scope->bus); path = (struct acpi_dmar_pci_path *)(scope + 1); count = (scope->length - sizeof(struct acpi_dmar_device_scope)) / sizeof(struct acpi_dmar_pci_path); @@ -98,6 +98,8 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope, count --; bus = pdev->subordinate; } + pci_bus_put(cbus); + if (!pdev) { printk(KERN_WARNING PREFIX "Device scope device [%04x:%02x:%02x.%02x] not found\n", diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c index 4ef80ad..209f1a2 100644 --- a/drivers/pci/hotplug/cpci_hotplug_pci.c +++ b/drivers/pci/hotplug/cpci_hotplug_pci.c @@ -296,8 +296,8 @@ int __ref cpci_configure_slot(struct slot *slot) unsigned char end = parent->subordinate; for (busnr = start; busnr <= end; busnr++) { - if (!pci_find_bus(pci_domain_nr(parent), - busnr)) + if (!pci_bus_present(pci_domain_nr(parent), + busnr)) break; } if (busnr >= end) { diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index 4fda7e6..dede10f 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c @@ -739,7 +739,7 @@ static u8 bus_structure_fixup(u8 busno) struct pci_dev *dev; u16 l; - if (pci_find_bus(0, busno) || !(ibmphp_find_same_bus_num(busno))) + if (pci_bus_present(0, busno) || !(ibmphp_find_same_bus_num(busno))) return 1; bus = kmalloc(sizeof(*bus), GFP_KERNEL); @@ -788,7 +788,7 @@ static int ibm_configure_device(struct pci_func *func) PCI_DEVFN(func->device, func->function)); if (func->dev == NULL) { - struct pci_bus *bus = pci_find_bus(0, func->busno); + struct pci_bus *bus = pci_get_bus(0, func->busno); if (!bus) return 0; @@ -796,6 +796,7 @@ static int ibm_configure_device(struct pci_func *func) PCI_DEVFN(func->device, func->function)); if (num) pci_bus_add_devices(bus); + pci_bus_put(bus); func->dev = pci_get_bus_and_slot(func->busno, PCI_DEVFN(func->device, func->function)); @@ -1315,13 +1316,14 @@ static int __init ibmphp_init(void) goto exit; } - bus = pci_find_bus(0, 0); + bus = pci_get_bus(0, 0); if (!bus) { err("Can't find the root pci bus, can not continue\n"); rc = -ENODEV; goto error; } memcpy(ibmphp_pci_bus, bus, sizeof(*ibmphp_pci_bus)); + pci_bus_put(bus); ibmphp_debug = debug; diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index de57311..7c4c1e3 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -692,7 +692,7 @@ static int __init sn_pci_hotplug_init(void) INIT_LIST_HEAD(&sn_hp_list); - while ((pci_bus = pci_find_next_bus(pci_bus))) { + while ((pci_bus = pci_get_next_bus(pci_bus))) { if (!pci_bus->sysdata) continue; @@ -711,6 +711,7 @@ static int __init sn_pci_hotplug_init(void) break; } } + pci_bus_put(pci_bus); return registered == 1 ? 0 : -ENODEV; } diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c index d92807b..a58587f 100644 --- a/drivers/pci/hotplug/shpchp_pci.c +++ b/drivers/pci/hotplug/shpchp_pci.c @@ -67,8 +67,8 @@ int __ref shpchp_configure_device(struct slot *p_slot) unsigned char busnr, start = parent->secondary; unsigned char end = parent->subordinate; for (busnr = start; busnr <= end; busnr++) { - if (!pci_find_bus(pci_domain_nr(parent), - busnr)) + if (!pci_bus_present(pci_domain_nr(parent), + busnr)) break; } if (busnr > end) { diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c index efa30da..8744b56 100644 --- a/drivers/pci/hotplug/shpchp_sysfs.c +++ b/drivers/pci/hotplug/shpchp_sysfs.c @@ -74,7 +74,7 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha } out += sprintf(out, "Free resources: bus numbers\n"); for (busnr = bus->secondary; busnr <= bus->subordinate; busnr++) { - if (!pci_find_bus(pci_domain_nr(bus), busnr)) + if (!pci_bus_present(pci_domain_nr(bus), busnr)) break; } if (busnr < bus->subordinate) diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 6554e1a..631c655 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -65,11 +65,12 @@ static void virtfn_remove_bus(struct pci_bus *bus, int busnr) if (bus->number == busnr) return; - child = pci_find_bus(pci_domain_nr(bus), busnr); + child = pci_get_bus(pci_domain_nr(bus), busnr); BUG_ON(!child); if (list_empty(&child->devices)) pci_remove_bus(child); + pci_bus_put(child); } static int virtfn_add(struct pci_dev *dev, int id, int reset) @@ -156,11 +157,12 @@ static void virtfn_remove(struct pci_dev *dev, int id, int reset) struct pci_dev *virtfn; struct pci_sriov *iov = dev->sriov; - bus = pci_find_bus(pci_domain_nr(dev->bus), virtfn_bus(dev, id)); + bus = pci_get_bus(pci_domain_nr(dev->bus), virtfn_bus(dev, id)); if (!bus) return; virtfn = pci_get_slot(bus, virtfn_devfn(dev, id)); + pci_bus_put(bus); if (!virtfn) return; diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index c180455..96599b4 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -297,7 +297,7 @@ static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf, if (val) { mutex_lock(&pci_remove_rescan_mutex); arch_pci_root_rescan(); - while ((b = pci_find_next_bus(b)) != NULL) + while ((b = pci_get_next_bus(b)) != NULL) pci_rescan_bus(b); mutex_unlock(&pci_remove_rescan_mutex); } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index b832f0f..2c20628 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -146,7 +146,7 @@ pci_max_busnr(void) unsigned char max, n; max = 0; - while ((bus = pci_find_next_bus(bus)) != NULL) { + while ((bus = pci_get_next_bus(bus)) != NULL) { n = pci_bus_max_busnr(bus); if(n > max) max = n; diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c index 001f1b7..88b9ef9 100644 --- a/drivers/pci/pcie/pme.c +++ b/drivers/pci/pcie/pme.c @@ -139,7 +139,7 @@ static bool pcie_pme_from_pci_bridge(struct pci_bus *bus, u8 devfn) static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id) { u8 busnr = req_id >> 8, devfn = req_id & 0xff; - struct pci_bus *bus; + struct pci_bus *bus = NULL; struct pci_dev *dev; bool found = false; @@ -168,7 +168,7 @@ static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id) } /* Second, find the bus the source device is on. */ - bus = pci_find_bus(pci_domain_nr(port->bus), busnr); + bus = pci_get_bus(pci_domain_nr(port->bus), busnr); if (!bus) goto out; @@ -178,16 +178,7 @@ static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id) goto out; /* Finally, try to find the PME source on the bus. */ - down_read(&pci_bus_sem); - list_for_each_entry(dev, &bus->devices, bus_list) { - pci_dev_get(dev); - if (dev->devfn == devfn) { - found = true; - break; - } - pci_dev_put(dev); - } - up_read(&pci_bus_sem); + dev = pci_get_slot(bus, devfn); if (found) { /* The device is there, but we have to check its PME status. */ @@ -213,6 +204,7 @@ static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id) } out: + pci_bus_put(bus); if (!found) dev_dbg(&port->dev, "Spurious native PME interrupt!\n"); } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 273c387..ae93aad 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -926,6 +926,8 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, child = pci_add_new_bus(bus, dev, secondary); if (!child) goto out; + + pci_bus_get(child); child->primary = primary; child->subordinate = subordinate; child->bridge_ctl = bctl; @@ -938,6 +940,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, max = cmax; if (child->subordinate > max) max = child->subordinate; + pci_bus_put(child); } else { /* * We need to assign a number to this bus which we always @@ -1826,10 +1829,11 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, b->sysdata = sysdata; b->ops = ops; - b2 = pci_find_bus(pci_domain_nr(b), bus); + b2 = pci_get_bus(pci_domain_nr(b), bus); if (b2) { /* If we already got to this bus through a different bridge, ignore it */ dev_dbg(&b2->dev, "bus already known\n"); + pci_bus_put(b2); goto err_out; } diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index 9c43ab4..21c33e5 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -520,7 +520,7 @@ static int __devinit pcifront_rescan_root(struct pcifront_device *pdev, dev_info(&pdev->xdev->dev, "Rescanning PCI Frontend Bus %04x:%02x\n", domain, bus); - b = pci_find_bus(domain, bus); + b = pci_get_bus(domain, bus); if (!b) /* If the bus is unknown, create it. */ return pcifront_scan_root(pdev, domain, bus); @@ -532,6 +532,7 @@ static int __devinit pcifront_rescan_root(struct pcifront_device *pdev, /* Create SysFS and notify udev of the devices. Aka: "going live" */ pci_bus_add_devices(b); + pci_bus_put(b); return err; } @@ -1032,13 +1033,14 @@ static int pcifront_detach_devices(struct pcifront_device *pdev) goto out; } - pci_bus = pci_find_bus(domain, bus); + pci_bus = pci_get_bus(domain, bus); if (!pci_bus) { dev_dbg(&pdev->xdev->dev, "Cannot get bus %04x:%02x\n", domain, bus); continue; } pci_dev = pci_get_slot(pci_bus, PCI_DEVFN(slot, func)); + pci_bus_put(pci_bus); if (!pci_dev) { dev_dbg(&pdev->xdev->dev, "Cannot get PCI device %04x:%02x:%02x.%d\n", -- 1.7.5.4 ^ permalink raw reply related [flat|nested] 11+ messages in thread
end of thread, other threads:[~2012-03-13 8:13 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2012-03-11 17:48 [RFC PATCH 0/5] PCI: introduce hotplug safe bus searching interfaces Jiang Liu 2012-03-11 17:48 ` [PATCH 1/5] Fix device reference count leakage in pci_dev_present() Jiang Liu 2012-03-11 17:48 ` [PATCH 2/5] Correctly clean up pci root buses in function pci_remove_bus() Jiang Liu 2012-03-13 6:24 ` Yinghai Lu 2012-03-13 7:23 ` Jiang Liu 2012-03-11 17:48 ` [PATCH 3/5] Fix an access-after-free issue in function pci_stop_and_remove_bus() Jiang Liu 2012-03-13 3:47 ` Bjorn Helgaas 2012-03-11 17:48 ` [RFC PATCH 4/5] PCI: Introduce hotplug-safe pci bus searching interfaces Jiang Liu 2012-03-13 3:49 ` Bjorn Helgaas 2012-03-13 8:13 ` Jiang Liu 2012-03-11 17:48 ` [RFC PATCH 5/5] PCI: Replace old pci bus searching function calls with hotplug safe ones Jiang Liu
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).