27
27
#include <media/tuner.h>
28
28
29
29
static DEFINE_MUTEX (dvbdev_mutex );
30
+ static LIST_HEAD (dvbdevfops_list );
30
31
static int dvbdev_debug ;
31
32
32
33
module_param (dvbdev_debug , int , 0644 );
@@ -453,33 +454,61 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
453
454
enum dvb_device_type type , int demux_sink_pads )
454
455
{
455
456
struct dvb_device * dvbdev ;
456
- struct file_operations * dvbdevfops ;
457
+ struct file_operations * dvbdevfops = NULL ;
458
+ struct dvbdevfops_node * node = NULL , * new_node = NULL ;
457
459
struct device * clsdev ;
458
460
int minor ;
459
461
int id , ret ;
460
462
461
463
mutex_lock (& dvbdev_register_lock );
462
464
463
- if ((id = dvbdev_get_free_id (adap , type )) < 0 ){
465
+ if ((id = dvbdev_get_free_id (adap , type )) < 0 ) {
464
466
mutex_unlock (& dvbdev_register_lock );
465
467
* pdvbdev = NULL ;
466
468
pr_err ("%s: couldn't find free device id\n" , __func__ );
467
469
return - ENFILE ;
468
470
}
469
471
470
472
* pdvbdev = dvbdev = kzalloc (sizeof (* dvbdev ), GFP_KERNEL );
471
-
472
473
if (!dvbdev ){
473
474
mutex_unlock (& dvbdev_register_lock );
474
475
return - ENOMEM ;
475
476
}
476
477
477
- dvbdevfops = kmemdup (template -> fops , sizeof (* dvbdevfops ), GFP_KERNEL );
478
+ /*
479
+ * When a device of the same type is probe()d more than once,
480
+ * the first allocated fops are used. This prevents memory leaks
481
+ * that can occur when the same device is probe()d repeatedly.
482
+ */
483
+ list_for_each_entry (node , & dvbdevfops_list , list_head ) {
484
+ if (node -> fops -> owner == adap -> module &&
485
+ node -> type == type &&
486
+ node -> template == template ) {
487
+ dvbdevfops = node -> fops ;
488
+ break ;
489
+ }
490
+ }
478
491
479
- if (!dvbdevfops ){
480
- kfree (dvbdev );
481
- mutex_unlock (& dvbdev_register_lock );
482
- return - ENOMEM ;
492
+ if (dvbdevfops == NULL ) {
493
+ dvbdevfops = kmemdup (template -> fops , sizeof (* dvbdevfops ), GFP_KERNEL );
494
+ if (!dvbdevfops ) {
495
+ kfree (dvbdev );
496
+ mutex_unlock (& dvbdev_register_lock );
497
+ return - ENOMEM ;
498
+ }
499
+
500
+ new_node = kzalloc (sizeof (struct dvbdevfops_node ), GFP_KERNEL );
501
+ if (!new_node ) {
502
+ kfree (dvbdevfops );
503
+ kfree (dvbdev );
504
+ mutex_unlock (& dvbdev_register_lock );
505
+ return - ENOMEM ;
506
+ }
507
+
508
+ new_node -> fops = dvbdevfops ;
509
+ new_node -> type = type ;
510
+ new_node -> template = template ;
511
+ list_add_tail (& new_node -> list_head , & dvbdevfops_list );
483
512
}
484
513
485
514
memcpy (dvbdev , template , sizeof (struct dvb_device ));
@@ -490,20 +519,20 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
490
519
dvbdev -> priv = priv ;
491
520
dvbdev -> fops = dvbdevfops ;
492
521
init_waitqueue_head (& dvbdev -> wait_queue );
493
-
494
522
dvbdevfops -> owner = adap -> module ;
495
-
496
523
list_add_tail (& dvbdev -> list_head , & adap -> device_list );
497
-
498
524
down_write (& minor_rwsem );
499
525
#ifdef CONFIG_DVB_DYNAMIC_MINORS
500
526
for (minor = 0 ; minor < MAX_DVB_MINORS ; minor ++ )
501
527
if (dvb_minors [minor ] == NULL )
502
528
break ;
503
-
504
529
if (minor == MAX_DVB_MINORS ) {
530
+ if (new_node ) {
531
+ list_del (& new_node -> list_head );
532
+ kfree (dvbdevfops );
533
+ kfree (new_node );
534
+ }
505
535
list_del (& dvbdev -> list_head );
506
- kfree (dvbdevfops );
507
536
kfree (dvbdev );
508
537
up_write (& minor_rwsem );
509
538
mutex_unlock (& dvbdev_register_lock );
@@ -512,41 +541,47 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
512
541
#else
513
542
minor = nums2minor (adap -> num , type , id );
514
543
#endif
515
-
516
544
dvbdev -> minor = minor ;
517
545
dvb_minors [minor ] = dvb_device_get (dvbdev );
518
546
up_write (& minor_rwsem );
519
-
520
547
ret = dvb_register_media_device (dvbdev , type , minor , demux_sink_pads );
521
548
if (ret ) {
522
549
pr_err ("%s: dvb_register_media_device failed to create the mediagraph\n" ,
523
550
__func__ );
524
-
551
+ if (new_node ) {
552
+ list_del (& new_node -> list_head );
553
+ kfree (dvbdevfops );
554
+ kfree (new_node );
555
+ }
525
556
dvb_media_device_free (dvbdev );
526
557
list_del (& dvbdev -> list_head );
527
- kfree (dvbdevfops );
528
558
kfree (dvbdev );
529
559
mutex_unlock (& dvbdev_register_lock );
530
560
return ret ;
531
561
}
532
562
533
- mutex_unlock (& dvbdev_register_lock );
534
-
535
563
clsdev = device_create (dvb_class , adap -> device ,
536
564
MKDEV (DVB_MAJOR , minor ),
537
565
dvbdev , "dvb%d.%s%d" , adap -> num , dnames [type ], id );
538
566
if (IS_ERR (clsdev )) {
539
567
pr_err ("%s: failed to create device dvb%d.%s%d (%ld)\n" ,
540
568
__func__ , adap -> num , dnames [type ], id , PTR_ERR (clsdev ));
569
+ if (new_node ) {
570
+ list_del (& new_node -> list_head );
571
+ kfree (dvbdevfops );
572
+ kfree (new_node );
573
+ }
541
574
dvb_media_device_free (dvbdev );
542
575
list_del (& dvbdev -> list_head );
543
- kfree (dvbdevfops );
544
576
kfree (dvbdev );
577
+ mutex_unlock (& dvbdev_register_lock );
545
578
return PTR_ERR (clsdev );
546
579
}
580
+
547
581
dprintk ("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n" ,
548
582
adap -> num , dnames [type ], id , minor , minor );
549
583
584
+ mutex_unlock (& dvbdev_register_lock );
550
585
return 0 ;
551
586
}
552
587
EXPORT_SYMBOL (dvb_register_device );
@@ -575,7 +610,6 @@ static void dvb_free_device(struct kref *ref)
575
610
{
576
611
struct dvb_device * dvbdev = container_of (ref , struct dvb_device , ref );
577
612
578
- kfree (dvbdev -> fops );
579
613
kfree (dvbdev );
580
614
}
581
615
@@ -1081,9 +1115,17 @@ static int __init init_dvbdev(void)
1081
1115
1082
1116
static void __exit exit_dvbdev (void )
1083
1117
{
1118
+ struct dvbdevfops_node * node , * next ;
1119
+
1084
1120
class_destroy (dvb_class );
1085
1121
cdev_del (& dvb_device_cdev );
1086
1122
unregister_chrdev_region (MKDEV (DVB_MAJOR , 0 ), MAX_DVB_MINORS );
1123
+
1124
+ list_for_each_entry_safe (node , next , & dvbdevfops_list , list_head ) {
1125
+ list_del (& node -> list_head );
1126
+ kfree (node -> fops );
1127
+ kfree (node );
1128
+ }
1087
1129
}
1088
1130
1089
1131
subsys_initcall (init_dvbdev );
0 commit comments