[media] cx88: fix locking of sub-driver operations
authorJonathan Nieder <jrnieder@gmail.com>
Sun, 1 May 2011 09:29:37 +0000 (06:29 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Fri, 20 May 2011 12:29:36 +0000 (09:29 -0300)
The BKL conversion of this driver seems to have gone wrong.
Loading the cx88-blackbird driver deadlocks.

The cause: mpeg_ops::open in the cx2388x blackbird driver acquires the
device lock and calls the sub-driver's request_acquire, which tries to
acquire the lock again.  Fix it by clarifying the semantics of
request_acquire, request_release, advise_acquire, and advise_release:
now all will rely on the caller to acquire the device lock.

Based on work by Ben Hutchings <ben@decadent.org.uk>.

Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=31962
Reported-by: Andi Huber <hobrom@gmx.at>
Tested-by: Andi Huber <hobrom@gmx.at>
Tested-by: Marlon de Boer <marlon@hyves.nl>
Cc: stable@kernel.org
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-mpeg.c
drivers/media/video/cx88/cx88.h

index b93fbd39a39e50e4174047fd78203ae0ac328b96..a6f7d53a4510f914d838be94da57e849cc4d0221 100644 (file)
@@ -1125,13 +1125,13 @@ static int mpeg_release(struct file *file)
 
        /* Make sure we release the hardware */
        drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
-       mutex_unlock(&dev->core->lock);
-
        if (drv)
                drv->request_release(drv);
 
        atomic_dec(&dev->core->mpeg_users);
 
+       mutex_unlock(&dev->core->lock);
+
        return 0;
 }
 
index 84002bc80db5c2a7fb4e2b581bde0167181a6610..c69df7ebb6a7575f0478a34c7b41142aa83c4cc9 100644 (file)
@@ -135,8 +135,6 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
 
        mutex_lock(&dev->core->lock);
        drv = cx8802_get_driver(dev, CX88_MPEG_DVB);
-       mutex_unlock(&dev->core->lock);
-
        if (drv) {
                if (acquire){
                        dev->frontends.active_fe_id = fe_id;
@@ -146,6 +144,7 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
                        dev->frontends.active_fe_id = 0;
                }
        }
+       mutex_unlock(&dev->core->lock);
 
        return ret;
 }
index a092c3a4c56d8a4e764bd71f5b09985ce44d6cbe..91d3d179c3c780172059fb5b4bb1248d018b5e1f 100644 (file)
@@ -624,13 +624,11 @@ static int cx8802_request_acquire(struct cx8802_driver *drv)
 
        if (drv->advise_acquire)
        {
-               mutex_lock(&drv->core->lock);
                core->active_ref++;
                if (core->active_type_id == CX88_BOARD_NONE) {
                        core->active_type_id = drv->type_id;
                        drv->advise_acquire(drv);
                }
-               mutex_unlock(&drv->core->lock);
 
                mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __func__, cx_read(MO_GP0_IO));
        }
@@ -643,14 +641,12 @@ static int cx8802_request_release(struct cx8802_driver *drv)
 {
        struct cx88_core *core = drv->core;
 
-       mutex_lock(&drv->core->lock);
        if (drv->advise_release && --core->active_ref == 0)
        {
                drv->advise_release(drv);
                core->active_type_id = CX88_BOARD_NONE;
                mpeg_dbg(1,"%s() Post release GPIO=%x\n", __func__, cx_read(MO_GP0_IO));
        }
-       mutex_unlock(&drv->core->lock);
 
        return 0;
 }
index e3d56c2352036a4585bd3892f4a846d8bfb380ee..9731daa92a065478cb228856aae92c623649d68f 100644 (file)
@@ -510,7 +510,8 @@ struct cx8802_driver {
        /* Caller must _not_ hold core->lock */
        int (*probe)(struct cx8802_driver *drv);
 
-       /* Caller must hold core->lock */
+       /* Callers to the following functions must hold core->lock */
+
        int (*remove)(struct cx8802_driver *drv);
 
        /* MPEG 8802 -> mini driver - Access for hardware control */