@@ -89,8 +89,11 @@ static bool delete_fprobe_node(struct fprobe_hlist_node *node)
8989{
9090 lockdep_assert_held (& fprobe_mutex );
9191
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+ }
9497 return !!find_first_fprobe_node (node -> addr );
9598}
9699
@@ -411,6 +414,102 @@ static void fprobe_graph_remove_ips(unsigned long *addrs, int num)
411414 ftrace_set_filter_ips (& fprobe_graph_ops .ops , addrs , num , 1 , 0 );
412415}
413416
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+
414513static int symbols_cmp (const void * a , const void * b )
415514{
416515 const char * * str_a = (const char * * ) a ;
@@ -445,6 +544,7 @@ struct filter_match_data {
445544 size_t index ;
446545 size_t size ;
447546 unsigned long * addrs ;
547+ struct module * * mods ;
448548};
449549
450550static 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
458558 if (!ftrace_location (addr ))
459559 return 0 ;
460560
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 ;
463566
567+ match -> mods [match -> index ] = mod ;
568+ match -> addrs [match -> index ] = addr ;
569+ }
464570 match -> index ++ ;
465571 return match -> index == match -> size ;
466572}
467573
468574/*
469575 * 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.
471582 */
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 )
474586{
475587 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 };
477589 int ret ;
478590
591+ if (addrs && !mods )
592+ return - EINVAL ;
593+
479594 ret = kallsyms_on_each_symbol (filter_match_callback , & match );
480595 if (ret < 0 )
481596 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+ }
485602
486603 return match .index ?: - ENOENT ;
487604}
@@ -543,24 +660,35 @@ static int fprobe_init(struct fprobe *fp, unsigned long *addrs, int num)
543660 */
544661int register_fprobe (struct fprobe * fp , const char * filter , const char * notfilter )
545662{
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 ;
548666
549667 if (!fp || !filter )
550668 return - EINVAL ;
551669
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 ;
555673
556- addrs = kcalloc (ret , sizeof (unsigned long ), GFP_KERNEL );
674+ addrs = kcalloc (num , sizeof (* addrs ), GFP_KERNEL );
557675 if (!addrs )
558676 return - ENOMEM ;
559- ret = ip_list_from_filter (filter , notfilter , addrs , ret );
560- if (ret > 0 )
561- ret = register_fprobe_ips (fp , addrs , ret );
562677
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+ }
564692 return ret ;
565693}
566694EXPORT_SYMBOL_GPL (register_fprobe );
0 commit comments