summaryrefslogtreecommitdiff
path: root/drivers/media/usb/uvc/uvc_v4l2.c
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2013-04-26 05:28:51 +0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-06-09 02:51:16 +0400
commit17706f5653a90ff277b5b36c2eb60ff872df5e7a (patch)
tree110fbcca442fc9801187db3b73de32897fe9b9a0 /drivers/media/usb/uvc/uvc_v4l2.c
parentc2a273b24f2c82184cc0f04ba3a61da51c84724b (diff)
downloadlinux-17706f5653a90ff277b5b36c2eb60ff872df5e7a.tar.xz
[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)
return -ENOMEM;
}
- if (atomic_inc_return(&stream->dev->users) == 1) {
- ret = uvc_status_start(stream->dev);
+ mutex_lock(&stream->dev->lock);
+ if (stream->dev->users == 0) {
+ ret = uvc_status_start(stream->dev, GFP_KERNEL);
if (ret < 0) {
- atomic_dec(&stream->dev->users);
+ mutex_unlock(&stream->dev->lock);
usb_autopm_put_interface(stream->dev->intf);
kfree(handle);
return ret;
}
}
+ stream->dev->users++;
+ mutex_unlock(&stream->dev->lock);
+
v4l2_fh_init(&handle->vfh, stream->vdev);
v4l2_fh_add(&handle->vfh);
handle->chain = stream->chain;
@@ -538,8 +542,10 @@ static int uvc_v4l2_release(struct file *file)
kfree(handle);
file->private_data = NULL;
- if (atomic_dec_return(&stream->dev->users) == 0)
+ mutex_lock(&stream->dev->lock);
+ if (--stream->dev->users == 0)
uvc_status_stop(stream->dev);
+ mutex_unlock(&stream->dev->lock);
usb_autopm_put_interface(stream->dev->intf);
return 0;