[media] dvb: push down ioctl lock in dvb_usercopy

Since most dvb ioctls wrap their real work with dvb_usercopy, the static mutex
used in dvb_usercopy effectively is a global lock for dvb ioctls.
Unfortunately, frontend ioctls can be blocked by the frontend thread for
several seconds; this leads to unacceptable lock contention.  Mitigate that by
pushing the mutex from dvb_usercopy down to the individual, device specific
ioctls.
There are 10 such ioctl functions using dvb_usercopy, either calling it
directly, or via the trivial wrapper dvb_generic_ioctl. The following already
employ their own locking and look safe:
    • dvb_demux_ioctl           (as per dvb_demux_do_ioctl)
    • dvb_dvr_ioctl             (as per dvb_dvr_do_ioctl)
    • dvb_osd_ioctl             (as per single non-trivial callee)
    • fdtv_ca_ioctl             (as per callees)
    • dvb_frontend_ioctl
The following functions do not, and are thus changed to use a device specific
mutex:
    • dvb_net_ioctl             (as per dvb_net_do_ioctl)
    • dvb_ca_en50221_io_ioctl   (as per dvb_ca_en50221_io_do_ioctl)
    • dvb_video_ioctl
    • dvb_audio_ioctl
    • dvb_ca_ioctl

Signed-off-by: Nikolaus Schulz <schulz@macnetix.de>
Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c
index 4bd8bd5..2f54e2b 100644
--- a/drivers/media/pci/ttpci/av7110.c
+++ b/drivers/media/pci/ttpci/av7110.c
@@ -2723,6 +2723,8 @@
 	if (ret < 0)
 		goto err_av7110_exit_v4l_12;
 
+	mutex_init(&av7110->ioctl_mutex);
+
 #if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
 	av7110_ir_init(av7110);
 #endif
diff --git a/drivers/media/pci/ttpci/av7110.h b/drivers/media/pci/ttpci/av7110.h
index a378662..ef3d960 100644
--- a/drivers/media/pci/ttpci/av7110.h
+++ b/drivers/media/pci/ttpci/av7110.h
@@ -271,6 +271,8 @@
 	struct dvb_frontend* fe;
 	fe_status_t fe_status;
 
+	struct mutex ioctl_mutex;
+
 	/* crash recovery */
 	void				(*recover)(struct av7110* av7110);
 	fe_sec_voltage_t		saved_voltage;
diff --git a/drivers/media/pci/ttpci/av7110_av.c b/drivers/media/pci/ttpci/av7110_av.c
index 952b33d..301029c 100644
--- a/drivers/media/pci/ttpci/av7110_av.c
+++ b/drivers/media/pci/ttpci/av7110_av.c
@@ -1109,6 +1109,9 @@
 		}
 	}
 
+	if (mutex_lock_interruptible(&av7110->ioctl_mutex))
+		return -ERESTARTSYS;
+
 	switch (cmd) {
 	case VIDEO_STOP:
 		av7110->videostate.play_state = VIDEO_STOPPED;
@@ -1297,6 +1300,7 @@
 		break;
 	}
 
+	mutex_unlock(&av7110->ioctl_mutex);
 	return ret;
 }
 
@@ -1314,6 +1318,9 @@
 	    (cmd != AUDIO_GET_STATUS))
 		return -EPERM;
 
+	if (mutex_lock_interruptible(&av7110->ioctl_mutex))
+		return -ERESTARTSYS;
+
 	switch (cmd) {
 	case AUDIO_STOP:
 		if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
@@ -1442,6 +1449,7 @@
 		ret = -ENOIOCTLCMD;
 	}
 
+	mutex_unlock(&av7110->ioctl_mutex);
 	return ret;
 }
 
diff --git a/drivers/media/pci/ttpci/av7110_ca.c b/drivers/media/pci/ttpci/av7110_ca.c
index 9fc1dd0..a6079b9 100644
--- a/drivers/media/pci/ttpci/av7110_ca.c
+++ b/drivers/media/pci/ttpci/av7110_ca.c
@@ -253,12 +253,17 @@
 	struct dvb_device *dvbdev = file->private_data;
 	struct av7110 *av7110 = dvbdev->priv;
 	unsigned long arg = (unsigned long) parg;
+	int ret = 0;
 
 	dprintk(8, "av7110:%p\n",av7110);
 
+	if (mutex_lock_interruptible(&av7110->ioctl_mutex))
+		return -ERESTARTSYS;
+
 	switch (cmd) {
 	case CA_RESET:
-		return ci_ll_reset(&av7110->ci_wbuffer, file, arg, &av7110->ci_slot[0]);
+		ret = ci_ll_reset(&av7110->ci_wbuffer, file, arg,
+				  &av7110->ci_slot[0]);
 		break;
 	case CA_GET_CAP:
 	{
@@ -277,8 +282,10 @@
 	{
 		ca_slot_info_t *info=(ca_slot_info_t *)parg;
 
-		if (info->num < 0 || info->num > 1)
+		if (info->num < 0 || info->num > 1) {
+			mutex_unlock(&av7110->ioctl_mutex);
 			return -EINVAL;
+		}
 		av7110->ci_slot[info->num].num = info->num;
 		av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ?
 							CA_CI_LINK : CA_CI;
@@ -306,10 +313,10 @@
 	{
 		ca_descr_t *descr = (ca_descr_t*) parg;
 
-		if (descr->index >= 16)
+		if (descr->index >= 16 || descr->parity > 1) {
+			mutex_unlock(&av7110->ioctl_mutex);
 			return -EINVAL;
-		if (descr->parity > 1)
-			return -EINVAL;
+		}
 		av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetDescr, 5,
 			      (descr->index<<8)|descr->parity,
 			      (descr->cw[0]<<8)|descr->cw[1],
@@ -320,9 +327,12 @@
 	}
 
 	default:
-		return -EINVAL;
+		ret = -EINVAL;
+		break;
 	}
-	return 0;
+
+	mutex_unlock(&av7110->ioctl_mutex);
+	return ret;
 }
 
 static ssize_t dvb_ca_write(struct file *file, const char __user *buf,