From: Ben Hutchings <b...@decadent.org.uk>
Date: Tue, 29 Mar 2011 03:25:15 +0100

The BKL conversion of this family of drivers seems to have gone wrong.
Opening cx88-blackbird will deadlock.  Various other uses of the
sub-device and driver lists appear to be subject to race conditions.

In particular, mpeg_ops::open in the cx2388x blackbird driver acquires
the device lock and then calls the drivers' request_acquire, which
tries to acquire the lock again --- deadlock.  Fix it by clarifying
the semantics of request_acquire, request_release, advise_acquire, and
advise_release: all require the caller to hold the device lock now.

[jn: split from a larger patch, with new commit message]

Reported-by: Andi Huber <hob...@gmx.at>
Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=31962
Signed-off-by: Ben Hutchings <b...@decadent.org.uk>
Signed-off-by: Jonathan Nieder <jrnie...@gmail.com>
Cc: sta...@kernel.org
---
 drivers/media/video/cx88/cx88-blackbird.c |    9 ++-------
 drivers/media/video/cx88/cx88-dvb.c       |    8 +-------
 drivers/media/video/cx88/cx88-mpeg.c      |    4 ----
 drivers/media/video/cx88/cx88.h           |    3 ++-
 4 files changed, 5 insertions(+), 19 deletions(-)

diff --git a/drivers/media/video/cx88/cx88-blackbird.c 
b/drivers/media/video/cx88/cx88-blackbird.c
index 85910c6..a6f7d53 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -1125,18 +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);
-
-       /*
-        * NEEDSWORK: the driver can be yanked from under our feet.
-        * The following really ought to be protected with core->lock.
-        */
-
        if (drv)
                drv->request_release(drv);
 
        atomic_dec(&dev->core->mpeg_users);
 
+       mutex_unlock(&dev->core->lock);
+
        return 0;
 }
 
diff --git a/drivers/media/video/cx88/cx88-dvb.c 
b/drivers/media/video/cx88/cx88-dvb.c
index 5d0f947..c69df7e 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -135,13 +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);
-
-       /*
-        * NEEDSWORK: The driver can be yanked from under our feet now.
-        * We ought to keep holding core->lock during the below.
-        */
-
        if (drv) {
                if (acquire){
                        dev->frontends.active_fe_id = fe_id;
@@ -151,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;
 }
diff --git a/drivers/media/video/cx88/cx88-mpeg.c 
b/drivers/media/video/cx88/cx88-mpeg.c
index 918172b..9147c16 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -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;
 }
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index e3d56c2..9731daa 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -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 */
-- 
1.7.5.rc0

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

Reply via email to