diff mbox series

[v3,7/8] media: subdev: fix compat_ioctl32

Message ID 20210614103409.3154127-8-arnd@kernel.org (mailing list archive)
State New, archived
Headers show
Series media: v4l2: compat ioctl fixes | expand

Commit Message

Arnd Bergmann June 14, 2021, 10:34 a.m. UTC
From: Arnd Bergmann <arnd@arndb.de>

The adv7842 and si4713 drivers each define one private ioctl command that
are handled through the subdev_ioctl() helpers, but that don't work in
compat mode because this does not handle private ioctl commands.

The compat_ioctl32 callback for subdevs has outdated calling conventions,
but as there are no users of that, it is easy to change the function
pointer type and the caller to make it behave the same way as the normal
ioctl callback and hook in the two drivers that need no argument
conversion.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/media/i2c/adv7842.c           |  3 +++
 drivers/media/radio/si4713/si4713.c   |  3 +++
 drivers/media/v4l2-core/v4l2-subdev.c | 19 ++++++++++++++++---
 include/media/v4l2-subdev.h           |  3 +--
 4 files changed, 23 insertions(+), 5 deletions(-)

Comments

Laurent Pinchart June 14, 2021, 5:18 p.m. UTC | #1
Hi Arnd,

Thank you for the patch.

On Mon, Jun 14, 2021 at 12:34:08PM +0200, Arnd Bergmann wrote:
> From: Arnd Bergmann <arnd@arndb.de>
> 
> The adv7842 and si4713 drivers each define one private ioctl command that
> are handled through the subdev_ioctl() helpers, but that don't work in

s/don't/doesn't/

> compat mode because this does not handle private ioctl commands.
> 
> The compat_ioctl32 callback for subdevs has outdated calling conventions,
> but as there are no users of that, it is easy to change the function
> pointer type and the caller to make it behave the same way as the normal
> ioctl callback and hook in the two drivers that need no argument
> conversion.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
>  drivers/media/i2c/adv7842.c           |  3 +++
>  drivers/media/radio/si4713/si4713.c   |  3 +++
>  drivers/media/v4l2-core/v4l2-subdev.c | 19 ++++++++++++++++---
>  include/media/v4l2-subdev.h           |  3 +--
>  4 files changed, 23 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
> index 78e61fe6f2f0..cd6df4f52f33 100644
> --- a/drivers/media/i2c/adv7842.c
> +++ b/drivers/media/i2c/adv7842.c
> @@ -3293,6 +3293,9 @@ static const struct v4l2_ctrl_ops adv7842_ctrl_ops = {
>  static const struct v4l2_subdev_core_ops adv7842_core_ops = {
>  	.log_status = adv7842_log_status,
>  	.ioctl = adv7842_ioctl,
> +#ifdef CONFIG_COMPAT
> +	.compat_ioctl32 = adv7842_ioctl,
> +#endif
>  	.interrupt_service_routine = adv7842_isr,
>  	.subscribe_event = adv7842_subscribe_event,
>  	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
> diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c
> index adbf43ff6a21..ae7e477774e3 100644
> --- a/drivers/media/radio/si4713/si4713.c
> +++ b/drivers/media/radio/si4713/si4713.c
> @@ -1398,6 +1398,9 @@ static const struct v4l2_ctrl_ops si4713_ctrl_ops = {
>  
>  static const struct v4l2_subdev_core_ops si4713_subdev_core_ops = {
>  	.ioctl		= si4713_ioctl,
> +#ifdef CONFIG_COMPAT
> +	.compat_ioctl32	= si4713_ioctl,
> +#endif

Should we drop v4l2_subdev_core_ops.compat_ioctl32 and call
v4l2_subdev_core_ops.ioctl from subdev_do_compat_ioctl32() ? New drivers
should design custom ioctls in a way that doesn't require compat code.

>  };
>  
>  static const struct v4l2_subdev_tuner_ops si4713_subdev_tuner_ops = {
> diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> index bf3aa9252458..fbd176d6c415 100644
> --- a/drivers/media/v4l2-core/v4l2-subdev.c
> +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> @@ -686,13 +686,26 @@ static long subdev_ioctl(struct file *file, unsigned int cmd,
>  }
>  
>  #ifdef CONFIG_COMPAT
> -static long subdev_compat_ioctl32(struct file *file, unsigned int cmd,
> -	unsigned long arg)
> +static long subdev_do_compat_ioctl32(struct file *file, unsigned int cmd, void *arg)
>  {
>  	struct video_device *vdev = video_devdata(file);
>  	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
> +	struct mutex *lock = vdev->lock;
> +	long ret = -ENODEV;
>  
> -	return v4l2_subdev_call(sd, core, compat_ioctl32, cmd, arg);
> +	if (lock && mutex_lock_interruptible(lock))
> +		return -ERESTARTSYS;
> +	if (video_is_registered(vdev))
> +		ret = v4l2_subdev_call(sd, core, compat_ioctl32, cmd, arg);
> +	if (lock)
> +		mutex_unlock(lock);
> +	return ret;
> +}
> +
> +static long subdev_compat_ioctl32(struct file *file, unsigned int cmd,
> +	unsigned long arg)
> +{
> +	return video_usercopy(file, cmd, arg, subdev_do_compat_ioctl32);
>  }
>  #endif
>  
> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> index d0e9a5bdb08b..42aa1f6c7c3f 100644
> --- a/include/media/v4l2-subdev.h
> +++ b/include/media/v4l2-subdev.h
> @@ -195,8 +195,7 @@ struct v4l2_subdev_core_ops {
>  	int (*s_gpio)(struct v4l2_subdev *sd, u32 val);
>  	long (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
>  #ifdef CONFIG_COMPAT
> -	long (*compat_ioctl32)(struct v4l2_subdev *sd, unsigned int cmd,
> -			       unsigned long arg);
> +	long (*compat_ioctl32)(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
>  #endif
>  #ifdef CONFIG_VIDEO_ADV_DEBUG
>  	int (*g_register)(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg);
Hans Verkuil June 15, 2021, 8:26 a.m. UTC | #2
On 14/06/2021 19:18, Laurent Pinchart wrote:
> Hi Arnd,
> 
> Thank you for the patch.
> 
> On Mon, Jun 14, 2021 at 12:34:08PM +0200, Arnd Bergmann wrote:
>> From: Arnd Bergmann <arnd@arndb.de>
>>
>> The adv7842 and si4713 drivers each define one private ioctl command that
>> are handled through the subdev_ioctl() helpers, but that don't work in
> 
> s/don't/doesn't/
> 
>> compat mode because this does not handle private ioctl commands.
>>
>> The compat_ioctl32 callback for subdevs has outdated calling conventions,
>> but as there are no users of that, it is easy to change the function
>> pointer type and the caller to make it behave the same way as the normal
>> ioctl callback and hook in the two drivers that need no argument
>> conversion.
>>
>> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
>> ---
>>  drivers/media/i2c/adv7842.c           |  3 +++
>>  drivers/media/radio/si4713/si4713.c   |  3 +++
>>  drivers/media/v4l2-core/v4l2-subdev.c | 19 ++++++++++++++++---
>>  include/media/v4l2-subdev.h           |  3 +--
>>  4 files changed, 23 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
>> index 78e61fe6f2f0..cd6df4f52f33 100644
>> --- a/drivers/media/i2c/adv7842.c
>> +++ b/drivers/media/i2c/adv7842.c
>> @@ -3293,6 +3293,9 @@ static const struct v4l2_ctrl_ops adv7842_ctrl_ops = {
>>  static const struct v4l2_subdev_core_ops adv7842_core_ops = {
>>  	.log_status = adv7842_log_status,
>>  	.ioctl = adv7842_ioctl,
>> +#ifdef CONFIG_COMPAT
>> +	.compat_ioctl32 = adv7842_ioctl,
>> +#endif
>>  	.interrupt_service_routine = adv7842_isr,
>>  	.subscribe_event = adv7842_subscribe_event,
>>  	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
>> diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c
>> index adbf43ff6a21..ae7e477774e3 100644
>> --- a/drivers/media/radio/si4713/si4713.c
>> +++ b/drivers/media/radio/si4713/si4713.c
>> @@ -1398,6 +1398,9 @@ static const struct v4l2_ctrl_ops si4713_ctrl_ops = {
>>  
>>  static const struct v4l2_subdev_core_ops si4713_subdev_core_ops = {
>>  	.ioctl		= si4713_ioctl,
>> +#ifdef CONFIG_COMPAT
>> +	.compat_ioctl32	= si4713_ioctl,
>> +#endif
> 
> Should we drop v4l2_subdev_core_ops.compat_ioctl32 and call
> v4l2_subdev_core_ops.ioctl from subdev_do_compat_ioctl32() ? New drivers
> should design custom ioctls in a way that doesn't require compat code.

I agree, we can drop it completely.

I'll skip this patch, but I'll take the other 7 patches and make a v3 PR with
updated Reviewed-by tags from Laurent.

Regards,

	Hans

> 
>>  };
>>  
>>  static const struct v4l2_subdev_tuner_ops si4713_subdev_tuner_ops = {
>> diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
>> index bf3aa9252458..fbd176d6c415 100644
>> --- a/drivers/media/v4l2-core/v4l2-subdev.c
>> +++ b/drivers/media/v4l2-core/v4l2-subdev.c
>> @@ -686,13 +686,26 @@ static long subdev_ioctl(struct file *file, unsigned int cmd,
>>  }
>>  
>>  #ifdef CONFIG_COMPAT
>> -static long subdev_compat_ioctl32(struct file *file, unsigned int cmd,
>> -	unsigned long arg)
>> +static long subdev_do_compat_ioctl32(struct file *file, unsigned int cmd, void *arg)
>>  {
>>  	struct video_device *vdev = video_devdata(file);
>>  	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
>> +	struct mutex *lock = vdev->lock;
>> +	long ret = -ENODEV;
>>  
>> -	return v4l2_subdev_call(sd, core, compat_ioctl32, cmd, arg);
>> +	if (lock && mutex_lock_interruptible(lock))
>> +		return -ERESTARTSYS;
>> +	if (video_is_registered(vdev))
>> +		ret = v4l2_subdev_call(sd, core, compat_ioctl32, cmd, arg);
>> +	if (lock)
>> +		mutex_unlock(lock);
>> +	return ret;
>> +}
>> +
>> +static long subdev_compat_ioctl32(struct file *file, unsigned int cmd,
>> +	unsigned long arg)
>> +{
>> +	return video_usercopy(file, cmd, arg, subdev_do_compat_ioctl32);
>>  }
>>  #endif
>>  
>> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
>> index d0e9a5bdb08b..42aa1f6c7c3f 100644
>> --- a/include/media/v4l2-subdev.h
>> +++ b/include/media/v4l2-subdev.h
>> @@ -195,8 +195,7 @@ struct v4l2_subdev_core_ops {
>>  	int (*s_gpio)(struct v4l2_subdev *sd, u32 val);
>>  	long (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
>>  #ifdef CONFIG_COMPAT
>> -	long (*compat_ioctl32)(struct v4l2_subdev *sd, unsigned int cmd,
>> -			       unsigned long arg);
>> +	long (*compat_ioctl32)(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
>>  #endif
>>  #ifdef CONFIG_VIDEO_ADV_DEBUG
>>  	int (*g_register)(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg);
>
Arnd Bergmann June 15, 2021, 8:39 a.m. UTC | #3
On Tue, Jun 15, 2021 at 10:27 AM Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
> On 14/06/2021 19:18, Laurent Pinchart wrote:

> >
> > Should we drop v4l2_subdev_core_ops.compat_ioctl32 and call
> > v4l2_subdev_core_ops.ioctl from subdev_do_compat_ioctl32() ? New drivers
> > should design custom ioctls in a way that doesn't require compat code.
>
> I agree, we can drop it completely.

I agree about new drivers defining their ioctls in a compatible way,
though Ideally
I'd say subdev drivers should not use custom ioctls at all. There are
two other drivers
that define private subdev ioctls and that lack a working compat handler:

- the omap3 isp driver would not work in compat mode, though I don't think there
  are any 64-bit SoCs using this hardware. The Sitara AM6 and J72 SoCs
  are the only chips in that family at the moment, but these don't
seem to include
  any image processor.

- The Intel Atom ISP driver has a broken compat ioctl handler that I remove
  in this series, but the  v4l2_subdev_core_ops->compat_ioctl32 callback
  would be the correct place to hook these up if they do not get fixed.

> I'll skip this patch, but I'll take the other 7 patches and make a v3 PR with
> updated Reviewed-by tags from Laurent.

Thanks!

        Arnd
diff mbox series

Patch

diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index 78e61fe6f2f0..cd6df4f52f33 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -3293,6 +3293,9 @@  static const struct v4l2_ctrl_ops adv7842_ctrl_ops = {
 static const struct v4l2_subdev_core_ops adv7842_core_ops = {
 	.log_status = adv7842_log_status,
 	.ioctl = adv7842_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl32 = adv7842_ioctl,
+#endif
 	.interrupt_service_routine = adv7842_isr,
 	.subscribe_event = adv7842_subscribe_event,
 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c
index adbf43ff6a21..ae7e477774e3 100644
--- a/drivers/media/radio/si4713/si4713.c
+++ b/drivers/media/radio/si4713/si4713.c
@@ -1398,6 +1398,9 @@  static const struct v4l2_ctrl_ops si4713_ctrl_ops = {
 
 static const struct v4l2_subdev_core_ops si4713_subdev_core_ops = {
 	.ioctl		= si4713_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl32	= si4713_ioctl,
+#endif
 };
 
 static const struct v4l2_subdev_tuner_ops si4713_subdev_tuner_ops = {
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index bf3aa9252458..fbd176d6c415 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -686,13 +686,26 @@  static long subdev_ioctl(struct file *file, unsigned int cmd,
 }
 
 #ifdef CONFIG_COMPAT
-static long subdev_compat_ioctl32(struct file *file, unsigned int cmd,
-	unsigned long arg)
+static long subdev_do_compat_ioctl32(struct file *file, unsigned int cmd, void *arg)
 {
 	struct video_device *vdev = video_devdata(file);
 	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+	struct mutex *lock = vdev->lock;
+	long ret = -ENODEV;
 
-	return v4l2_subdev_call(sd, core, compat_ioctl32, cmd, arg);
+	if (lock && mutex_lock_interruptible(lock))
+		return -ERESTARTSYS;
+	if (video_is_registered(vdev))
+		ret = v4l2_subdev_call(sd, core, compat_ioctl32, cmd, arg);
+	if (lock)
+		mutex_unlock(lock);
+	return ret;
+}
+
+static long subdev_compat_ioctl32(struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	return video_usercopy(file, cmd, arg, subdev_do_compat_ioctl32);
 }
 #endif
 
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index d0e9a5bdb08b..42aa1f6c7c3f 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -195,8 +195,7 @@  struct v4l2_subdev_core_ops {
 	int (*s_gpio)(struct v4l2_subdev *sd, u32 val);
 	long (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
 #ifdef CONFIG_COMPAT
-	long (*compat_ioctl32)(struct v4l2_subdev *sd, unsigned int cmd,
-			       unsigned long arg);
+	long (*compat_ioctl32)(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
 #endif
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 	int (*g_register)(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg);