V4L/DVB (8505): saa7134-empress.c: fix deadlock
ts_release() locked a mutex that videobuf_stop() also tried to obtain. But ts_release() shouldn't hold that mutex at all. Make empress_users atomic as well to prevent possible race condition. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
This commit is contained in:
parent
feb75f0710
commit
1052efe0fc
@ -89,14 +89,14 @@ static int ts_open(struct inode *inode, struct file *file)
|
|||||||
err = -EBUSY;
|
err = -EBUSY;
|
||||||
if (!mutex_trylock(&dev->empress_tsq.vb_lock))
|
if (!mutex_trylock(&dev->empress_tsq.vb_lock))
|
||||||
goto done;
|
goto done;
|
||||||
if (dev->empress_users)
|
if (atomic_read(&dev->empress_users))
|
||||||
goto done_up;
|
goto done_up;
|
||||||
|
|
||||||
/* Unmute audio */
|
/* Unmute audio */
|
||||||
saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
|
saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
|
||||||
saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));
|
saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));
|
||||||
|
|
||||||
dev->empress_users++;
|
atomic_inc(&dev->empress_users);
|
||||||
file->private_data = dev;
|
file->private_data = dev;
|
||||||
err = 0;
|
err = 0;
|
||||||
|
|
||||||
@ -110,8 +110,6 @@ static int ts_release(struct inode *inode, struct file *file)
|
|||||||
{
|
{
|
||||||
struct saa7134_dev *dev = file->private_data;
|
struct saa7134_dev *dev = file->private_data;
|
||||||
|
|
||||||
mutex_lock(&dev->empress_tsq.vb_lock);
|
|
||||||
|
|
||||||
videobuf_stop(&dev->empress_tsq);
|
videobuf_stop(&dev->empress_tsq);
|
||||||
videobuf_mmap_free(&dev->empress_tsq);
|
videobuf_mmap_free(&dev->empress_tsq);
|
||||||
|
|
||||||
@ -122,9 +120,7 @@ static int ts_release(struct inode *inode, struct file *file)
|
|||||||
saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
|
saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
|
||||||
saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
|
saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
|
||||||
|
|
||||||
dev->empress_users--;
|
atomic_dec(&dev->empress_users);
|
||||||
|
|
||||||
mutex_unlock(&dev->empress_tsq.vb_lock);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -447,7 +443,7 @@ static void empress_signal_update(struct work_struct *work)
|
|||||||
ts_reset_encoder(dev);
|
ts_reset_encoder(dev);
|
||||||
} else {
|
} else {
|
||||||
dprintk("video signal acquired\n");
|
dprintk("video signal acquired\n");
|
||||||
if (dev->empress_users)
|
if (atomic_read(&dev->empress_users))
|
||||||
ts_init_encoder(dev);
|
ts_init_encoder(dev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -561,7 +561,7 @@ struct saa7134_dev {
|
|||||||
/* SAA7134_MPEG_EMPRESS only */
|
/* SAA7134_MPEG_EMPRESS only */
|
||||||
struct video_device *empress_dev;
|
struct video_device *empress_dev;
|
||||||
struct videobuf_queue empress_tsq;
|
struct videobuf_queue empress_tsq;
|
||||||
unsigned int empress_users;
|
atomic_t empress_users;
|
||||||
struct work_struct empress_workqueue;
|
struct work_struct empress_workqueue;
|
||||||
int empress_started;
|
int empress_started;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user