Skip to content

Commit 476c5bb

Browse files
committed
tracing/fprobe: Fix to unregister ftrace_ops if it is empty on module unloading
Fix fprobe to unregister ftrace_ops if corresponding type of fprobe does not exist on the fprobe_ip_table and it is expected to be empty when unloading modules. Since ftrace thinks that the empty hash means everything to be traced, if we set fprobes only on the unloaded module, all functions are traced unexpectedly after unloading module. e.g. # modprobe xt_LOG.ko # echo 'f:test log_tg*' > dynamic_events # echo 1 > events/fprobes/test/enable # cat enabled_functions log_tg [xt_LOG] (1) tramp: 0xffffffffa0004000 (fprobe_ftrace_entry+0x0/0x490) ->fprobe_ftrace_entry+0x0/0x490 log_tg_check [xt_LOG] (1) tramp: 0xffffffffa0004000 (fprobe_ftrace_entry+0x0/0x490) ->fprobe_ftrace_entry+0x0/0x490 log_tg_destroy [xt_LOG] (1) tramp: 0xffffffffa0004000 (fprobe_ftrace_entry+0x0/0x490) ->fprobe_ftrace_entry+0x0/0x490 # rmmod xt_LOG # wc -l enabled_functions 34085 enabled_functions Link: https://lore.kernel.org/all/177669368776.132053.10042301916765771279.stgit@mhiramat.tok.corp.google.com/ Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
1 parent 0ac0058 commit 476c5bb

1 file changed

Lines changed: 159 additions & 65 deletions

File tree

kernel/trace/fprobe.c

Lines changed: 159 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -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. */
255313
static 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

298359
static 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+
319389
static 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+
336438
static 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
363465
static 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+
384519
static 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
408543
static 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
}
536674
NOKPROBE_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

Comments
 (0)