Instead of probing devices sequentially in the PROBE_PREFER_ASYNCHRONOUS
mode, scan devices concurrently. This helps when the wall clock time for
a single probe is significantly above the CPU time needed for a single
probe, e.g. when scanning SCSI LUNs over a storage network.

Cc: Lee Duncan <ldun...@suse.com>
Cc: Hannes Reinecke <h...@suse.com>
Cc: Luis Chamberlain <mcg...@kernel.org>
Cc: Johannes Thumshirn <jthumsh...@suse.de>
Cc: Christoph Hellwig <h...@lst.de>
Cc: Greg Kroah-Hartman <gre...@linuxfoundation.org>
Cc: Dan Williams <dan.j.willi...@intel.com>
Signed-off-by: Bart Van Assche <bvanass...@acm.org>
---
 drivers/base/bus.c |  3 +--
 drivers/base/dd.c  | 49 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 8bfd27ec73d6..18ca1178821f 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -696,8 +696,7 @@ int bus_add_driver(struct device_driver *drv)
 
 out_unregister:
        kobject_put(&priv->kobj);
-       /* drv->p is freed in driver_release()  */
-       drv->p = NULL;
+
 out_put_bus:
        bus_put(bus);
        return error;
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 033382421351..f8d645aa09be 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -27,6 +27,7 @@
 #include <linux/async.h>
 #include <linux/pm_runtime.h>
 #include <linux/pinctrl/devinfo.h>
+#include <linux/slab.h>
 
 #include "base.h"
 #include "power/power.h"
@@ -691,6 +692,49 @@ int driver_probe_device(struct device_driver *drv, struct 
device *dev)
        return ret;
 }
 
+struct driver_and_dev {
+       struct device_driver    *drv;
+       struct device           *dev;
+};
+
+static void __driver_probe_device_async(void *data, async_cookie_t cookie)
+{
+       struct driver_and_dev *dd = data;
+       struct device_driver *drv = dd->drv;
+       struct device *dev = dd->dev;
+
+       device_lock(dev);
+       driver_probe_device(drv, dev);
+       device_unlock(dev);
+       kobject_put(&drv->p->kobj);
+       module_put(drv->owner);
+       kfree(dd);
+}
+
+static void driver_probe_device_async(struct device_driver *drv,
+                                     struct device *dev)
+{
+       struct driver_and_dev *dd;
+
+       if (!try_module_get(drv->owner))
+               return;
+       dd = kmalloc(sizeof(*dd), GFP_KERNEL);
+       if (!dd) {
+               /* If out of memory, scan synchronously. */
+               device_lock(dev);
+               driver_probe_device(drv, dev);
+               device_unlock(dev);
+               module_put(drv->owner);
+               return;
+       }
+       *dd = (struct driver_and_dev){
+               .drv = drv,
+               .dev = dev,
+       };
+       kobject_get(&drv->p->kobj);
+       async_schedule(__driver_probe_device_async, dd);
+}
+
 bool driver_allows_async_probing(struct device_driver *drv)
 {
        switch (drv->probe_type) {
@@ -777,6 +821,11 @@ static int __device_attach_driver(struct device_driver 
*drv, void *_data)
        if (data->check_async && async_allowed != data->want_async)
                return 0;
 
+       if (data->check_async) {
+               driver_probe_device_async(drv, dev);
+               return 0;
+       }
+
        return driver_probe_device(drv, dev);
 }
 
-- 
2.19.1.568.g152ad8e336-goog

Reply via email to