From 169316cd4fa882d232b112eda1fbeff217446b7d Mon Sep 17 00:00:00 2001 From: Sandor Yu Date: Tue, 1 Sep 2015 15:15:48 +0800 Subject: [PATCH] MLK-11508-1: Revert "[media] v4l2-core: remove the old .ioctl BKL replacement" This reverts commit 5cf6f7f327c95f09be859889be39e78950516556. --- drivers/media/v4l2-core/v4l2-dev.c | 28 +++++++++++++++++++++++++++ drivers/media/v4l2-core/v4l2-device.c | 1 + include/media/v4l2-dev.h | 1 + include/media/v4l2-device.h | 2 ++ 4 files changed, 32 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index fe5581c0eaeb..206cff6b0c97 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -360,6 +360,34 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ret = vdev->fops->unlocked_ioctl(filp, cmd, arg); if (lock) mutex_unlock(lock); + } else if (vdev->fops->ioctl) { + /* This code path is a replacement for the BKL. It is a major + * hack but it will have to do for those drivers that are not + * yet converted to use unlocked_ioctl. + * + * All drivers implement struct v4l2_device, so we use the + * lock defined there to serialize the ioctls. + * + * However, if the driver sleeps, then it blocks all ioctls + * since the lock is still held. This is very common for + * VIDIOC_DQBUF since that normally waits for a frame to arrive. + * As a result any other ioctl calls will proceed very, very + * slowly since each call will have to wait for the VIDIOC_QBUF + * to finish. Things that should take 0.01s may now take 10-20 + * seconds. + * + * The workaround is to *not* take the lock for VIDIOC_DQBUF. + * This actually works OK for videobuf-based drivers, since + * videobuf will take its own internal lock. + */ + struct mutex *m = &vdev->v4l2_dev->ioctl_lock; + + if (cmd != VIDIOC_DQBUF && mutex_lock_interruptible(m)) + return -ERESTARTSYS; + if (video_is_registered(vdev)) + ret = vdev->fops->ioctl(filp, cmd, arg); + if (cmd != VIDIOC_DQBUF) + mutex_unlock(m); } else ret = -ENOTTY; diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c index 62bbed76dbbc..e4d15ee44a6d 100644 --- a/drivers/media/v4l2-core/v4l2-device.c +++ b/drivers/media/v4l2-core/v4l2-device.c @@ -37,6 +37,7 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev) INIT_LIST_HEAD(&v4l2_dev->subdevs); spin_lock_init(&v4l2_dev->lock); + mutex_init(&v4l2_dev->ioctl_lock); v4l2_prio_init(&v4l2_dev->prio); kref_init(&v4l2_dev->ref); get_device(dev); diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index e657614521e3..252bd3dae53f 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -152,6 +152,7 @@ struct v4l2_file_operations { ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); unsigned int (*poll) (struct file *, struct poll_table_struct *); + long (*ioctl) (struct file *, unsigned int, unsigned long); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); #ifdef CONFIG_COMPAT long (*compat_ioctl32) (struct file *, unsigned int, unsigned long); diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h index 8ffa94009d1a..bb97f64e91c8 100644 --- a/include/media/v4l2-device.h +++ b/include/media/v4l2-device.h @@ -69,6 +69,8 @@ struct v4l2_device { unsigned int notification, void *arg); struct v4l2_ctrl_handler *ctrl_handler; struct v4l2_prio_state prio; + /* BKL replacement mutex. Temporary solution only. */ + struct mutex ioctl_lock; struct kref ref; void (*release)(struct v4l2_device *v4l2_dev); };