Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

+159 -65
+159 -65
kernel/trace/fprobe.c
··· 79 79 }; 80 80 81 81 /* 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) 83 83 { 84 84 int ret; 85 85 ··· 92 92 return ret; 93 93 } 94 94 95 - static void delete_fprobe_node(struct fprobe_hlist_node *node) 95 + static void __delete_fprobe_node(struct fprobe_hlist_node *node) 96 96 { 97 97 lockdep_assert_held(&fprobe_mutex); 98 98 ··· 250 250 return ret; 251 251 } 252 252 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 + 253 310 #if defined(CONFIG_DYNAMIC_FTRACE_WITH_ARGS) || defined(CONFIG_DYNAMIC_FTRACE_WITH_REGS) 311 + 254 312 /* ftrace_ops callback, this processes fprobes which have only entry_handler. */ 255 313 static void fprobe_ftrace_entry(unsigned long ip, unsigned long parent_ip, 256 314 struct ftrace_ops *ops, struct ftrace_regs *fregs) ··· 351 293 .func = fprobe_ftrace_entry, 352 294 .flags = FTRACE_OPS_FL_SAVE_ARGS, 353 295 }; 354 - static int fprobe_ftrace_active; 296 + /* Number of ftrace fprobe nodes */ 297 + static int nr_ftrace_fprobes; 298 + /* Is fprobe_ftrace_ops registered? */ 299 + static bool fprobe_ftrace_registered; 355 300 356 301 static int fprobe_ftrace_add_ips(unsigned long *addrs, int num) 357 302 { ··· 366 305 if (ret) 367 306 return ret; 368 307 369 - if (!fprobe_ftrace_active) { 308 + if (!fprobe_ftrace_registered) { 370 309 ret = register_ftrace_function(&fprobe_ftrace_ops); 371 310 if (ret) { 372 311 ftrace_free_filter(&fprobe_ftrace_ops); 373 312 return ret; 374 313 } 314 + fprobe_ftrace_registered = true; 375 315 } 376 - fprobe_ftrace_active++; 377 316 return 0; 317 + } 318 + 319 + static void __fprobe_ftrace_unregister(void) 320 + { 321 + if (fprobe_ftrace_registered) { 322 + unregister_ftrace_function(&fprobe_ftrace_ops); 323 + ftrace_free_filter(&fprobe_ftrace_ops); 324 + fprobe_ftrace_registered = false; 325 + } 378 326 } 379 327 380 328 static void fprobe_ftrace_remove_ips(unsigned long *addrs, int num) 381 329 { 382 330 lockdep_assert_held(&fprobe_mutex); 383 331 384 - fprobe_ftrace_active--; 385 - if (!fprobe_ftrace_active) { 386 - unregister_ftrace_function(&fprobe_ftrace_ops); 387 - ftrace_free_filter(&fprobe_ftrace_ops); 388 - } else if (num) 332 + if (!nr_ftrace_fprobes) 333 + __fprobe_ftrace_unregister(); 334 + else if (num) 389 335 ftrace_set_filter_ips(&fprobe_ftrace_ops, addrs, num, 1, 0); 390 336 } 391 337 392 338 static bool fprobe_is_ftrace(struct fprobe *fp) 393 339 { 394 340 return !fp->exit_handler; 341 + } 342 + 343 + /* Node insertion and deletion requires the fprobe_mutex */ 344 + static int insert_fprobe_node(struct fprobe_hlist_node *node, struct fprobe *fp) 345 + { 346 + int ret; 347 + 348 + lockdep_assert_held(&fprobe_mutex); 349 + 350 + ret = __insert_fprobe_node(node, fp); 351 + if (!ret) { 352 + if (fprobe_is_ftrace(fp)) 353 + nr_ftrace_fprobes++; 354 + else 355 + nr_fgraph_fprobes++; 356 + } 357 + 358 + return ret; 359 + } 360 + 361 + static void delete_fprobe_node(struct fprobe_hlist_node *node) 362 + { 363 + struct fprobe *fp; 364 + 365 + lockdep_assert_held(&fprobe_mutex); 366 + 367 + fp = READ_ONCE(node->fp); 368 + if (fp) { 369 + if (fprobe_is_ftrace(fp)) 370 + nr_ftrace_fprobes--; 371 + else 372 + nr_fgraph_fprobes--; 373 + } 374 + __delete_fprobe_node(node); 395 375 } 396 376 397 377 static bool fprobe_exists_on_hash(unsigned long ip, bool ftrace) ··· 464 362 #ifdef CONFIG_MODULES 465 363 static void fprobe_remove_ips(unsigned long *ips, unsigned int cnt) 466 364 { 467 - ftrace_set_filter_ips(&fprobe_graph_ops.ops, ips, cnt, 1, 0); 468 - ftrace_set_filter_ips(&fprobe_ftrace_ops, ips, cnt, 1, 0); 365 + if (!nr_fgraph_fprobes) 366 + __fprobe_graph_unregister(); 367 + else if (cnt) 368 + ftrace_set_filter_ips(&fprobe_graph_ops.ops, ips, cnt, 1, 0); 369 + 370 + if (!nr_ftrace_fprobes) 371 + __fprobe_ftrace_unregister(); 372 + else if (cnt) 373 + ftrace_set_filter_ips(&fprobe_ftrace_ops, ips, cnt, 1, 0); 469 374 } 470 375 #endif 471 376 #else ··· 488 379 static bool fprobe_is_ftrace(struct fprobe *fp) 489 380 { 490 381 return false; 382 + } 383 + 384 + /* Node insertion and deletion requires the fprobe_mutex */ 385 + static int insert_fprobe_node(struct fprobe_hlist_node *node, struct fprobe *fp) 386 + { 387 + int ret; 388 + 389 + lockdep_assert_held(&fprobe_mutex); 390 + 391 + ret = __insert_fprobe_node(node, fp); 392 + if (!ret) 393 + nr_fgraph_fprobes++; 394 + 395 + return ret; 396 + } 397 + 398 + static void delete_fprobe_node(struct fprobe_hlist_node *node) 399 + { 400 + struct fprobe *fp; 401 + 402 + lockdep_assert_held(&fprobe_mutex); 403 + 404 + fp = READ_ONCE(node->fp); 405 + if (fp) 406 + nr_fgraph_fprobes--; 407 + __delete_fprobe_node(node); 491 408 } 492 409 493 410 static bool fprobe_exists_on_hash(unsigned long ip, bool ftrace __maybe_unused) ··· 542 407 #ifdef CONFIG_MODULES 543 408 static void fprobe_remove_ips(unsigned long *ips, unsigned int cnt) 544 409 { 545 - ftrace_set_filter_ips(&fprobe_graph_ops.ops, ips, cnt, 1, 0); 410 + if (!nr_fgraph_fprobes) 411 + __fprobe_graph_unregister(); 412 + else if (cnt) 413 + ftrace_set_filter_ips(&fprobe_graph_ops.ops, ips, cnt, 1, 0); 546 414 } 547 415 #endif 548 416 #endif /* !CONFIG_DYNAMIC_FTRACE_WITH_ARGS && !CONFIG_DYNAMIC_FTRACE_WITH_REGS */ ··· 673 535 } 674 536 NOKPROBE_SYMBOL(fprobe_return); 675 537 676 - static struct fgraph_ops fprobe_graph_ops = { 677 - .entryfunc = fprobe_fgraph_entry, 678 - .retfunc = fprobe_return, 679 - }; 680 - static int fprobe_graph_active; 681 - 682 - /* Add @addrs to the ftrace filter and register fgraph if needed. */ 683 - static int fprobe_graph_add_ips(unsigned long *addrs, int num) 684 - { 685 - int ret; 686 - 687 - lockdep_assert_held(&fprobe_mutex); 688 - 689 - ret = ftrace_set_filter_ips(&fprobe_graph_ops.ops, addrs, num, 0, 0); 690 - if (ret) 691 - return ret; 692 - 693 - if (!fprobe_graph_active) { 694 - ret = register_ftrace_graph(&fprobe_graph_ops); 695 - if (WARN_ON_ONCE(ret)) { 696 - ftrace_free_filter(&fprobe_graph_ops.ops); 697 - return ret; 698 - } 699 - } 700 - fprobe_graph_active++; 701 - return 0; 702 - } 703 - 704 - /* Remove @addrs from the ftrace filter and unregister fgraph if possible. */ 705 - static void fprobe_graph_remove_ips(unsigned long *addrs, int num) 706 - { 707 - lockdep_assert_held(&fprobe_mutex); 708 - 709 - fprobe_graph_active--; 710 - /* Q: should we unregister it ? */ 711 - if (!fprobe_graph_active) { 712 - unregister_ftrace_graph(&fprobe_graph_ops); 713 - ftrace_free_filter(&fprobe_graph_ops.ops); 714 - } else if (num) 715 - ftrace_set_filter_ips(&fprobe_graph_ops.ops, addrs, num, 1, 0); 716 - } 717 - 718 538 #ifdef CONFIG_MODULES 719 539 720 540 #define FPROBE_IPS_BATCH_INIT 128 ··· 749 653 } while (node == ERR_PTR(-EAGAIN) && !retry); 750 654 rhashtable_walk_exit(&iter); 751 655 /* Remove any ips from hash table(s) */ 752 - if (alist.index > 0) { 753 - fprobe_remove_ips(alist.addrs, alist.index); 754 - /* 755 - * If we break rhashtable walk loop except for -EAGAIN, we need 756 - * to restart looping from start for safety. Anyway, this is 757 - * not a hotpath. 758 - */ 759 - if (retry) 760 - goto again; 761 - } 656 + fprobe_remove_ips(alist.addrs, alist.index); 657 + /* 658 + * If we break rhashtable walk loop except for -EAGAIN, we need 659 + * to restart looping from start for safety. Anyway, this is 660 + * not a hotpath. 661 + */ 662 + if (retry) 663 + goto again; 762 664 763 665 mutex_unlock(&fprobe_mutex); 764 666