aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikolaus Schulz <schulz@macnetix.de>2012-12-23 16:49:07 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-12-27 12:44:21 -0500
commit30ad64b8ac539459f8975aa186421ef3db0bb5cb (patch)
tree1f1024574f1e7bb1ddf25ea79f3c361acfa0f3fe
parent6ae23224557d797439d02f6ce5d10a82ab544b21 (diff)
[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>
-rw-r--r--drivers/media/dvb-core/dvb_ca_en50221.c9
-rw-r--r--drivers/media/dvb-core/dvb_net.c71
-rw-r--r--drivers/media/dvb-core/dvb_net.h1
-rw-r--r--drivers/media/dvb-core/dvbdev.c2
-rw-r--r--drivers/media/pci/ttpci/av7110.c2
-rw-r--r--drivers/media/pci/ttpci/av7110.h2
-rw-r--r--drivers/media/pci/ttpci/av7110_av.c8
-rw-r--r--drivers/media/pci/ttpci/av7110_ca.c24
8 files changed, 87 insertions, 32 deletions
diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c
index 9be65a3b931f..190e5e0f48c7 100644
--- a/drivers/media/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb-core/dvb_ca_en50221.c
@@ -156,6 +156,9 @@ struct dvb_ca_private {
156 156
157 /* Slot to start looking for data to read from in the next user-space read operation */ 157 /* Slot to start looking for data to read from in the next user-space read operation */
158 int next_read_slot; 158 int next_read_slot;
159
160 /* mutex serializing ioctls */
161 struct mutex ioctl_mutex;
159}; 162};
160 163
161static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca); 164static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca);
@@ -1191,6 +1194,9 @@ static int dvb_ca_en50221_io_do_ioctl(struct file *file,
1191 1194
1192 dprintk("%s\n", __func__); 1195 dprintk("%s\n", __func__);
1193 1196
1197 if (mutex_lock_interruptible(&ca->ioctl_mutex))
1198 return -ERESTARTSYS;
1199
1194 switch (cmd) { 1200 switch (cmd) {
1195 case CA_RESET: 1201 case CA_RESET:
1196 for (slot = 0; slot < ca->slot_count; slot++) { 1202 for (slot = 0; slot < ca->slot_count; slot++) {
@@ -1241,6 +1247,7 @@ static int dvb_ca_en50221_io_do_ioctl(struct file *file,
1241 break; 1247 break;
1242 } 1248 }
1243 1249
1250 mutex_unlock(&ca->ioctl_mutex);
1244 return err; 1251 return err;
1245} 1252}
1246 1253
@@ -1695,6 +1702,8 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
1695 mutex_init(&ca->slot_info[i].slot_lock); 1702 mutex_init(&ca->slot_info[i].slot_lock);
1696 } 1703 }
1697 1704
1705 mutex_init(&ca->ioctl_mutex);
1706
1698 if (signal_pending(current)) { 1707 if (signal_pending(current)) {
1699 ret = -EINTR; 1708 ret = -EINTR;
1700 goto error; 1709 goto error;
diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c
index c2117688aa23..44225b186f6d 100644
--- a/drivers/media/dvb-core/dvb_net.c
+++ b/drivers/media/dvb-core/dvb_net.c
@@ -1345,26 +1345,35 @@ static int dvb_net_do_ioctl(struct file *file,
1345{ 1345{
1346 struct dvb_device *dvbdev = file->private_data; 1346 struct dvb_device *dvbdev = file->private_data;
1347 struct dvb_net *dvbnet = dvbdev->priv; 1347 struct dvb_net *dvbnet = dvbdev->priv;
1348 int ret = 0;
1348 1349
1349 if (((file->f_flags&O_ACCMODE)==O_RDONLY)) 1350 if (((file->f_flags&O_ACCMODE)==O_RDONLY))
1350 return -EPERM; 1351 return -EPERM;
1351 1352
1353 if (mutex_lock_interruptible(&dvbnet->ioctl_mutex))
1354 return -ERESTARTSYS;
1355
1352 switch (cmd) { 1356 switch (cmd) {
1353 case NET_ADD_IF: 1357 case NET_ADD_IF:
1354 { 1358 {
1355 struct dvb_net_if *dvbnetif = parg; 1359 struct dvb_net_if *dvbnetif = parg;
1356 int result; 1360 int result;
1357 1361
1358 if (!capable(CAP_SYS_ADMIN)) 1362 if (!capable(CAP_SYS_ADMIN)) {
1359 return -EPERM; 1363 ret = -EPERM;
1364 goto ioctl_error;
1365 }
1360 1366
1361 if (!try_module_get(dvbdev->adapter->module)) 1367 if (!try_module_get(dvbdev->adapter->module)) {
1362 return -EPERM; 1368 ret = -EPERM;
1369 goto ioctl_error;
1370 }
1363 1371
1364 result=dvb_net_add_if(dvbnet, dvbnetif->pid, dvbnetif->feedtype); 1372 result=dvb_net_add_if(dvbnet, dvbnetif->pid, dvbnetif->feedtype);
1365 if (result<0) { 1373 if (result<0) {
1366 module_put(dvbdev->adapter->module); 1374 module_put(dvbdev->adapter->module);
1367 return result; 1375 ret = result;
1376 goto ioctl_error;
1368 } 1377 }
1369 dvbnetif->if_num=result; 1378 dvbnetif->if_num=result;
1370 break; 1379 break;
@@ -1376,8 +1385,10 @@ static int dvb_net_do_ioctl(struct file *file,
1376 struct dvb_net_if *dvbnetif = parg; 1385 struct dvb_net_if *dvbnetif = parg;
1377 1386
1378 if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX || 1387 if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
1379 !dvbnet->state[dvbnetif->if_num]) 1388 !dvbnet->state[dvbnetif->if_num]) {
1380 return -EINVAL; 1389 ret = -EINVAL;
1390 goto ioctl_error;
1391 }
1381 1392
1382 netdev = dvbnet->device[dvbnetif->if_num]; 1393 netdev = dvbnet->device[dvbnetif->if_num];
1383 1394
@@ -1388,16 +1399,18 @@ static int dvb_net_do_ioctl(struct file *file,
1388 } 1399 }
1389 case NET_REMOVE_IF: 1400 case NET_REMOVE_IF:
1390 { 1401 {
1391 int ret; 1402 if (!capable(CAP_SYS_ADMIN)) {
1392 1403 ret = -EPERM;
1393 if (!capable(CAP_SYS_ADMIN)) 1404 goto ioctl_error;
1394 return -EPERM; 1405 }
1395 if ((unsigned long) parg >= DVB_NET_DEVICES_MAX) 1406 if ((unsigned long) parg >= DVB_NET_DEVICES_MAX) {
1396 return -EINVAL; 1407 ret = -EINVAL;
1408 goto ioctl_error;
1409 }
1397 ret = dvb_net_remove_if(dvbnet, (unsigned long) parg); 1410 ret = dvb_net_remove_if(dvbnet, (unsigned long) parg);
1398 if (!ret) 1411 if (!ret)
1399 module_put(dvbdev->adapter->module); 1412 module_put(dvbdev->adapter->module);
1400 return ret; 1413 break;
1401 } 1414 }
1402 1415
1403 /* binary compatibility cruft */ 1416 /* binary compatibility cruft */
@@ -1406,16 +1419,21 @@ static int dvb_net_do_ioctl(struct file *file,
1406 struct __dvb_net_if_old *dvbnetif = parg; 1419 struct __dvb_net_if_old *dvbnetif = parg;
1407 int result; 1420 int result;
1408 1421
1409 if (!capable(CAP_SYS_ADMIN)) 1422 if (!capable(CAP_SYS_ADMIN)) {
1410 return -EPERM; 1423 ret = -EPERM;
1424 goto ioctl_error;
1425 }
1411 1426
1412 if (!try_module_get(dvbdev->adapter->module)) 1427 if (!try_module_get(dvbdev->adapter->module)) {
1413 return -EPERM; 1428 ret = -EPERM;
1429 goto ioctl_error;
1430 }
1414 1431
1415 result=dvb_net_add_if(dvbnet, dvbnetif->pid, DVB_NET_FEEDTYPE_MPE); 1432 result=dvb_net_add_if(dvbnet, dvbnetif->pid, DVB_NET_FEEDTYPE_MPE);
1416 if (result<0) { 1433 if (result<0) {
1417 module_put(dvbdev->adapter->module); 1434 module_put(dvbdev->adapter->module);
1418 return result; 1435 ret = result;
1436 goto ioctl_error;
1419 } 1437 }
1420 dvbnetif->if_num=result; 1438 dvbnetif->if_num=result;
1421 break; 1439 break;
@@ -1427,8 +1445,10 @@ static int dvb_net_do_ioctl(struct file *file,
1427 struct __dvb_net_if_old *dvbnetif = parg; 1445 struct __dvb_net_if_old *dvbnetif = parg;
1428 1446
1429 if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX || 1447 if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
1430 !dvbnet->state[dvbnetif->if_num]) 1448 !dvbnet->state[dvbnetif->if_num]) {
1431 return -EINVAL; 1449 ret = -EINVAL;
1450 goto ioctl_error;
1451 }
1432 1452
1433 netdev = dvbnet->device[dvbnetif->if_num]; 1453 netdev = dvbnet->device[dvbnetif->if_num];
1434 1454
@@ -1437,9 +1457,13 @@ static int dvb_net_do_ioctl(struct file *file,
1437 break; 1457 break;
1438 } 1458 }
1439 default: 1459 default:
1440 return -ENOTTY; 1460 ret = -ENOTTY;
1461 break;
1441 } 1462 }
1442 return 0; 1463
1464ioctl_error:
1465 mutex_unlock(&dvbnet->ioctl_mutex);
1466 return ret;
1443} 1467}
1444 1468
1445static long dvb_net_ioctl(struct file *file, 1469static long dvb_net_ioctl(struct file *file,
@@ -1505,6 +1529,7 @@ int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet,
1505{ 1529{
1506 int i; 1530 int i;
1507 1531
1532 mutex_init(&dvbnet->ioctl_mutex);
1508 dvbnet->demux = dmx; 1533 dvbnet->demux = dmx;
1509 1534
1510 for (i=0; i<DVB_NET_DEVICES_MAX; i++) 1535 for (i=0; i<DVB_NET_DEVICES_MAX; i++)
diff --git a/drivers/media/dvb-core/dvb_net.h b/drivers/media/dvb-core/dvb_net.h
index 1e53acd50cf4..ede78e8c8aa8 100644
--- a/drivers/media/dvb-core/dvb_net.h
+++ b/drivers/media/dvb-core/dvb_net.h
@@ -40,6 +40,7 @@ struct dvb_net {
40 int state[DVB_NET_DEVICES_MAX]; 40 int state[DVB_NET_DEVICES_MAX];
41 unsigned int exit:1; 41 unsigned int exit:1;
42 struct dmx_demux *demux; 42 struct dmx_demux *demux;
43 struct mutex ioctl_mutex;
43}; 44};
44 45
45void dvb_net_release(struct dvb_net *); 46void dvb_net_release(struct dvb_net *);
diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index d33101aaf0b5..401ef64f92c6 100644
--- a/drivers/media/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -418,10 +418,8 @@ int dvb_usercopy(struct file *file,
418 } 418 }
419 419
420 /* call driver */ 420 /* call driver */
421 mutex_lock(&dvbdev_mutex);
422 if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD) 421 if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD)
423 err = -ENOTTY; 422 err = -ENOTTY;
424 mutex_unlock(&dvbdev_mutex);
425 423
426 if (err < 0) 424 if (err < 0)
427 goto out; 425 goto out;
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,
2723 if (ret < 0) 2723 if (ret < 0)
2724 goto err_av7110_exit_v4l_12; 2724 goto err_av7110_exit_v4l_12;
2725 2725
2726 mutex_init(&av7110->ioctl_mutex);
2727
2726#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) 2728#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
2727 av7110_ir_init(av7110); 2729 av7110_ir_init(av7110);
2728#endif 2730#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 {
271 struct dvb_frontend* fe; 271 struct dvb_frontend* fe;
272 fe_status_t fe_status; 272 fe_status_t fe_status;
273 273
274 struct mutex ioctl_mutex;
275
274 /* crash recovery */ 276 /* crash recovery */
275 void (*recover)(struct av7110* av7110); 277 void (*recover)(struct av7110* av7110);
276 fe_sec_voltage_t saved_voltage; 278 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,
1109 } 1109 }
1110 } 1110 }
1111 1111
1112 if (mutex_lock_interruptible(&av7110->ioctl_mutex))
1113 return -ERESTARTSYS;
1114
1112 switch (cmd) { 1115 switch (cmd) {
1113 case VIDEO_STOP: 1116 case VIDEO_STOP:
1114 av7110->videostate.play_state = VIDEO_STOPPED; 1117 av7110->videostate.play_state = VIDEO_STOPPED;
@@ -1297,6 +1300,7 @@ static int dvb_video_ioctl(struct file *file,
1297 break; 1300 break;
1298 } 1301 }
1299 1302
1303 mutex_unlock(&av7110->ioctl_mutex);
1300 return ret; 1304 return ret;
1301} 1305}
1302 1306
@@ -1314,6 +1318,9 @@ static int dvb_audio_ioctl(struct file *file,
1314 (cmd != AUDIO_GET_STATUS)) 1318 (cmd != AUDIO_GET_STATUS))
1315 return -EPERM; 1319 return -EPERM;
1316 1320
1321 if (mutex_lock_interruptible(&av7110->ioctl_mutex))
1322 return -ERESTARTSYS;
1323
1317 switch (cmd) { 1324 switch (cmd) {
1318 case AUDIO_STOP: 1325 case AUDIO_STOP:
1319 if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) 1326 if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
@@ -1442,6 +1449,7 @@ static int dvb_audio_ioctl(struct file *file,
1442 ret = -ENOIOCTLCMD; 1449 ret = -ENOIOCTLCMD;
1443 } 1450 }
1444 1451
1452 mutex_unlock(&av7110->ioctl_mutex);
1445 return ret; 1453 return ret;
1446} 1454}
1447 1455
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)
253 struct dvb_device *dvbdev = file->private_data; 253 struct dvb_device *dvbdev = file->private_data;
254 struct av7110 *av7110 = dvbdev->priv; 254 struct av7110 *av7110 = dvbdev->priv;
255 unsigned long arg = (unsigned long) parg; 255 unsigned long arg = (unsigned long) parg;
256 int ret = 0;
256 257
257 dprintk(8, "av7110:%p\n",av7110); 258 dprintk(8, "av7110:%p\n",av7110);
258 259
260 if (mutex_lock_interruptible(&av7110->ioctl_mutex))
261 return -ERESTARTSYS;
262
259 switch (cmd) { 263 switch (cmd) {
260 case CA_RESET: 264 case CA_RESET:
261 return ci_ll_reset(&av7110->ci_wbuffer, file, arg, &av7110->ci_slot[0]); 265 ret = ci_ll_reset(&av7110->ci_wbuffer, file, arg,
266 &av7110->ci_slot[0]);
262 break; 267 break;
263 case CA_GET_CAP: 268 case CA_GET_CAP:
264 { 269 {
@@ -277,8 +282,10 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg)
277 { 282 {
278 ca_slot_info_t *info=(ca_slot_info_t *)parg; 283 ca_slot_info_t *info=(ca_slot_info_t *)parg;
279 284
280 if (info->num < 0 || info->num > 1) 285 if (info->num < 0 || info->num > 1) {
286 mutex_unlock(&av7110->ioctl_mutex);
281 return -EINVAL; 287 return -EINVAL;
288 }
282 av7110->ci_slot[info->num].num = info->num; 289 av7110->ci_slot[info->num].num = info->num;
283 av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ? 290 av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ?
284 CA_CI_LINK : CA_CI; 291 CA_CI_LINK : CA_CI;
@@ -306,10 +313,10 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg)
306 { 313 {
307 ca_descr_t *descr = (ca_descr_t*) parg; 314 ca_descr_t *descr = (ca_descr_t*) parg;
308 315
309 if (descr->index >= 16) 316 if (descr->index >= 16 || descr->parity > 1) {
310 return -EINVAL; 317 mutex_unlock(&av7110->ioctl_mutex);
311 if (descr->parity > 1)
312 return -EINVAL; 318 return -EINVAL;
319 }
313 av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetDescr, 5, 320 av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetDescr, 5,
314 (descr->index<<8)|descr->parity, 321 (descr->index<<8)|descr->parity,
315 (descr->cw[0]<<8)|descr->cw[1], 322 (descr->cw[0]<<8)|descr->cw[1],
@@ -320,9 +327,12 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg)
320 } 327 }
321 328
322 default: 329 default:
323 return -EINVAL; 330 ret = -EINVAL;
331 break;
324 } 332 }
325 return 0; 333
334 mutex_unlock(&av7110->ioctl_mutex);
335 return ret;
326} 336}
327 337
328static ssize_t dvb_ca_write(struct file *file, const char __user *buf, 338static ssize_t dvb_ca_write(struct file *file, const char __user *buf,