aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorDarron Broad <darron@kewl.org>2008-10-15 12:37:59 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-10-17 16:28:22 -0400
commit6594690b39f9f9fcadafb1caf019bfd7a326e2e5 (patch)
treef302b75e9c1e8827ec491bdc82aebe47c0773d27 /drivers/media
parent5c310b1360f4be8a2cf944d9d65892839ed27d00 (diff)
V4L/DVB (9264): MFE: bugfix: multi-frontend mutual exclusion parallel open
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>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c49
1 files changed, 28 insertions, 21 deletions
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 62696f865576..6c9b9be9e286 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -1710,39 +1710,46 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
1710 struct dvb_frontend *fe = dvbdev->priv; 1710 struct dvb_frontend *fe = dvbdev->priv;
1711 struct dvb_frontend_private *fepriv = fe->frontend_priv; 1711 struct dvb_frontend_private *fepriv = fe->frontend_priv;
1712 struct dvb_adapter *adapter = fe->dvb; 1712 struct dvb_adapter *adapter = fe->dvb;
1713 struct dvb_device *mfedev;
1714 struct dvb_frontend *mfe;
1715 struct dvb_frontend_private *mfepriv;
1716 int mferetry;
1717 int ret; 1713 int ret;
1718 1714
1719 dprintk ("%s\n", __func__); 1715 dprintk ("%s\n", __func__);
1720 1716
1721 if (adapter->mfe_shared) { 1717 if (adapter->mfe_shared) {
1722 mutex_lock (&adapter->mfe_lock); 1718 mutex_lock (&adapter->mfe_lock);
1723 if (adapter->mfe_dvbdev != dvbdev) { 1719
1724 if (adapter->mfe_dvbdev) { 1720 if (adapter->mfe_dvbdev == NULL)
1725 mfedev = adapter->mfe_dvbdev; 1721 adapter->mfe_dvbdev = dvbdev;
1726 mfe = mfedev->priv; 1722
1727 mfepriv = mfe->frontend_priv; 1723 else if (adapter->mfe_dvbdev != dvbdev) {
1728 mutex_unlock (&adapter->mfe_lock); 1724 struct dvb_device
1729 mferetry = (dvb_mfe_wait_time << 1); 1725 *mfedev = adapter->mfe_dvbdev;
1730 while (mferetry-- && (mfedev->users != -1 || mfepriv->thread != NULL)) { 1726 struct dvb_frontend
1731 if(msleep_interruptible(500)) { 1727 *mfe = mfedev->priv;
1732 if(signal_pending(current)) 1728 struct dvb_frontend_private
1733 return -EINTR; 1729 *mfepriv = mfe->frontend_priv;
1734 } 1730 int mferetry = (dvb_mfe_wait_time << 1);
1731
1732 mutex_unlock (&adapter->mfe_lock);
1733 while (mferetry-- && (mfedev->users != -1 ||
1734 mfepriv->thread != NULL)) {
1735 if(msleep_interruptible(500)) {
1736 if(signal_pending(current))
1737 return -EINTR;
1735 } 1738 }
1736 mutex_lock (&adapter->mfe_lock); 1739 }
1740
1741 mutex_lock (&adapter->mfe_lock);
1742 if(adapter->mfe_dvbdev != dvbdev) {
1737 mfedev = adapter->mfe_dvbdev; 1743 mfedev = adapter->mfe_dvbdev;
1738 mfe = mfedev->priv; 1744 mfe = mfedev->priv;
1739 mfepriv = mfe->frontend_priv; 1745 mfepriv = mfe->frontend_priv;
1740 if (mfedev->users != -1 || mfepriv->thread != NULL) { 1746 if (mfedev->users != -1 ||
1741 ret = -EBUSY; 1747 mfepriv->thread != NULL) {
1742 goto err0; 1748 mutex_unlock (&adapter->mfe_lock);
1749 return -EBUSY;
1743 } 1750 }
1751 adapter->mfe_dvbdev = dvbdev;
1744 } 1752 }
1745 adapter->mfe_dvbdev = dvbdev;
1746 } 1753 }
1747 } 1754 }
1748 1755