media: v4l2-core: push taking ioctl mutex down to ioctl handler
authorHans Verkuil <hansverk@cisco.com>
Fri, 11 May 2018 09:32:24 +0000 (05:32 -0400)
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Mon, 28 May 2018 20:31:44 +0000 (16:31 -0400)
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 <hansverk@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
drivers/media/v4l2-core/v4l2-dev.c
drivers/media/v4l2-core/v4l2-ioctl.c
drivers/media/v4l2-core/v4l2-subdev.c
include/media/v4l2-dev.h
include/media/v4l2-ioctl.h

index c4f4357..4ffd7d6 100644 (file)
@@ -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;
 
index c23fbfe..965fd30 100644 (file)
@@ -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)
index f9eed93..6a7f7f7 100644 (file)
@@ -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
index 30423ae..456ac13 100644 (file)
@@ -436,15 +436,6 @@ void video_device_release(struct video_device *vdev);
 void video_device_release_empty(struct video_device *vdev);
 
 /**
- * v4l2_is_known_ioctl - Checks if a given cmd is a known V4L ioctl
- *
- * @cmd: ioctl command
- *
- * returns true if cmd is a known V4L2 ioctl
- */
-bool v4l2_is_known_ioctl(unsigned int cmd);
-
-/**
  * v4l2_disable_ioctl- mark that a given command isn't implemented.
  *     shouldn't use core locking
  *
index a7b3f7c..a8dbf5b 100644 (file)
@@ -658,18 +658,6 @@ void v4l_printk_ioctl(const char *prefix, unsigned int cmd);
 
 struct video_device;
 
-
-/**
- * v4l2_ioctl_get_lock - get the mutex (if any) that it is need to lock for
- *     a given command.
- *
- * @vdev: Pointer to struct &video_device.
- * @cmd: Ioctl name.
- *
- * .. note:: Internal use only. Should not be used outside V4L2 core.
- */
-struct mutex *v4l2_ioctl_get_lock(struct video_device *vdev, unsigned int cmd);
-
 /* names for fancy debug output */
 extern const char *v4l2_field_names[];
 extern const char *v4l2_type_names[];