diff options
author | Nikolaus Schulz <schulz@macnetix.de> | 2012-12-24 01:49:07 +0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-12-27 21:44:21 +0400 |
commit | 30ad64b8ac539459f8975aa186421ef3db0bb5cb (patch) | |
tree | 1f1024574f1e7bb1ddf25ea79f3c361acfa0f3fe /drivers/media/pci/ttpci | |
parent | 6ae23224557d797439d02f6ce5d10a82ab544b21 (diff) | |
download | linux-30ad64b8ac539459f8975aa186421ef3db0bb5cb.tar.xz |
[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>
Diffstat (limited to 'drivers/media/pci/ttpci')
-rw-r--r-- | drivers/media/pci/ttpci/av7110.c | 2 | ||||
-rw-r--r-- | drivers/media/pci/ttpci/av7110.h | 2 | ||||
-rw-r--r-- | drivers/media/pci/ttpci/av7110_av.c | 8 | ||||
-rw-r--r-- | drivers/media/pci/ttpci/av7110_ca.c | 24 |
4 files changed, 29 insertions, 7 deletions
diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index 4bd8bd56befc..2f54e2b741f6 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -2723,6 +2723,8 @@ static int __devinit av7110_attach(struct saa7146_dev* dev, 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 a378662b1dcf..ef3d9606b269 100644 --- a/drivers/media/pci/ttpci/av7110.h +++ b/drivers/media/pci/ttpci/av7110.h @@ -271,6 +271,8 @@ struct av7110 { 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 952b33dbac4f..301029ca4535 100644 --- a/drivers/media/pci/ttpci/av7110_av.c +++ b/drivers/media/pci/ttpci/av7110_av.c @@ -1109,6 +1109,9 @@ static int dvb_video_ioctl(struct file *file, } } + if (mutex_lock_interruptible(&av7110->ioctl_mutex)) + return -ERESTARTSYS; + switch (cmd) { case VIDEO_STOP: av7110->videostate.play_state = VIDEO_STOPPED; @@ -1297,6 +1300,7 @@ static int dvb_video_ioctl(struct file *file, break; } + mutex_unlock(&av7110->ioctl_mutex); return ret; } @@ -1314,6 +1318,9 @@ static int dvb_audio_ioctl(struct file *file, (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 @@ static int dvb_audio_ioctl(struct file *file, 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 9fc1dd0ba4c3..a6079b90252a 100644 --- a/drivers/media/pci/ttpci/av7110_ca.c +++ b/drivers/media/pci/ttpci/av7110_ca.c @@ -253,12 +253,17 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg) 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 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg) { 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 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg) { ca_descr_t *descr = (ca_descr_t*) parg; - if (descr->index >= 16) - return -EINVAL; - if (descr->parity > 1) + if (descr->index >= 16 || descr->parity > 1) { + mutex_unlock(&av7110->ioctl_mutex); 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 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg) } 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, |