diff mbox

[RFC] Drop non-unlocked ioctl support in v4l2-dev.c

Message ID 200908061709.41211.laurent.pinchart@ideasonboard.com (mailing list archive)
State RFC
Delegated to: Mauro Carvalho Chehab
Headers show

Commit Message

Laurent Pinchart Aug. 6, 2009, 3:09 p.m. UTC
Hi everybody,

this patch moves the BKL one level down by removing the non-unlocked ioctl in
v4l2-dev.c and calling lock_kernel/unlock_kernel in the unlocked_ioctl handler
if the driver only supports locked ioctl.

Opinions/comments/applause/kicks ?

Regards,

Laurent Pinchart


--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Hans Verkuil Aug. 6, 2009, 3:16 p.m. UTC | #1
Hi Laurent,

> Hi everybody,
>
> this patch moves the BKL one level down by removing the non-unlocked ioctl
> in
> v4l2-dev.c and calling lock_kernel/unlock_kernel in the unlocked_ioctl
> handler
> if the driver only supports locked ioctl.
>
> Opinions/comments/applause/kicks ?

I've been thinking about this as well, and my idea was to properly
implement this by letting the v4l core serialize ioctls if the driver
doesn't do its own serialization (either through mutexes or lock_kernel).

The driver can just set a flag in video_device if it wants to do
serialization manually, otherwise the core will serialize using a mutex
and we should be able to completely remove the BKL from all v4l drivers.

I was actually planning an RFC for this myself, but you've beaten me to it
:-)

Regards,

         Hans
Laurent Pinchart Aug. 7, 2009, 11:03 a.m. UTC | #2
Hi Hans,

On Thursday 06 August 2009 17:16:08 Hans Verkuil wrote:
> Hi Laurent,
>
> > Hi everybody,
> >
> > this patch moves the BKL one level down by removing the non-unlocked
> > ioctl in v4l2-dev.c and calling lock_kernel/unlock_kernel in the
> > unlocked_ioctl handler if the driver only supports locked ioctl.
> >
> > Opinions/comments/applause/kicks ?
>
> I've been thinking about this as well, and my idea was to properly
> implement this by letting the v4l core serialize ioctls if the driver
> doesn't do its own serialization (either through mutexes or lock_kernel).

A v4l-specific (or even device-specific) mutex would of course be better than 
the BKL.

Are there file operations other than ioctl that are protected by the BKL ? 
Blindly replacing the BKL by a mutex on ioctl would then introduce race 
conditions.

> The driver can just set a flag in video_device if it wants to do
> serialization manually, otherwise the core will serialize using a mutex
> and we should be able to completely remove the BKL from all v4l drivers.

Whether the driver fills v4l2_operations::ioctl or 
v4l2_operations::unlocked_ioctl can be considered as such a flag :-)

Many drivers are currently using the BKL in an unlocked_ioctl handler. I'm not 
sure it would be a good idea to move the BKL back to the v4l2 core, as the 
long term goal is to remove it completely and use fine-grain driver-level 
locking.

Regards,

Laurent Pinchart

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Hans Verkuil Aug. 7, 2009, 11:37 a.m. UTC | #3
On Friday 07 August 2009 13:03:22 Laurent Pinchart wrote:
> Hi Hans,
> 
> On Thursday 06 August 2009 17:16:08 Hans Verkuil wrote:
> > Hi Laurent,
> >
> > > Hi everybody,
> > >
> > > this patch moves the BKL one level down by removing the non-unlocked
> > > ioctl in v4l2-dev.c and calling lock_kernel/unlock_kernel in the
> > > unlocked_ioctl handler if the driver only supports locked ioctl.
> > >
> > > Opinions/comments/applause/kicks ?
> >
> > I've been thinking about this as well, and my idea was to properly
> > implement this by letting the v4l core serialize ioctls if the driver
> > doesn't do its own serialization (either through mutexes or lock_kernel).
> 
> A v4l-specific (or even device-specific) mutex would of course be better than 
> the BKL.
> 
> Are there file operations other than ioctl that are protected by the BKL ? 
> Blindly replacing the BKL by a mutex on ioctl would then introduce race 
> conditions.

I'd say that drivers that add sysfs or proc entries might be a problem, but
there are few drivers that do that and I suspect that quite a few have their
own locking.

Allowing the mutex to be accessed from elsewhere would be a simple solution
to this problem as all the sysfs/proc accesses can just attempt to get the
lock first, thus doing proper serializing.

> > The driver can just set a flag in video_device if it wants to do
> > serialization manually, otherwise the core will serialize using a mutex
> > and we should be able to completely remove the BKL from all v4l drivers.
> 
> Whether the driver fills v4l2_operations::ioctl or 
> v4l2_operations::unlocked_ioctl can be considered as such a flag :-)

Basically there are three situations:

1) unlocked_ioctl is set: in that case the driver takes care of all the
locking.

2) ioctl is set: in that case we keep the old BKL behavior.

3) unlocked_ioctl is set together with a serialize flag in struct v4l2_device:
in that case the v4l2 core will take care of most of the serialization for the
driver.

> Many drivers are currently using the BKL in an unlocked_ioctl handler. I'm not 
> sure it would be a good idea to move the BKL back to the v4l2 core, as the 
> long term goal is to remove it completely and use fine-grain driver-level 
> locking.

I agree with that. But I think the best approach to be able to remove the BKLs
is to provide a good alternative. Doing proper locking in a driver is quite
hard. Doing it in the v4l2 core is a lot easier to do right.

If the relevant file_operations are properly serialized, then that will simplify
drivers enormously. And it is also fairly easy to optimize certain ioctls:
e.g. the VIDIOC_QUERYCAP ioctl does not normally need a lock since it does
not access anything that needs to be protected. Intelligence like that can
be enabled on demand by setting a flag as well.

Basically I have no trust in device driver writers to do locking right, and
yes, that includes myself. It's hard to be sure that you covered all your
bases, especially for complicated drivers like most v4l drivers are.

Letting the core do most of the heavy lifting, even if you get somewhat
sub-optimal locking, is more than good enough in almost all cases.

And I expect that it is definitely more than good enough for drivers that
use the BKL.

Regards,

	Hans
diff mbox

Patch

diff -r 4533a406fddb linux/drivers/media/video/v4l2-dev.c
--- a/linux/drivers/media/video/v4l2-dev.c	Thu Aug 06 16:41:17 2009 +0200
+++ b/linux/drivers/media/video/v4l2-dev.c	Thu Aug 06 17:04:37 2009 +0200
@@ -25,6 +25,7 @@ 
 #include <linux/init.h>
 #include <linux/kmod.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
@@ -211,28 +212,22 @@ 
 	return vdev->fops->poll(filp, poll);
 }
 
-static int v4l2_ioctl(struct inode *inode, struct file *filp,
-		unsigned int cmd, unsigned long arg)
-{
-	struct video_device *vdev = video_devdata(filp);
-
-	if (!vdev->fops->ioctl)
-		return -ENOTTY;
-	/* Allow ioctl to continue even if the device was unregistered.
-	   Things like dequeueing buffers might still be useful. */
-	return vdev->fops->ioctl(filp, cmd, arg);
-}
-
 static long v4l2_unlocked_ioctl(struct file *filp,
 		unsigned int cmd, unsigned long arg)
 {
 	struct video_device *vdev = video_devdata(filp);
+	int ret = -ENOTTY;
 
-	if (!vdev->fops->unlocked_ioctl)
-		return -ENOTTY;
 	/* Allow ioctl to continue even if the device was unregistered.
 	   Things like dequeueing buffers might still be useful. */
-	return vdev->fops->unlocked_ioctl(filp, cmd, arg);
+	if (vdev->fops->ioctl) {
+		lock_kernel();
+		ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
+		unlock_kernel();
+	} else if (vdev->fops->unlocked_ioctl)
+		ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
+
+	return ret;
 }
 
 #ifdef CONFIG_MMU
@@ -320,22 +315,6 @@ 
 	.llseek = no_llseek,
 };
 
-static const struct file_operations v4l2_fops = {
-	.owner = THIS_MODULE,
-	.read = v4l2_read,
-	.write = v4l2_write,
-	.open = v4l2_open,
-	.get_unmapped_area = v4l2_get_unmapped_area,
-	.mmap = v4l2_mmap,
-	.ioctl = v4l2_ioctl,
-#ifdef CONFIG_COMPAT
-	.compat_ioctl = v4l2_compat_ioctl32,
-#endif
-	.release = v4l2_release,
-	.poll = v4l2_poll,
-	.llseek = no_llseek,
-};
-
 /**
  * get_index - assign stream number based on parent device
  * @vdev: video_device to assign index number to, vdev->parent should be assigned
@@ -534,15 +513,9 @@ 
 		goto cleanup;
 	}
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
-	if (vdev->fops->unlocked_ioctl)
-		vdev->cdev->ops = &v4l2_unlocked_fops;
-	else
-		vdev->cdev->ops = &v4l2_fops;
+	vdev->cdev->ops = &v4l2_unlocked_fops;
 #else
-	if (vdev->fops->unlocked_ioctl)
-		vdev->cdev->ops = (struct file_operations *)&v4l2_unlocked_fops;
-	else
-		vdev->cdev->ops = (struct file_operations *)&v4l2_fops;
+	vdev->cdev->ops = (struct file_operations *)&v4l2_unlocked_fops;
 #endif
 	vdev->cdev->owner = vdev->fops->owner;
 	ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);