From 73a110623e7b7592defea69f028cccae495d69a4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 11 May 2018 05:32:24 -0400 Subject: media: v4l2-core: push taking ioctl mutex down to ioctl handler The ioctl serialization mutex (vdev->lock or q->lock for vb2 queues) was taken at the highest level in v4l2-dev.c. This prevents more fine-grained locking since at that level we cannot examine the ioctl arguments, we can only do that after video_usercopy is called. So push the locking down to __video_do_ioctl() and subdev_do_ioctl_lock(). This also allows us to make a few functions in v4l2-ioctl.c static and video_usercopy() is no longer exported. The locking scheme is not changed by this patch, just pushed down. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-dev.c | 6 ------ drivers/media/v4l2-core/v4l2-ioctl.c | 20 +++++++++++++++++--- drivers/media/v4l2-core/v4l2-subdev.c | 17 ++++++++++++++++- 3 files changed, 33 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index c4f4357e9ca4..4ffd7d60a901 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -360,14 +360,8 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) int ret = -ENODEV; if (vdev->fops->unlocked_ioctl) { - struct mutex *lock = v4l2_ioctl_get_lock(vdev, cmd); - - if (lock && mutex_lock_interruptible(lock)) - return -ERESTARTSYS; if (video_is_registered(vdev)) ret = vdev->fops->unlocked_ioctl(filp, cmd, arg); - if (lock) - mutex_unlock(lock); } else ret = -ENOTTY; diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index c23fbfe90a9e..965fd301f617 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2655,14 +2655,15 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = { }; #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) -bool v4l2_is_known_ioctl(unsigned int cmd) +static bool v4l2_is_known_ioctl(unsigned int cmd) { if (_IOC_NR(cmd) >= V4L2_IOCTLS) return false; return v4l2_ioctls[_IOC_NR(cmd)].ioctl == cmd; } -struct mutex *v4l2_ioctl_get_lock(struct video_device *vdev, unsigned cmd) +static struct mutex *v4l2_ioctl_get_lock(struct video_device *vdev, + unsigned int cmd) { if (_IOC_NR(cmd) >= V4L2_IOCTLS) return vdev->lock; @@ -2713,6 +2714,7 @@ static long __video_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct video_device *vfd = video_devdata(file); + struct mutex *lock; /* ioctl serialization mutex */ const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; bool write_only = false; struct v4l2_ioctl_info default_info; @@ -2731,6 +2733,16 @@ static long __video_do_ioctl(struct file *file, if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) vfh = file->private_data; + lock = v4l2_ioctl_get_lock(vfd, cmd); + + if (lock && mutex_lock_interruptible(lock)) + return -ERESTARTSYS; + + if (!video_is_registered(vfd)) { + ret = -ENODEV; + goto unlock; + } + if (v4l2_is_known_ioctl(cmd)) { info = &v4l2_ioctls[_IOC_NR(cmd)]; @@ -2780,6 +2792,9 @@ done: } } +unlock: + if (lock) + mutex_unlock(lock); return ret; } @@ -2969,7 +2984,6 @@ out: kvfree(mbuf); return err; } -EXPORT_SYMBOL(video_usercopy); long video_ioctl2(struct file *file, unsigned int cmd, unsigned long arg) diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index f9eed938d348..6a7f7f75dfd7 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -502,10 +502,25 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) return 0; } +static long subdev_do_ioctl_lock(struct file *file, unsigned int cmd, void *arg) +{ + struct video_device *vdev = video_devdata(file); + struct mutex *lock = vdev->lock; + long ret = -ENODEV; + + if (lock && mutex_lock_interruptible(lock)) + return -ERESTARTSYS; + if (video_is_registered(vdev)) + ret = subdev_do_ioctl(file, cmd, arg); + if (lock) + mutex_unlock(lock); + return ret; +} + static long subdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - return video_usercopy(file, cmd, arg, subdev_do_ioctl); + return video_usercopy(file, cmd, arg, subdev_do_ioctl_lock); } #ifdef CONFIG_COMPAT -- cgit v1.2.3