@@ -89,8 +89,11 @@ static bool delete_fprobe_node(struct fprobe_hlist_node *node)
89
89
{
90
90
lockdep_assert_held (& fprobe_mutex );
91
91
92
- WRITE_ONCE (node -> fp , NULL );
93
- hlist_del_rcu (& node -> hlist );
92
+ /* Avoid double deleting */
93
+ if (READ_ONCE (node -> fp ) != NULL ) {
94
+ WRITE_ONCE (node -> fp , NULL );
95
+ hlist_del_rcu (& node -> hlist );
96
+ }
94
97
return !!find_first_fprobe_node (node -> addr );
95
98
}
96
99
@@ -411,6 +414,102 @@ static void fprobe_graph_remove_ips(unsigned long *addrs, int num)
411
414
ftrace_set_filter_ips (& fprobe_graph_ops .ops , addrs , num , 1 , 0 );
412
415
}
413
416
417
+ #ifdef CONFIG_MODULES
418
+
419
+ #define FPROBE_IPS_BATCH_INIT 8
420
+ /* instruction pointer address list */
421
+ struct fprobe_addr_list {
422
+ int index ;
423
+ int size ;
424
+ unsigned long * addrs ;
425
+ };
426
+
427
+ static int fprobe_addr_list_add (struct fprobe_addr_list * alist , unsigned long addr )
428
+ {
429
+ unsigned long * addrs ;
430
+
431
+ if (alist -> index >= alist -> size )
432
+ return - ENOMEM ;
433
+
434
+ alist -> addrs [alist -> index ++ ] = addr ;
435
+ if (alist -> index < alist -> size )
436
+ return 0 ;
437
+
438
+ /* Expand the address list */
439
+ addrs = kcalloc (alist -> size * 2 , sizeof (* addrs ), GFP_KERNEL );
440
+ if (!addrs )
441
+ return - ENOMEM ;
442
+
443
+ memcpy (addrs , alist -> addrs , alist -> size * sizeof (* addrs ));
444
+ alist -> size *= 2 ;
445
+ kfree (alist -> addrs );
446
+ alist -> addrs = addrs ;
447
+
448
+ return 0 ;
449
+ }
450
+
451
+ static void fprobe_remove_node_in_module (struct module * mod , struct hlist_head * head ,
452
+ struct fprobe_addr_list * alist )
453
+ {
454
+ struct fprobe_hlist_node * node ;
455
+ int ret = 0 ;
456
+
457
+ hlist_for_each_entry_rcu (node , head , hlist ) {
458
+ if (!within_module (node -> addr , mod ))
459
+ continue ;
460
+ if (delete_fprobe_node (node ))
461
+ continue ;
462
+ /*
463
+ * If failed to update alist, just continue to update hlist.
464
+ * Therefore, at list user handler will not hit anymore.
465
+ */
466
+ if (!ret )
467
+ ret = fprobe_addr_list_add (alist , node -> addr );
468
+ }
469
+ }
470
+
471
+ /* Handle module unloading to manage fprobe_ip_table. */
472
+ static int fprobe_module_callback (struct notifier_block * nb ,
473
+ unsigned long val , void * data )
474
+ {
475
+ struct fprobe_addr_list alist = {.size = FPROBE_IPS_BATCH_INIT };
476
+ struct module * mod = data ;
477
+ int i ;
478
+
479
+ if (val != MODULE_STATE_GOING )
480
+ return NOTIFY_DONE ;
481
+
482
+ alist .addrs = kcalloc (alist .size , sizeof (* alist .addrs ), GFP_KERNEL );
483
+ /* If failed to alloc memory, we can not remove ips from hash. */
484
+ if (!alist .addrs )
485
+ return NOTIFY_DONE ;
486
+
487
+ mutex_lock (& fprobe_mutex );
488
+ for (i = 0 ; i < FPROBE_IP_TABLE_SIZE ; i ++ )
489
+ fprobe_remove_node_in_module (mod , & fprobe_ip_table [i ], & alist );
490
+
491
+ if (alist .index < alist .size && alist .index > 0 )
492
+ ftrace_set_filter_ips (& fprobe_graph_ops .ops ,
493
+ alist .addrs , alist .index , 1 , 0 );
494
+ mutex_unlock (& fprobe_mutex );
495
+
496
+ kfree (alist .addrs );
497
+
498
+ return NOTIFY_DONE ;
499
+ }
500
+
501
+ static struct notifier_block fprobe_module_nb = {
502
+ .notifier_call = fprobe_module_callback ,
503
+ .priority = 0 ,
504
+ };
505
+
506
+ static int __init init_fprobe_module (void )
507
+ {
508
+ return register_module_notifier (& fprobe_module_nb );
509
+ }
510
+ early_initcall (init_fprobe_module );
511
+ #endif
512
+
414
513
static int symbols_cmp (const void * a , const void * b )
415
514
{
416
515
const char * * str_a = (const char * * ) a ;
@@ -445,6 +544,7 @@ struct filter_match_data {
445
544
size_t index ;
446
545
size_t size ;
447
546
unsigned long * addrs ;
547
+ struct module * * mods ;
448
548
};
449
549
450
550
static int filter_match_callback (void * data , const char * name , unsigned long addr )
@@ -458,30 +558,47 @@ static int filter_match_callback(void *data, const char *name, unsigned long add
458
558
if (!ftrace_location (addr ))
459
559
return 0 ;
460
560
461
- if (match -> addrs )
462
- match -> addrs [match -> index ] = addr ;
561
+ if (match -> addrs ) {
562
+ struct module * mod = __module_text_address (addr );
563
+
564
+ if (mod && !try_module_get (mod ))
565
+ return 0 ;
463
566
567
+ match -> mods [match -> index ] = mod ;
568
+ match -> addrs [match -> index ] = addr ;
569
+ }
464
570
match -> index ++ ;
465
571
return match -> index == match -> size ;
466
572
}
467
573
468
574
/*
469
575
* Make IP list from the filter/no-filter glob patterns.
470
- * Return the number of matched symbols, or -ENOENT.
576
+ * Return the number of matched symbols, or errno.
577
+ * If @addrs == NULL, this just counts the number of matched symbols. If @addrs
578
+ * is passed with an array, we need to pass the an @mods array of the same size
579
+ * to increment the module refcount for each symbol.
580
+ * This means we also need to call `module_put` for each element of @mods after
581
+ * using the @addrs.
471
582
*/
472
- static int ip_list_from_filter (const char * filter , const char * notfilter ,
473
- unsigned long * addrs , size_t size )
583
+ static int get_ips_from_filter (const char * filter , const char * notfilter ,
584
+ unsigned long * addrs , struct module * * mods ,
585
+ size_t size )
474
586
{
475
587
struct filter_match_data match = { .filter = filter , .notfilter = notfilter ,
476
- .index = 0 , .size = size , .addrs = addrs };
588
+ .index = 0 , .size = size , .addrs = addrs , . mods = mods };
477
589
int ret ;
478
590
591
+ if (addrs && !mods )
592
+ return - EINVAL ;
593
+
479
594
ret = kallsyms_on_each_symbol (filter_match_callback , & match );
480
595
if (ret < 0 )
481
596
return ret ;
482
- ret = module_kallsyms_on_each_symbol (NULL , filter_match_callback , & match );
483
- if (ret < 0 )
484
- return ret ;
597
+ if (IS_ENABLED (CONFIG_MODULES )) {
598
+ ret = module_kallsyms_on_each_symbol (NULL , filter_match_callback , & match );
599
+ if (ret < 0 )
600
+ return ret ;
601
+ }
485
602
486
603
return match .index ?: - ENOENT ;
487
604
}
@@ -543,24 +660,35 @@ static int fprobe_init(struct fprobe *fp, unsigned long *addrs, int num)
543
660
*/
544
661
int register_fprobe (struct fprobe * fp , const char * filter , const char * notfilter )
545
662
{
546
- unsigned long * addrs ;
547
- int ret ;
663
+ unsigned long * addrs __free (kfree ) = NULL ;
664
+ struct module * * mods __free (kfree ) = NULL ;
665
+ int ret , num ;
548
666
549
667
if (!fp || !filter )
550
668
return - EINVAL ;
551
669
552
- ret = ip_list_from_filter (filter , notfilter , NULL , FPROBE_IPS_MAX );
553
- if (ret < 0 )
554
- return ret ;
670
+ num = get_ips_from_filter (filter , notfilter , NULL , NULL , FPROBE_IPS_MAX );
671
+ if (num < 0 )
672
+ return num ;
555
673
556
- addrs = kcalloc (ret , sizeof (unsigned long ), GFP_KERNEL );
674
+ addrs = kcalloc (num , sizeof (* addrs ), GFP_KERNEL );
557
675
if (!addrs )
558
676
return - ENOMEM ;
559
- ret = ip_list_from_filter (filter , notfilter , addrs , ret );
560
- if (ret > 0 )
561
- ret = register_fprobe_ips (fp , addrs , ret );
562
677
563
- kfree (addrs );
678
+ mods = kcalloc (num , sizeof (* mods ), GFP_KERNEL );
679
+ if (!mods )
680
+ return - ENOMEM ;
681
+
682
+ ret = get_ips_from_filter (filter , notfilter , addrs , mods , num );
683
+ if (ret < 0 )
684
+ return ret ;
685
+
686
+ ret = register_fprobe_ips (fp , addrs , ret );
687
+
688
+ for (int i = 0 ; i < num ; i ++ ) {
689
+ if (mods [i ])
690
+ module_put (mods [i ]);
691
+ }
564
692
return ret ;
565
693
}
566
694
EXPORT_SYMBOL_GPL (register_fprobe );
0 commit comments