There is no good reason to hold the list_lock when reprobing the devices
and it prevents a clean implementation of subdevice notifiers. Move the
actual release of the devices outside of the loop which requires the
lock to be held.

Signed-off-by: Niklas Söderlund <niklas.soderlund+rene...@ragnatech.se>
---
 drivers/media/v4l2-core/v4l2-async.c | 29 ++++++++++-------------------
 1 file changed, 10 insertions(+), 19 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c 
b/drivers/media/v4l2-core/v4l2-async.c
index 0acf288d7227ba97..8fc84f7962386ddd 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -206,7 +206,7 @@ void v4l2_async_notifier_unregister(struct 
v4l2_async_notifier *notifier)
        unsigned int notif_n_subdev = notifier->num_subdevs;
        unsigned int n_subdev = min(notif_n_subdev, V4L2_MAX_SUBDEVS);
        struct device **dev;
-       int i = 0;
+       int i, count = 0;
 
        if (!notifier->v4l2_dev)
                return;
@@ -222,37 +222,28 @@ void v4l2_async_notifier_unregister(struct 
v4l2_async_notifier *notifier)
        list_del(&notifier->list);
 
        list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
-               struct device *d;
-
-               d = get_device(sd->dev);
+               if (dev)
+                       dev[count] = get_device(sd->dev);
+               count++;
 
                if (notifier->unbind)
                        notifier->unbind(notifier, sd, sd->asd);
 
                v4l2_async_cleanup(sd);
+       }
 
-               /* If we handled USB devices, we'd have to lock the parent too 
*/
-               device_release_driver(d);
+       mutex_unlock(&list_lock);
 
-               /*
-                * Store device at the device cache, in order to call
-                * put_device() on the final step
-                */
+       for (i = 0; i < count; i++) {
+               /* If we handled USB devices, we'd have to lock the parent too 
*/
                if (dev)
-                       dev[i++] = d;
-               else
-                       put_device(d);
+                       device_release_driver(dev[i]);
        }
 
-       mutex_unlock(&list_lock);
-
        /*
         * Call device_attach() to reprobe devices
-        *
-        * NOTE: If dev allocation fails, i is 0, and the whole loop won't be
-        * executed.
         */
-       while (i--) {
+       for (i = 0; dev && i < count; i++) {
                struct device *d = dev[i];
 
                if (d && device_attach(d) < 0) {
-- 
2.13.1

Reply via email to