[media] em28xx: Fix em28xx deplock
authorMauro Carvalho Chehab <m.chehab@samsung.com>
Fri, 27 Dec 2013 16:01:04 +0000 (13:01 -0300)
committerMauro Carvalho Chehab <m.chehab@samsung.com>
Sun, 5 Jan 2014 10:58:49 +0000 (08:58 -0200)
When em28xx extensions are loaded/removed, there are two locks:

a single static em28xx_devlist_mutex that registers each extension
and the struct em28xx dev->lock.

When extensions are registered, em28xx_devlist_mutex is taken first,
and then dev->lock.

Be sure that, when extensions are being removed, the same order
will be used.

Reviewed-by: Frank Schäfer <fschaefer.oss@googlemail.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
drivers/media/usb/em28xx/em28xx-cards.c
drivers/media/usb/em28xx/em28xx-core.c

index 551cbc2941907d8f88455e4005a6d48c11f31a3f..154e6f028fd202bd415e1cfd8a31e843be43e865 100644 (file)
@@ -3485,9 +3485,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
        dev->disconnected = 1;
 
        if (dev->is_audio_only) {
-               mutex_lock(&dev->lock);
                em28xx_close_extension(dev);
-               mutex_unlock(&dev->lock);
                return;
        }
 
@@ -3506,10 +3504,13 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
                em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
                em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE);
        }
+       mutex_unlock(&dev->lock);
 
        em28xx_close_extension(dev);
+
        /* NOTE: must be called BEFORE the resources are released */
 
+       mutex_lock(&dev->lock);
        if (!dev->users)
                em28xx_release_resources(dev);
 
index 3012912d299704e0d915f5c5c8eca2b8a5a28524..f77301773aee215741aae5dfa4b7d0b254349fcc 100644 (file)
@@ -1094,10 +1094,12 @@ void em28xx_close_extension(struct em28xx *dev)
        const struct em28xx_ops *ops = NULL;
 
        mutex_lock(&em28xx_devlist_mutex);
+       mutex_lock(&dev->lock);
        list_for_each_entry(ops, &em28xx_extension_devlist, next) {
                if (ops->fini)
                        ops->fini(dev);
        }
+       mutex_unlock(&dev->lock);
        list_del(&dev->devlist);
        mutex_unlock(&em28xx_devlist_mutex);
 }