aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/v4l2-dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/v4l2-dev.c')
-rw-r--r--drivers/media/video/v4l2-dev.c72
1 files changed, 53 insertions, 19 deletions
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 0ca7978654b5..359e23290a7e 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -25,7 +25,6 @@
25#include <linux/init.h> 25#include <linux/init.h>
26#include <linux/kmod.h> 26#include <linux/kmod.h>
27#include <linux/slab.h> 27#include <linux/slab.h>
28#include <linux/smp_lock.h>
29#include <asm/uaccess.h> 28#include <asm/uaccess.h>
30#include <asm/system.h> 29#include <asm/system.h>
31 30
@@ -187,12 +186,12 @@ static ssize_t v4l2_read(struct file *filp, char __user *buf,
187 size_t sz, loff_t *off) 186 size_t sz, loff_t *off)
188{ 187{
189 struct video_device *vdev = video_devdata(filp); 188 struct video_device *vdev = video_devdata(filp);
190 int ret = -EIO; 189 int ret = -ENODEV;
191 190
192 if (!vdev->fops->read) 191 if (!vdev->fops->read)
193 return -EINVAL; 192 return -EINVAL;
194 if (vdev->lock) 193 if (vdev->lock && mutex_lock_interruptible(vdev->lock))
195 mutex_lock(vdev->lock); 194 return -ERESTARTSYS;
196 if (video_is_registered(vdev)) 195 if (video_is_registered(vdev))
197 ret = vdev->fops->read(filp, buf, sz, off); 196 ret = vdev->fops->read(filp, buf, sz, off);
198 if (vdev->lock) 197 if (vdev->lock)
@@ -204,12 +203,12 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf,
204 size_t sz, loff_t *off) 203 size_t sz, loff_t *off)
205{ 204{
206 struct video_device *vdev = video_devdata(filp); 205 struct video_device *vdev = video_devdata(filp);
207 int ret = -EIO; 206 int ret = -ENODEV;
208 207
209 if (!vdev->fops->write) 208 if (!vdev->fops->write)
210 return -EINVAL; 209 return -EINVAL;
211 if (vdev->lock) 210 if (vdev->lock && mutex_lock_interruptible(vdev->lock))
212 mutex_lock(vdev->lock); 211 return -ERESTARTSYS;
213 if (video_is_registered(vdev)) 212 if (video_is_registered(vdev))
214 ret = vdev->fops->write(filp, buf, sz, off); 213 ret = vdev->fops->write(filp, buf, sz, off);
215 if (vdev->lock) 214 if (vdev->lock)
@@ -220,10 +219,10 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf,
220static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll) 219static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll)
221{ 220{
222 struct video_device *vdev = video_devdata(filp); 221 struct video_device *vdev = video_devdata(filp);
223 int ret = DEFAULT_POLLMASK; 222 int ret = POLLERR | POLLHUP;
224 223
225 if (!vdev->fops->poll) 224 if (!vdev->fops->poll)
226 return ret; 225 return DEFAULT_POLLMASK;
227 if (vdev->lock) 226 if (vdev->lock)
228 mutex_lock(vdev->lock); 227 mutex_lock(vdev->lock);
229 if (video_is_registered(vdev)) 228 if (video_is_registered(vdev))
@@ -239,18 +238,45 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
239 int ret = -ENODEV; 238 int ret = -ENODEV;
240 239
241 if (vdev->fops->unlocked_ioctl) { 240 if (vdev->fops->unlocked_ioctl) {
242 if (vdev->lock) 241 if (vdev->lock && mutex_lock_interruptible(vdev->lock))
243 mutex_lock(vdev->lock); 242 return -ERESTARTSYS;
244 if (video_is_registered(vdev)) 243 if (video_is_registered(vdev))
245 ret = vdev->fops->unlocked_ioctl(filp, cmd, arg); 244 ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
246 if (vdev->lock) 245 if (vdev->lock)
247 mutex_unlock(vdev->lock); 246 mutex_unlock(vdev->lock);
248 } else if (vdev->fops->ioctl) { 247 } else if (vdev->fops->ioctl) {
249 /* TODO: convert all drivers to unlocked_ioctl */ 248 /* This code path is a replacement for the BKL. It is a major
250 lock_kernel(); 249 * hack but it will have to do for those drivers that are not
250 * yet converted to use unlocked_ioctl.
251 *
252 * There are two options: if the driver implements struct
253 * v4l2_device, then the lock defined there is used to
254 * serialize the ioctls. Otherwise the v4l2 core lock defined
255 * below is used. This lock is really bad since it serializes
256 * completely independent devices.
257 *
258 * Both variants suffer from the same problem: if the driver
259 * sleeps, then it blocks all ioctls since the lock is still
260 * held. This is very common for VIDIOC_DQBUF since that
261 * normally waits for a frame to arrive. As a result any other
262 * ioctl calls will proceed very, very slowly since each call
263 * will have to wait for the VIDIOC_QBUF to finish. Things that
264 * should take 0.01s may now take 10-20 seconds.
265 *
266 * The workaround is to *not* take the lock for VIDIOC_DQBUF.
267 * This actually works OK for videobuf-based drivers, since
268 * videobuf will take its own internal lock.
269 */
270 static DEFINE_MUTEX(v4l2_ioctl_mutex);
271 struct mutex *m = vdev->v4l2_dev ?
272 &vdev->v4l2_dev->ioctl_lock : &v4l2_ioctl_mutex;
273
274 if (cmd != VIDIOC_DQBUF && mutex_lock_interruptible(m))
275 return -ERESTARTSYS;
251 if (video_is_registered(vdev)) 276 if (video_is_registered(vdev))
252 ret = vdev->fops->ioctl(filp, cmd, arg); 277 ret = vdev->fops->ioctl(filp, cmd, arg);
253 unlock_kernel(); 278 if (cmd != VIDIOC_DQBUF)
279 mutex_unlock(m);
254 } else 280 } else
255 ret = -ENOTTY; 281 ret = -ENOTTY;
256 282
@@ -264,8 +290,8 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
264 290
265 if (!vdev->fops->mmap) 291 if (!vdev->fops->mmap)
266 return ret; 292 return ret;
267 if (vdev->lock) 293 if (vdev->lock && mutex_lock_interruptible(vdev->lock))
268 mutex_lock(vdev->lock); 294 return -ERESTARTSYS;
269 if (video_is_registered(vdev)) 295 if (video_is_registered(vdev))
270 ret = vdev->fops->mmap(filp, vm); 296 ret = vdev->fops->mmap(filp, vm);
271 if (vdev->lock) 297 if (vdev->lock)
@@ -283,7 +309,7 @@ static int v4l2_open(struct inode *inode, struct file *filp)
283 mutex_lock(&videodev_lock); 309 mutex_lock(&videodev_lock);
284 vdev = video_devdata(filp); 310 vdev = video_devdata(filp);
285 /* return ENODEV if the video device has already been removed. */ 311 /* return ENODEV if the video device has already been removed. */
286 if (vdev == NULL) { 312 if (vdev == NULL || !video_is_registered(vdev)) {
287 mutex_unlock(&videodev_lock); 313 mutex_unlock(&videodev_lock);
288 return -ENODEV; 314 return -ENODEV;
289 } 315 }
@@ -291,8 +317,10 @@ static int v4l2_open(struct inode *inode, struct file *filp)
291 video_get(vdev); 317 video_get(vdev);
292 mutex_unlock(&videodev_lock); 318 mutex_unlock(&videodev_lock);
293 if (vdev->fops->open) { 319 if (vdev->fops->open) {
294 if (vdev->lock) 320 if (vdev->lock && mutex_lock_interruptible(vdev->lock)) {
295 mutex_lock(vdev->lock); 321 ret = -ERESTARTSYS;
322 goto err;
323 }
296 if (video_is_registered(vdev)) 324 if (video_is_registered(vdev))
297 ret = vdev->fops->open(filp); 325 ret = vdev->fops->open(filp);
298 else 326 else
@@ -301,6 +329,7 @@ static int v4l2_open(struct inode *inode, struct file *filp)
301 mutex_unlock(vdev->lock); 329 mutex_unlock(vdev->lock);
302 } 330 }
303 331
332err:
304 /* decrease the refcount in case of an error */ 333 /* decrease the refcount in case of an error */
305 if (ret) 334 if (ret)
306 video_put(vdev); 335 video_put(vdev);
@@ -595,7 +624,12 @@ void video_unregister_device(struct video_device *vdev)
595 if (!vdev || !video_is_registered(vdev)) 624 if (!vdev || !video_is_registered(vdev))
596 return; 625 return;
597 626
627 mutex_lock(&videodev_lock);
628 /* This must be in a critical section to prevent a race with v4l2_open.
629 * Once this bit has been cleared video_get may never be called again.
630 */
598 clear_bit(V4L2_FL_REGISTERED, &vdev->flags); 631 clear_bit(V4L2_FL_REGISTERED, &vdev->flags);
632 mutex_unlock(&videodev_lock);
599 device_unregister(&vdev->dev); 633 device_unregister(&vdev->dev);
600} 634}
601EXPORT_SYMBOL(video_unregister_device); 635EXPORT_SYMBOL(video_unregister_device);