]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
V4L/DVB (9264): MFE: bugfix: multi-frontend mutual exclusion parallel open
authorDarron Broad <darron@kewl.org>
Wed, 15 Oct 2008 16:37:59 +0000 (13:37 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Fri, 17 Oct 2008 20:28:22 +0000 (17:28 -0300)
When moving from one frontend to another
an application could spawn multiple threads opening
the same new frontend and in some circumstances all of
these could become delayed waiting for the previous
frontend readers or previous frontend writer thread to
complete.

In this scenario the first thread will succeed on open
to bring the new frontend online but any others will return
EBUSY. This is a fault.  If the first succeeds and all others
are on the same frontend then they should succeed also.

Signed-off-by: Darron Broad <darron@kewl.org>
Signed-off-by: Steven Toth <stoth@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/dvb/dvb-core/dvb_frontend.c

index 62696f86557693fcf838027aa35140d8f8d3df79..6c9b9be9e286ac3c6c0429ab6e23714ee1c8a05c 100644 (file)
@@ -1710,39 +1710,46 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
        struct dvb_frontend *fe = dvbdev->priv;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
        struct dvb_adapter *adapter = fe->dvb;
-       struct dvb_device *mfedev;
-       struct dvb_frontend *mfe;
-       struct dvb_frontend_private *mfepriv;
-       int mferetry;
        int ret;
 
        dprintk ("%s\n", __func__);
 
        if (adapter->mfe_shared) {
                mutex_lock (&adapter->mfe_lock);
-               if (adapter->mfe_dvbdev != dvbdev) {
-                       if (adapter->mfe_dvbdev) {
-                               mfedev = adapter->mfe_dvbdev;
-                               mfe = mfedev->priv;
-                               mfepriv = mfe->frontend_priv;
-                               mutex_unlock (&adapter->mfe_lock);
-                               mferetry = (dvb_mfe_wait_time << 1);
-                               while (mferetry-- && (mfedev->users != -1 || mfepriv->thread != NULL)) {
-                                       if(msleep_interruptible(500)) {
-                                               if(signal_pending(current))
-                                                       return -EINTR;
-                                       }
+
+               if (adapter->mfe_dvbdev == NULL)
+                       adapter->mfe_dvbdev = dvbdev;
+
+               else if (adapter->mfe_dvbdev != dvbdev) {
+                       struct dvb_device
+                               *mfedev = adapter->mfe_dvbdev;
+                       struct dvb_frontend
+                               *mfe = mfedev->priv;
+                       struct dvb_frontend_private
+                               *mfepriv = mfe->frontend_priv;
+                       int mferetry = (dvb_mfe_wait_time << 1);
+
+                       mutex_unlock (&adapter->mfe_lock);
+                       while (mferetry-- && (mfedev->users != -1 ||
+                                       mfepriv->thread != NULL)) {
+                               if(msleep_interruptible(500)) {
+                                       if(signal_pending(current))
+                                               return -EINTR;
                                }
-                               mutex_lock (&adapter->mfe_lock);
+                       }
+
+                       mutex_lock (&adapter->mfe_lock);
+                       if(adapter->mfe_dvbdev != dvbdev) {
                                mfedev = adapter->mfe_dvbdev;
                                mfe = mfedev->priv;
                                mfepriv = mfe->frontend_priv;
-                               if (mfedev->users != -1 || mfepriv->thread != NULL) {
-                                       ret = -EBUSY;
-                                       goto err0;
+                               if (mfedev->users != -1 ||
+                                               mfepriv->thread != NULL) {
+                                       mutex_unlock (&adapter->mfe_lock);
+                                       return -EBUSY;
                                }
+                               adapter->mfe_dvbdev = dvbdev;
                        }
-                       adapter->mfe_dvbdev = dvbdev;
                }
        }