aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/usb/uvc/uvc_v4l2.c
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2013-04-25 21:28:51 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-06-08 18:51:16 -0400
commit17706f5653a90ff277b5b36c2eb60ff872df5e7a (patch)
tree110fbcca442fc9801187db3b73de32897fe9b9a0 /drivers/media/usb/uvc/uvc_v4l2.c
parentc2a273b24f2c82184cc0f04ba3a61da51c84724b (diff)
[media] uvcvideo: Fix open/close race condition
Maintaining the users count using an atomic variable makes sure that access to the counter won't be racy, but doesn't serialize access to the operations protected by the counter. This creates a race condition that could result in the status URB being submitted multiple times. Use a mutex to protect the users count and serialize access to the status start and stop operations. Reported-by: Shawn Nematbakhsh <shawnn@chromium.org> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/usb/uvc/uvc_v4l2.c')
-rw-r--r--drivers/media/usb/uvc/uvc_v4l2.c14
1 files changed, 10 insertions, 4 deletions
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index b2dc32623a71..3afff92804d3 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -498,16 +498,20 @@ static int uvc_v4l2_open(struct file *file)
498 return -ENOMEM; 498 return -ENOMEM;
499 } 499 }
500 500
501 if (atomic_inc_return(&stream->dev->users) == 1) { 501 mutex_lock(&stream->dev->lock);
502 ret = uvc_status_start(stream->dev); 502 if (stream->dev->users == 0) {
503 ret = uvc_status_start(stream->dev, GFP_KERNEL);
503 if (ret < 0) { 504 if (ret < 0) {
504 atomic_dec(&stream->dev->users); 505 mutex_unlock(&stream->dev->lock);
505 usb_autopm_put_interface(stream->dev->intf); 506 usb_autopm_put_interface(stream->dev->intf);
506 kfree(handle); 507 kfree(handle);
507 return ret; 508 return ret;
508 } 509 }
509 } 510 }
510 511
512 stream->dev->users++;
513 mutex_unlock(&stream->dev->lock);
514
511 v4l2_fh_init(&handle->vfh, stream->vdev); 515 v4l2_fh_init(&handle->vfh, stream->vdev);
512 v4l2_fh_add(&handle->vfh); 516 v4l2_fh_add(&handle->vfh);
513 handle->chain = stream->chain; 517 handle->chain = stream->chain;
@@ -538,8 +542,10 @@ static int uvc_v4l2_release(struct file *file)
538 kfree(handle); 542 kfree(handle);
539 file->private_data = NULL; 543 file->private_data = NULL;
540 544
541 if (atomic_dec_return(&stream->dev->users) == 0) 545 mutex_lock(&stream->dev->lock);
546 if (--stream->dev->users == 0)
542 uvc_status_stop(stream->dev); 547 uvc_status_stop(stream->dev);
548 mutex_unlock(&stream->dev->lock);
543 549
544 usb_autopm_put_interface(stream->dev->intf); 550 usb_autopm_put_interface(stream->dev->intf);
545 return 0; 551 return 0;