media: v4l2-dev: lock req_queue_mutex
We need to serialize streamon/off with queueing new requests. These ioctls may trigger the cancellation of a streaming operation, and that should not be mixed with queuing a new request at the same time. Finally close() needs this lock since that too can trigger the cancellation of a streaming operation. We take the req_queue_mutex here before any other locks since it is a very high-level lock. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Reviewed-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
This commit is contained in:
parent
93a9d9008d
commit
cc6eddcd37
|
@ -444,8 +444,22 @@ static int v4l2_release(struct inode *inode, struct file *filp)
|
|||
struct video_device *vdev = video_devdata(filp);
|
||||
int ret = 0;
|
||||
|
||||
if (vdev->fops->release)
|
||||
ret = vdev->fops->release(filp);
|
||||
/*
|
||||
* We need to serialize the release() with queueing new requests.
|
||||
* The release() may trigger the cancellation of a streaming
|
||||
* operation, and that should not be mixed with queueing a new
|
||||
* request at the same time.
|
||||
*/
|
||||
if (vdev->fops->release) {
|
||||
if (v4l2_device_supports_requests(vdev->v4l2_dev)) {
|
||||
mutex_lock(&vdev->v4l2_dev->mdev->req_queue_mutex);
|
||||
ret = vdev->fops->release(filp);
|
||||
mutex_unlock(&vdev->v4l2_dev->mdev->req_queue_mutex);
|
||||
} else {
|
||||
ret = vdev->fops->release(filp);
|
||||
}
|
||||
}
|
||||
|
||||
if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP)
|
||||
dprintk("%s: release\n",
|
||||
video_device_node_name(vdev));
|
||||
|
|
|
@ -2780,6 +2780,7 @@ static long __video_do_ioctl(struct file *file,
|
|||
unsigned int cmd, void *arg)
|
||||
{
|
||||
struct video_device *vfd = video_devdata(file);
|
||||
struct mutex *req_queue_lock = NULL;
|
||||
struct mutex *lock; /* ioctl serialization mutex */
|
||||
const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
|
||||
bool write_only = false;
|
||||
|
@ -2799,10 +2800,27 @@ static long __video_do_ioctl(struct file *file,
|
|||
if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags))
|
||||
vfh = file->private_data;
|
||||
|
||||
/*
|
||||
* We need to serialize streamon/off with queueing new requests.
|
||||
* These ioctls may trigger the cancellation of a streaming
|
||||
* operation, and that should not be mixed with queueing a new
|
||||
* request at the same time.
|
||||
*/
|
||||
if (v4l2_device_supports_requests(vfd->v4l2_dev) &&
|
||||
(cmd == VIDIOC_STREAMON || cmd == VIDIOC_STREAMOFF)) {
|
||||
req_queue_lock = &vfd->v4l2_dev->mdev->req_queue_mutex;
|
||||
|
||||
if (mutex_lock_interruptible(req_queue_lock))
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
lock = v4l2_ioctl_get_lock(vfd, vfh, cmd, arg);
|
||||
|
||||
if (lock && mutex_lock_interruptible(lock))
|
||||
if (lock && mutex_lock_interruptible(lock)) {
|
||||
if (req_queue_lock)
|
||||
mutex_unlock(req_queue_lock);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
if (!video_is_registered(vfd)) {
|
||||
ret = -ENODEV;
|
||||
|
@ -2861,6 +2879,8 @@ done:
|
|||
unlock:
|
||||
if (lock)
|
||||
mutex_unlock(lock);
|
||||
if (req_queue_lock)
|
||||
mutex_unlock(req_queue_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue