From: Jiang Liu <jiang....@huawei.com>

There are two global lists inf file drivers/acpi/pci_root.c.
One is for registered acpi_pci_drivers, the other is for
enumerated ACPI PCI root bridge objects. These two global
lists may change dynamically when registering/deregistering
acpi_pci_drivers or adding/removing ACPI PCI root bridge
objects. So protect them by mutex lock.

-v2: remove -rcu

Signed-off-by: Jiang Liu <jiang....@huawei.com>
Signed-off-by: Yinghai Lu <ying...@kernel.org>
---
 drivers/acpi/pci_root.c |   70 +++++++++++++++++++++++++++--------------------
 1 files changed, 40 insertions(+), 30 deletions(-)

diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 0ea5ad0..67f7733 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -27,7 +27,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/pci.h>
@@ -71,6 +71,8 @@ static struct acpi_driver acpi_pci_root_driver = {
                },
 };
 
+/* Lock to protect both acpi_pci_roots and acpi_pci_drivers lists */
+static DEFINE_MUTEX(acpi_pci_root_lock);
 static LIST_HEAD(acpi_pci_roots);
 static LIST_HEAD(acpi_pci_drivers);
 
@@ -81,47 +83,46 @@ int acpi_pci_register_driver(struct acpi_pci_driver *driver)
        int n = 0;
        struct acpi_pci_root *root;
 
+       mutex_lock(&acpi_pci_root_lock);
        list_add_tail(&driver->node, &acpi_pci_drivers);
-
-       if (!driver->add)
-               return 0;
-
-       list_for_each_entry(root, &acpi_pci_roots, node) {
-               driver->add(root);
-               n++;
-       }
+       if (driver->add)
+               list_for_each_entry(root, &acpi_pci_roots, node) {
+                       driver->add(root);
+                       n++;
+               }
+       mutex_unlock(&acpi_pci_root_lock);
 
        return n;
 }
-
 EXPORT_SYMBOL(acpi_pci_register_driver);
 
 void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
 {
        struct acpi_pci_root *root;
 
+       mutex_lock(&acpi_pci_root_lock);
        list_del(&driver->node);
-
-       if (!driver->remove)
-               return;
-
-       list_for_each_entry(root, &acpi_pci_roots, node)
-               driver->remove(root);
+       if (driver->remove)
+               list_for_each_entry(root, &acpi_pci_roots, node)
+                       driver->remove(root);
+       mutex_unlock(&acpi_pci_root_lock);
 }
-
 EXPORT_SYMBOL(acpi_pci_unregister_driver);
 
 acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus)
 {
        struct acpi_pci_root *root;
-       
+       struct acpi_handle *handle = NULL;
+
        list_for_each_entry(root, &acpi_pci_roots, node)
                if ((root->segment == (u16) seg) &&
-                   (root->secondary.start == (u16) bus))
-                       return root->device->handle;
-       return NULL;            
-}
+                   (root->secondary.start == (u16) bus)) {
+                       handle = root->device->handle;
+                       break;
+               }
 
+       return handle;
+}
 EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle);
 
 /**
@@ -459,7 +460,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device 
*device)
        if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
                printk(KERN_ERR PREFIX "can't evaluate _SEG\n");
                result = -ENODEV;
-               goto end;
+               goto out_free;
        }
 
        /* Check _CRS first, then _BBN.  If no _BBN, default to zero. */
@@ -484,7 +485,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device 
*device)
                else {
                        printk(KERN_ERR PREFIX "can't evaluate _BBN\n");
                        result = -ENODEV;
-                       goto end;
+                       goto out_free;
                }
        }
 
@@ -508,7 +509,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device 
*device)
         * TBD: Need PCI interface for enumeration/configuration of roots.
         */
 
-       /* TBD: Locking */
+       mutex_lock(&acpi_pci_root_lock);
        list_add_tail(&root->node, &acpi_pci_roots);
 
        printk(KERN_INFO PREFIX "%s [%s] (domain %04x %pR)\n",
@@ -528,7 +529,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device 
*device)
                            "Bus %04x:%02x not present in PCI namespace\n",
                            root->segment, (unsigned int)root->secondary.start);
                result = -ENODEV;
-               goto end;
+               goto out_del_root;
        }
 
        /*
@@ -538,7 +539,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device 
*device)
         */
        result = acpi_pci_bind_root(device);
        if (result)
-               goto end;
+               goto out_del_root;
 
        /*
         * PCI Routing Table
@@ -621,11 +622,14 @@ static int __devinit acpi_pci_root_add(struct acpi_device 
*device)
        if (device->wakeup.flags.run_wake)
                device_set_run_wake(root->bus->bridge, true);
 
+       mutex_unlock(&acpi_pci_root_lock);
+
        return 0;
 
-end:
-       if (!list_empty(&root->node))
-               list_del(&root->node);
+out_del_root:
+       list_del(&root->node);
+       mutex_unlock(&acpi_pci_root_lock);
+out_free:
        kfree(root);
        return result;
 }
@@ -635,11 +639,14 @@ static int acpi_pci_root_start(struct acpi_device *device)
        struct acpi_pci_root *root = acpi_driver_data(device);
        struct acpi_pci_driver *driver;
 
+       mutex_lock(&acpi_pci_root_lock);
        list_for_each_entry(driver, &acpi_pci_drivers, node)
                if (driver->add)
                        driver->add(root);
 
        pci_bus_add_devices(root->bus);
+       mutex_unlock(&acpi_pci_root_lock);
+
        return 0;
 }
 
@@ -650,6 +657,8 @@ static int acpi_pci_root_remove(struct acpi_device *device, 
int type)
        struct acpi_pci_root *root = acpi_driver_data(device);
        struct acpi_pci_driver *driver;
 
+       mutex_lock(&acpi_pci_root_lock);
+
        /* that root bus could be removed already */
        if (!pci_find_bus(root->segment, root->secondary.start)) {
                dev_printk(KERN_DEBUG, &device->dev,
@@ -677,6 +686,7 @@ static int acpi_pci_root_remove(struct acpi_device *device, 
int type)
 
 out:
        list_del(&root->node);
+       mutex_unlock(&acpi_pci_root_lock);
        kfree(root);
 
        return 0;
-- 
1.7.7

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to