@@ -79,7 +79,7 @@ static const struct rhashtable_params fprobe_rht_params = {
7979};
8080
8181/* Node insertion and deletion requires the fprobe_mutex */
82- static int insert_fprobe_node (struct fprobe_hlist_node * node , struct fprobe * fp )
82+ static int __insert_fprobe_node (struct fprobe_hlist_node * node , struct fprobe * fp )
8383{
8484 int ret ;
8585
@@ -92,7 +92,7 @@ static int insert_fprobe_node(struct fprobe_hlist_node *node, struct fprobe *fp)
9292 return ret ;
9393}
9494
95- static void delete_fprobe_node (struct fprobe_hlist_node * node )
95+ static void __delete_fprobe_node (struct fprobe_hlist_node * node )
9696{
9797 lockdep_assert_held (& fprobe_mutex );
9898
@@ -250,7 +250,65 @@ static inline int __fprobe_kprobe_handler(unsigned long ip, unsigned long parent
250250 return ret ;
251251}
252252
253+ static int fprobe_fgraph_entry (struct ftrace_graph_ent * trace , struct fgraph_ops * gops ,
254+ struct ftrace_regs * fregs );
255+ static void fprobe_return (struct ftrace_graph_ret * trace ,
256+ struct fgraph_ops * gops ,
257+ struct ftrace_regs * fregs );
258+
259+ static struct fgraph_ops fprobe_graph_ops = {
260+ .entryfunc = fprobe_fgraph_entry ,
261+ .retfunc = fprobe_return ,
262+ };
263+ /* Number of fgraph fprobe nodes */
264+ static int nr_fgraph_fprobes ;
265+ /* Is fprobe_graph_ops registered? */
266+ static bool fprobe_graph_registered ;
267+
268+ /* Add @addrs to the ftrace filter and register fgraph if needed. */
269+ static int fprobe_graph_add_ips (unsigned long * addrs , int num )
270+ {
271+ int ret ;
272+
273+ lockdep_assert_held (& fprobe_mutex );
274+
275+ ret = ftrace_set_filter_ips (& fprobe_graph_ops .ops , addrs , num , 0 , 0 );
276+ if (ret )
277+ return ret ;
278+
279+ if (!fprobe_graph_registered ) {
280+ ret = register_ftrace_graph (& fprobe_graph_ops );
281+ if (WARN_ON_ONCE (ret )) {
282+ ftrace_free_filter (& fprobe_graph_ops .ops );
283+ return ret ;
284+ }
285+ fprobe_graph_registered = true;
286+ }
287+ return 0 ;
288+ }
289+
290+ static void __fprobe_graph_unregister (void )
291+ {
292+ if (fprobe_graph_registered ) {
293+ unregister_ftrace_graph (& fprobe_graph_ops );
294+ ftrace_free_filter (& fprobe_graph_ops .ops );
295+ fprobe_graph_registered = false;
296+ }
297+ }
298+
299+ /* Remove @addrs from the ftrace filter and unregister fgraph if possible. */
300+ static void fprobe_graph_remove_ips (unsigned long * addrs , int num )
301+ {
302+ lockdep_assert_held (& fprobe_mutex );
303+
304+ if (!nr_fgraph_fprobes )
305+ __fprobe_graph_unregister ();
306+ else if (num )
307+ ftrace_set_filter_ips (& fprobe_graph_ops .ops , addrs , num , 1 , 0 );
308+ }
309+
253310#if defined(CONFIG_DYNAMIC_FTRACE_WITH_ARGS ) || defined(CONFIG_DYNAMIC_FTRACE_WITH_REGS )
311+
254312/* ftrace_ops callback, this processes fprobes which have only entry_handler. */
255313static void fprobe_ftrace_entry (unsigned long ip , unsigned long parent_ip ,
256314 struct ftrace_ops * ops , struct ftrace_regs * fregs )
@@ -293,7 +351,10 @@ static struct ftrace_ops fprobe_ftrace_ops = {
293351 .func = fprobe_ftrace_entry ,
294352 .flags = FTRACE_OPS_FL_SAVE_ARGS ,
295353};
296- static int fprobe_ftrace_active ;
354+ /* Number of ftrace fprobe nodes */
355+ static int nr_ftrace_fprobes ;
356+ /* Is fprobe_ftrace_ops registered? */
357+ static bool fprobe_ftrace_registered ;
297358
298359static int fprobe_ftrace_add_ips (unsigned long * addrs , int num )
299360{
@@ -305,26 +366,33 @@ static int fprobe_ftrace_add_ips(unsigned long *addrs, int num)
305366 if (ret )
306367 return ret ;
307368
308- if (!fprobe_ftrace_active ) {
369+ if (!fprobe_ftrace_registered ) {
309370 ret = register_ftrace_function (& fprobe_ftrace_ops );
310371 if (ret ) {
311372 ftrace_free_filter (& fprobe_ftrace_ops );
312373 return ret ;
313374 }
375+ fprobe_ftrace_registered = true;
314376 }
315- fprobe_ftrace_active ++ ;
316377 return 0 ;
317378}
318379
380+ static void __fprobe_ftrace_unregister (void )
381+ {
382+ if (fprobe_ftrace_registered ) {
383+ unregister_ftrace_function (& fprobe_ftrace_ops );
384+ ftrace_free_filter (& fprobe_ftrace_ops );
385+ fprobe_ftrace_registered = false;
386+ }
387+ }
388+
319389static void fprobe_ftrace_remove_ips (unsigned long * addrs , int num )
320390{
321391 lockdep_assert_held (& fprobe_mutex );
322392
323- fprobe_ftrace_active -- ;
324- if (!fprobe_ftrace_active ) {
325- unregister_ftrace_function (& fprobe_ftrace_ops );
326- ftrace_free_filter (& fprobe_ftrace_ops );
327- } else if (num )
393+ if (!nr_ftrace_fprobes )
394+ __fprobe_ftrace_unregister ();
395+ else if (num )
328396 ftrace_set_filter_ips (& fprobe_ftrace_ops , addrs , num , 1 , 0 );
329397}
330398
@@ -333,6 +401,40 @@ static bool fprobe_is_ftrace(struct fprobe *fp)
333401 return !fp -> exit_handler ;
334402}
335403
404+ /* Node insertion and deletion requires the fprobe_mutex */
405+ static int insert_fprobe_node (struct fprobe_hlist_node * node , struct fprobe * fp )
406+ {
407+ int ret ;
408+
409+ lockdep_assert_held (& fprobe_mutex );
410+
411+ ret = __insert_fprobe_node (node , fp );
412+ if (!ret ) {
413+ if (fprobe_is_ftrace (fp ))
414+ nr_ftrace_fprobes ++ ;
415+ else
416+ nr_fgraph_fprobes ++ ;
417+ }
418+
419+ return ret ;
420+ }
421+
422+ static void delete_fprobe_node (struct fprobe_hlist_node * node )
423+ {
424+ struct fprobe * fp ;
425+
426+ lockdep_assert_held (& fprobe_mutex );
427+
428+ fp = READ_ONCE (node -> fp );
429+ if (fp ) {
430+ if (fprobe_is_ftrace (fp ))
431+ nr_ftrace_fprobes -- ;
432+ else
433+ nr_fgraph_fprobes -- ;
434+ }
435+ __delete_fprobe_node (node );
436+ }
437+
336438static bool fprobe_exists_on_hash (unsigned long ip , bool ftrace )
337439{
338440 struct rhlist_head * head , * pos ;
@@ -362,8 +464,15 @@ static bool fprobe_exists_on_hash(unsigned long ip, bool ftrace)
362464#ifdef CONFIG_MODULES
363465static void fprobe_remove_ips (unsigned long * ips , unsigned int cnt )
364466{
365- ftrace_set_filter_ips (& fprobe_graph_ops .ops , ips , cnt , 1 , 0 );
366- ftrace_set_filter_ips (& fprobe_ftrace_ops , ips , cnt , 1 , 0 );
467+ if (!nr_fgraph_fprobes )
468+ __fprobe_graph_unregister ();
469+ else if (cnt )
470+ ftrace_set_filter_ips (& fprobe_graph_ops .ops , ips , cnt , 1 , 0 );
471+
472+ if (!nr_ftrace_fprobes )
473+ __fprobe_ftrace_unregister ();
474+ else if (cnt )
475+ ftrace_set_filter_ips (& fprobe_ftrace_ops , ips , cnt , 1 , 0 );
367476}
368477#endif
369478#else
@@ -381,6 +490,32 @@ static bool fprobe_is_ftrace(struct fprobe *fp)
381490 return false;
382491}
383492
493+ /* Node insertion and deletion requires the fprobe_mutex */
494+ static int insert_fprobe_node (struct fprobe_hlist_node * node , struct fprobe * fp )
495+ {
496+ int ret ;
497+
498+ lockdep_assert_held (& fprobe_mutex );
499+
500+ ret = __insert_fprobe_node (node , fp );
501+ if (!ret )
502+ nr_fgraph_fprobes ++ ;
503+
504+ return ret ;
505+ }
506+
507+ static void delete_fprobe_node (struct fprobe_hlist_node * node )
508+ {
509+ struct fprobe * fp ;
510+
511+ lockdep_assert_held (& fprobe_mutex );
512+
513+ fp = READ_ONCE (node -> fp );
514+ if (fp )
515+ nr_fgraph_fprobes -- ;
516+ __delete_fprobe_node (node );
517+ }
518+
384519static bool fprobe_exists_on_hash (unsigned long ip , bool ftrace __maybe_unused )
385520{
386521 struct rhlist_head * head , * pos ;
@@ -407,7 +542,10 @@ static bool fprobe_exists_on_hash(unsigned long ip, bool ftrace __maybe_unused)
407542#ifdef CONFIG_MODULES
408543static void fprobe_remove_ips (unsigned long * ips , unsigned int cnt )
409544{
410- ftrace_set_filter_ips (& fprobe_graph_ops .ops , ips , cnt , 1 , 0 );
545+ if (!nr_fgraph_fprobes )
546+ __fprobe_graph_unregister ();
547+ else if (cnt )
548+ ftrace_set_filter_ips (& fprobe_graph_ops .ops , ips , cnt , 1 , 0 );
411549}
412550#endif
413551#endif /* !CONFIG_DYNAMIC_FTRACE_WITH_ARGS && !CONFIG_DYNAMIC_FTRACE_WITH_REGS */
@@ -535,48 +673,6 @@ static void fprobe_return(struct ftrace_graph_ret *trace,
535673}
536674NOKPROBE_SYMBOL (fprobe_return );
537675
538- static struct fgraph_ops fprobe_graph_ops = {
539- .entryfunc = fprobe_fgraph_entry ,
540- .retfunc = fprobe_return ,
541- };
542- static int fprobe_graph_active ;
543-
544- /* Add @addrs to the ftrace filter and register fgraph if needed. */
545- static int fprobe_graph_add_ips (unsigned long * addrs , int num )
546- {
547- int ret ;
548-
549- lockdep_assert_held (& fprobe_mutex );
550-
551- ret = ftrace_set_filter_ips (& fprobe_graph_ops .ops , addrs , num , 0 , 0 );
552- if (ret )
553- return ret ;
554-
555- if (!fprobe_graph_active ) {
556- ret = register_ftrace_graph (& fprobe_graph_ops );
557- if (WARN_ON_ONCE (ret )) {
558- ftrace_free_filter (& fprobe_graph_ops .ops );
559- return ret ;
560- }
561- }
562- fprobe_graph_active ++ ;
563- return 0 ;
564- }
565-
566- /* Remove @addrs from the ftrace filter and unregister fgraph if possible. */
567- static void fprobe_graph_remove_ips (unsigned long * addrs , int num )
568- {
569- lockdep_assert_held (& fprobe_mutex );
570-
571- fprobe_graph_active -- ;
572- /* Q: should we unregister it ? */
573- if (!fprobe_graph_active ) {
574- unregister_ftrace_graph (& fprobe_graph_ops );
575- ftrace_free_filter (& fprobe_graph_ops .ops );
576- } else if (num )
577- ftrace_set_filter_ips (& fprobe_graph_ops .ops , addrs , num , 1 , 0 );
578- }
579-
580676#ifdef CONFIG_MODULES
581677
582678#define FPROBE_IPS_BATCH_INIT 128
@@ -653,16 +749,14 @@ static int fprobe_module_callback(struct notifier_block *nb,
653749 } while (node == ERR_PTR (- EAGAIN ) && !retry );
654750 rhashtable_walk_exit (& iter );
655751 /* Remove any ips from hash table(s) */
656- if (alist .index > 0 ) {
657- fprobe_remove_ips (alist .addrs , alist .index );
658- /*
659- * If we break rhashtable walk loop except for -EAGAIN, we need
660- * to restart looping from start for safety. Anyway, this is
661- * not a hotpath.
662- */
663- if (retry )
664- goto again ;
665- }
752+ fprobe_remove_ips (alist .addrs , alist .index );
753+ /*
754+ * If we break rhashtable walk loop except for -EAGAIN, we need
755+ * to restart looping from start for safety. Anyway, this is
756+ * not a hotpath.
757+ */
758+ if (retry )
759+ goto again ;
666760
667761 mutex_unlock (& fprobe_mutex );
668762
0 commit comments