diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2008-07-26 08:01:24 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-07-27 10:06:23 -0400 |
commit | 1052efe0fc69130d9d6a44bc9ceecd229221d9a1 (patch) | |
tree | 7e7f19cbbd3ff023e80eb7da5b68469085bdfe59 | |
parent | feb75f07102a85026d41e2c4e4113c34dd035c30 (diff) |
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>
-rw-r--r-- | drivers/media/video/saa7134/saa7134-empress.c | 12 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134.h | 2 |
2 files changed, 5 insertions, 9 deletions
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 8b3f95167781..2ecfbd1b41fc 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c | |||
@@ -89,14 +89,14 @@ static int ts_open(struct inode *inode, struct file *file) | |||
89 | err = -EBUSY; | 89 | err = -EBUSY; |
90 | if (!mutex_trylock(&dev->empress_tsq.vb_lock)) | 90 | if (!mutex_trylock(&dev->empress_tsq.vb_lock)) |
91 | goto done; | 91 | goto done; |
92 | if (dev->empress_users) | 92 | if (atomic_read(&dev->empress_users)) |
93 | goto done_up; | 93 | goto done_up; |
94 | 94 | ||
95 | /* Unmute audio */ | 95 | /* Unmute audio */ |
96 | saa_writeb(SAA7134_AUDIO_MUTE_CTRL, | 96 | saa_writeb(SAA7134_AUDIO_MUTE_CTRL, |
97 | saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6)); | 97 | saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6)); |
98 | 98 | ||
99 | dev->empress_users++; | 99 | atomic_inc(&dev->empress_users); |
100 | file->private_data = dev; | 100 | file->private_data = dev; |
101 | err = 0; | 101 | err = 0; |
102 | 102 | ||
@@ -110,8 +110,6 @@ static int ts_release(struct inode *inode, struct file *file) | |||
110 | { | 110 | { |
111 | struct saa7134_dev *dev = file->private_data; | 111 | struct saa7134_dev *dev = file->private_data; |
112 | 112 | ||
113 | mutex_lock(&dev->empress_tsq.vb_lock); | ||
114 | |||
115 | videobuf_stop(&dev->empress_tsq); | 113 | videobuf_stop(&dev->empress_tsq); |
116 | videobuf_mmap_free(&dev->empress_tsq); | 114 | videobuf_mmap_free(&dev->empress_tsq); |
117 | 115 | ||
@@ -122,9 +120,7 @@ static int ts_release(struct inode *inode, struct file *file) | |||
122 | saa_writeb(SAA7134_AUDIO_MUTE_CTRL, | 120 | saa_writeb(SAA7134_AUDIO_MUTE_CTRL, |
123 | saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6)); | 121 | saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6)); |
124 | 122 | ||
125 | dev->empress_users--; | 123 | atomic_dec(&dev->empress_users); |
126 | |||
127 | mutex_unlock(&dev->empress_tsq.vb_lock); | ||
128 | 124 | ||
129 | return 0; | 125 | return 0; |
130 | } | 126 | } |
@@ -447,7 +443,7 @@ static void empress_signal_update(struct work_struct *work) | |||
447 | ts_reset_encoder(dev); | 443 | ts_reset_encoder(dev); |
448 | } else { | 444 | } else { |
449 | dprintk("video signal acquired\n"); | 445 | dprintk("video signal acquired\n"); |
450 | if (dev->empress_users) | 446 | if (atomic_read(&dev->empress_users)) |
451 | ts_init_encoder(dev); | 447 | ts_init_encoder(dev); |
452 | } | 448 | } |
453 | } | 449 | } |
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index ade4e19799e9..ed20dd56379c 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h | |||
@@ -561,7 +561,7 @@ struct saa7134_dev { | |||
561 | /* SAA7134_MPEG_EMPRESS only */ | 561 | /* SAA7134_MPEG_EMPRESS only */ |
562 | struct video_device *empress_dev; | 562 | struct video_device *empress_dev; |
563 | struct videobuf_queue empress_tsq; | 563 | struct videobuf_queue empress_tsq; |
564 | unsigned int empress_users; | 564 | atomic_t empress_users; |
565 | struct work_struct empress_workqueue; | 565 | struct work_struct empress_workqueue; |
566 | int empress_started; | 566 | int empress_started; |
567 | 567 | ||