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.

Merge tag 'probes-v6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull probes updates from Masami Hiramatsu:

- uprobes: make trace_uprobe->nhit counter a per-CPU one

This makes uprobe event's hit counter per-CPU for improving
scalability on multi-core environment

- kprobes: Remove obsoleted declaration for init_test_probes

Remove unused init_test_probes() from header

- Raw tracepoint probe supports raw tracepoint events on modules:
- add a function for iterating over all tracepoints in all modules
- add a function for iterating over tracepoints in a module
- support raw tracepoint events on modules
- support raw tracepoints on future loaded modules
- add a test for tracepoint events on modules"

* tag 'probes-v6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
sefltests/tracing: Add a test for tracepoint events on modules
tracing/fprobe: Support raw tracepoints on future loaded modules
tracing/fprobe: Support raw tracepoint events on modules
tracepoint: Support iterating tracepoints in a loading module
tracepoint: Support iterating over tracepoints on modules
kprobes: Remove obsoleted declaration for init_test_probes
uprobes: turn trace_uprobe's nhit counter to be per-CPU one

+275 -62
-9
include/linux/kprobes.h
··· 269 269 270 270 extern struct kretprobe_blackpoint kretprobe_blacklist[]; 271 271 272 - #ifdef CONFIG_KPROBES_SANITY_TEST 273 - extern int init_test_probes(void); 274 - #else /* !CONFIG_KPROBES_SANITY_TEST */ 275 - static inline int init_test_probes(void) 276 - { 277 - return 0; 278 - } 279 - #endif /* CONFIG_KPROBES_SANITY_TEST */ 280 - 281 272 extern int arch_prepare_kprobe(struct kprobe *p); 282 273 extern void arch_arm_kprobe(struct kprobe *p); 283 274 extern void arch_disarm_kprobe(struct kprobe *p);
+20
include/linux/tracepoint.h
··· 64 64 bool trace_module_has_bad_taint(struct module *mod); 65 65 extern int register_tracepoint_module_notifier(struct notifier_block *nb); 66 66 extern int unregister_tracepoint_module_notifier(struct notifier_block *nb); 67 + void for_each_module_tracepoint(void (*fct)(struct tracepoint *, 68 + struct module *, void *), 69 + void *priv); 70 + void for_each_tracepoint_in_module(struct module *, 71 + void (*fct)(struct tracepoint *, 72 + struct module *, void *), 73 + void *priv); 67 74 #else 68 75 static inline bool trace_module_has_bad_taint(struct module *mod) 69 76 { ··· 85 78 int unregister_tracepoint_module_notifier(struct notifier_block *nb) 86 79 { 87 80 return 0; 81 + } 82 + static inline 83 + void for_each_module_tracepoint(void (*fct)(struct tracepoint *, 84 + struct module *, void *), 85 + void *priv) 86 + { 87 + } 88 + static inline 89 + void for_each_tracepoint_in_module(struct module *mod, 90 + void (*fct)(struct tracepoint *, 91 + struct module *, void *), 92 + void *priv) 93 + { 88 94 } 89 95 #endif /* CONFIG_MODULES */ 90 96
+130 -49
kernel/trace/trace_fprobe.c
··· 21 21 #define FPROBE_EVENT_SYSTEM "fprobes" 22 22 #define TRACEPOINT_EVENT_SYSTEM "tracepoints" 23 23 #define RETHOOK_MAXACTIVE_MAX 4096 24 + #define TRACEPOINT_STUB ERR_PTR(-ENOENT) 24 25 25 26 static int trace_fprobe_create(const char *raw_command); 26 27 static int trace_fprobe_show(struct seq_file *m, struct dyn_event *ev); ··· 386 385 const char *event, 387 386 const char *symbol, 388 387 struct tracepoint *tpoint, 388 + struct module *mod, 389 389 int maxactive, 390 390 int nargs, bool is_return) 391 391 { ··· 407 405 tf->fp.entry_handler = fentry_dispatcher; 408 406 409 407 tf->tpoint = tpoint; 408 + tf->mod = mod; 410 409 tf->fp.nr_maxactive = maxactive; 411 410 412 411 ret = trace_probe_init(&tf->tp, event, group, false, nargs); ··· 675 672 return trace_probe_unregister_event_call(&tf->tp); 676 673 } 677 674 675 + static int __regsiter_tracepoint_fprobe(struct trace_fprobe *tf) 676 + { 677 + struct tracepoint *tpoint = tf->tpoint; 678 + unsigned long ip = (unsigned long)tpoint->probestub; 679 + int ret; 680 + 681 + /* 682 + * Here, we do 2 steps to enable fprobe on a tracepoint. 683 + * At first, put __probestub_##TP function on the tracepoint 684 + * and put a fprobe on the stub function. 685 + */ 686 + ret = tracepoint_probe_register_prio_may_exist(tpoint, 687 + tpoint->probestub, NULL, 0); 688 + if (ret < 0) 689 + return ret; 690 + return register_fprobe_ips(&tf->fp, &ip, 1); 691 + } 692 + 678 693 /* Internal register function - just handle fprobe and flags */ 679 694 static int __register_trace_fprobe(struct trace_fprobe *tf) 680 695 { ··· 719 698 tf->fp.flags |= FPROBE_FL_DISABLED; 720 699 721 700 if (trace_fprobe_is_tracepoint(tf)) { 722 - struct tracepoint *tpoint = tf->tpoint; 723 - unsigned long ip = (unsigned long)tpoint->probestub; 724 - /* 725 - * Here, we do 2 steps to enable fprobe on a tracepoint. 726 - * At first, put __probestub_##TP function on the tracepoint 727 - * and put a fprobe on the stub function. 728 - */ 729 - ret = tracepoint_probe_register_prio_may_exist(tpoint, 730 - tpoint->probestub, NULL, 0); 731 - if (ret < 0) 732 - return ret; 733 - return register_fprobe_ips(&tf->fp, &ip, 1); 701 + 702 + /* This tracepoint is not loaded yet */ 703 + if (tf->tpoint == TRACEPOINT_STUB) 704 + return 0; 705 + 706 + return __regsiter_tracepoint_fprobe(tf); 734 707 } 735 708 736 709 /* TODO: handle filter, nofilter or symbol list */ ··· 877 862 return ret; 878 863 } 879 864 865 + struct __find_tracepoint_cb_data { 866 + const char *tp_name; 867 + struct tracepoint *tpoint; 868 + struct module *mod; 869 + }; 870 + 871 + static void __find_tracepoint_module_cb(struct tracepoint *tp, struct module *mod, void *priv) 872 + { 873 + struct __find_tracepoint_cb_data *data = priv; 874 + 875 + if (!data->tpoint && !strcmp(data->tp_name, tp->name)) { 876 + data->tpoint = tp; 877 + if (!data->mod) { 878 + data->mod = mod; 879 + if (!try_module_get(data->mod)) { 880 + data->tpoint = NULL; 881 + data->mod = NULL; 882 + } 883 + } 884 + } 885 + } 886 + 887 + static void __find_tracepoint_cb(struct tracepoint *tp, void *priv) 888 + { 889 + struct __find_tracepoint_cb_data *data = priv; 890 + 891 + if (!data->tpoint && !strcmp(data->tp_name, tp->name)) 892 + data->tpoint = tp; 893 + } 894 + 895 + /* 896 + * Find a tracepoint from kernel and module. If the tracepoint is in a module, 897 + * this increments the module refcount to prevent unloading until the 898 + * trace_fprobe is registered to the list. After registering the trace_fprobe 899 + * on the trace_fprobe list, the module refcount is decremented because 900 + * tracepoint_probe_module_cb will handle it. 901 + */ 902 + static struct tracepoint *find_tracepoint(const char *tp_name, 903 + struct module **tp_mod) 904 + { 905 + struct __find_tracepoint_cb_data data = { 906 + .tp_name = tp_name, 907 + .mod = NULL, 908 + }; 909 + 910 + for_each_kernel_tracepoint(__find_tracepoint_cb, &data); 911 + 912 + if (!data.tpoint && IS_ENABLED(CONFIG_MODULES)) { 913 + for_each_module_tracepoint(__find_tracepoint_module_cb, &data); 914 + *tp_mod = data.mod; 915 + } 916 + 917 + return data.tpoint; 918 + } 919 + 880 920 #ifdef CONFIG_MODULES 921 + static void reenable_trace_fprobe(struct trace_fprobe *tf) 922 + { 923 + struct trace_probe *tp = &tf->tp; 924 + 925 + list_for_each_entry(tf, trace_probe_probe_list(tp), tp.list) { 926 + __enable_trace_fprobe(tf); 927 + } 928 + } 929 + 930 + static struct tracepoint *find_tracepoint_in_module(struct module *mod, 931 + const char *tp_name) 932 + { 933 + struct __find_tracepoint_cb_data data = { 934 + .tp_name = tp_name, 935 + .mod = mod, 936 + }; 937 + 938 + for_each_tracepoint_in_module(mod, __find_tracepoint_module_cb, &data); 939 + return data.tpoint; 940 + } 941 + 881 942 static int __tracepoint_probe_module_cb(struct notifier_block *self, 882 943 unsigned long val, void *data) 883 944 { 884 945 struct tp_module *tp_mod = data; 946 + struct tracepoint *tpoint; 885 947 struct trace_fprobe *tf; 886 948 struct dyn_event *pos; 887 949 888 - if (val != MODULE_STATE_GOING) 950 + if (val != MODULE_STATE_GOING && val != MODULE_STATE_COMING) 889 951 return NOTIFY_DONE; 890 952 891 953 mutex_lock(&event_mutex); 892 954 for_each_trace_fprobe(tf, pos) { 893 - if (tp_mod->mod == tf->mod) { 955 + if (val == MODULE_STATE_COMING && tf->tpoint == TRACEPOINT_STUB) { 956 + tpoint = find_tracepoint_in_module(tp_mod->mod, tf->symbol); 957 + if (tpoint) { 958 + tf->tpoint = tpoint; 959 + tf->mod = tp_mod->mod; 960 + if (!WARN_ON_ONCE(__regsiter_tracepoint_fprobe(tf)) && 961 + trace_probe_is_enabled(&tf->tp)) 962 + reenable_trace_fprobe(tf); 963 + } 964 + } else if (val == MODULE_STATE_GOING && tp_mod->mod == tf->mod) { 894 965 tracepoint_probe_unregister(tf->tpoint, 895 966 tf->tpoint->probestub, NULL); 896 967 tf->tpoint = NULL; ··· 992 891 .notifier_call = __tracepoint_probe_module_cb, 993 892 }; 994 893 #endif /* CONFIG_MODULES */ 995 - 996 - struct __find_tracepoint_cb_data { 997 - const char *tp_name; 998 - struct tracepoint *tpoint; 999 - }; 1000 - 1001 - static void __find_tracepoint_cb(struct tracepoint *tp, void *priv) 1002 - { 1003 - struct __find_tracepoint_cb_data *data = priv; 1004 - 1005 - if (!data->tpoint && !strcmp(data->tp_name, tp->name)) 1006 - data->tpoint = tp; 1007 - } 1008 - 1009 - static struct tracepoint *find_tracepoint(const char *tp_name) 1010 - { 1011 - struct __find_tracepoint_cb_data data = { 1012 - .tp_name = tp_name, 1013 - }; 1014 - 1015 - for_each_kernel_tracepoint(__find_tracepoint_cb, &data); 1016 - 1017 - return data.tpoint; 1018 - } 1019 894 1020 895 static int parse_symbol_and_return(int argc, const char *argv[], 1021 896 char **symbol, bool *is_return, ··· 1073 996 char abuf[MAX_BTF_ARGS_LEN]; 1074 997 char *dbuf = NULL; 1075 998 bool is_tracepoint = false; 999 + struct module *tp_mod = NULL; 1076 1000 struct tracepoint *tpoint = NULL; 1077 1001 struct traceprobe_parse_context ctx = { 1078 1002 .flags = TPARG_FL_KERNEL | TPARG_FL_FPROBE, ··· 1158 1080 1159 1081 if (is_tracepoint) { 1160 1082 ctx.flags |= TPARG_FL_TPOINT; 1161 - tpoint = find_tracepoint(symbol); 1162 - if (!tpoint) { 1083 + tpoint = find_tracepoint(symbol, &tp_mod); 1084 + if (tpoint) { 1085 + ctx.funcname = kallsyms_lookup( 1086 + (unsigned long)tpoint->probestub, 1087 + NULL, NULL, NULL, sbuf); 1088 + } else if (IS_ENABLED(CONFIG_MODULES)) { 1089 + /* This *may* be loaded afterwards */ 1090 + tpoint = TRACEPOINT_STUB; 1091 + ctx.funcname = symbol; 1092 + } else { 1163 1093 trace_probe_log_set_index(1); 1164 1094 trace_probe_log_err(0, NO_TRACEPOINT); 1165 1095 goto parse_error; 1166 1096 } 1167 - ctx.funcname = kallsyms_lookup( 1168 - (unsigned long)tpoint->probestub, 1169 - NULL, NULL, NULL, sbuf); 1170 1097 } else 1171 1098 ctx.funcname = symbol; 1172 1099 ··· 1193 1110 goto out; 1194 1111 1195 1112 /* setup a probe */ 1196 - tf = alloc_trace_fprobe(group, event, symbol, tpoint, maxactive, 1197 - argc, is_return); 1113 + tf = alloc_trace_fprobe(group, event, symbol, tpoint, tp_mod, 1114 + maxactive, argc, is_return); 1198 1115 if (IS_ERR(tf)) { 1199 1116 ret = PTR_ERR(tf); 1200 1117 /* This must return -ENOMEM, else there is a bug */ 1201 1118 WARN_ON_ONCE(ret != -ENOMEM); 1202 1119 goto out; /* We know tf is not allocated */ 1203 1120 } 1204 - 1205 - if (is_tracepoint) 1206 - tf->mod = __module_text_address( 1207 - (unsigned long)tf->tpoint->probestub); 1208 1121 1209 1122 /* parse arguments */ 1210 1123 for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) { ··· 1234 1155 } 1235 1156 1236 1157 out: 1158 + if (tp_mod) 1159 + module_put(tp_mod); 1237 1160 traceprobe_finish_parse(&ctx); 1238 1161 trace_probe_log_clear(); 1239 1162 kfree(new_argv);
+21 -3
kernel/trace/trace_uprobe.c
··· 17 17 #include <linux/string.h> 18 18 #include <linux/rculist.h> 19 19 #include <linux/filter.h> 20 + #include <linux/percpu.h> 20 21 21 22 #include "trace_dynevent.h" 22 23 #include "trace_probe.h" ··· 63 62 struct uprobe *uprobe; 64 63 unsigned long offset; 65 64 unsigned long ref_ctr_offset; 66 - unsigned long nhit; 65 + unsigned long __percpu *nhits; 67 66 struct trace_probe tp; 68 67 }; 69 68 ··· 338 337 if (!tu) 339 338 return ERR_PTR(-ENOMEM); 340 339 340 + tu->nhits = alloc_percpu(unsigned long); 341 + if (!tu->nhits) { 342 + ret = -ENOMEM; 343 + goto error; 344 + } 345 + 341 346 ret = trace_probe_init(&tu->tp, event, group, true, nargs); 342 347 if (ret < 0) 343 348 goto error; ··· 356 349 return tu; 357 350 358 351 error: 352 + free_percpu(tu->nhits); 359 353 kfree(tu); 360 354 361 355 return ERR_PTR(ret); ··· 370 362 path_put(&tu->path); 371 363 trace_probe_cleanup(&tu->tp); 372 364 kfree(tu->filename); 365 + free_percpu(tu->nhits); 373 366 kfree(tu); 374 367 } 375 368 ··· 824 815 { 825 816 struct dyn_event *ev = v; 826 817 struct trace_uprobe *tu; 818 + unsigned long nhits; 819 + int cpu; 827 820 828 821 if (!is_trace_uprobe(ev)) 829 822 return 0; 830 823 831 824 tu = to_trace_uprobe(ev); 825 + 826 + nhits = 0; 827 + for_each_possible_cpu(cpu) { 828 + nhits += per_cpu(*tu->nhits, cpu); 829 + } 830 + 832 831 seq_printf(m, " %s %-44s %15lu\n", tu->filename, 833 - trace_probe_name(&tu->tp), tu->nhit); 832 + trace_probe_name(&tu->tp), nhits); 834 833 return 0; 835 834 } 836 835 ··· 1525 1508 int ret = 0; 1526 1509 1527 1510 tu = container_of(con, struct trace_uprobe, consumer); 1528 - tu->nhit++; 1511 + 1512 + this_cpu_inc(*tu->nhits); 1529 1513 1530 1514 udd.tu = tu; 1531 1515 udd.bp_addr = instruction_pointer(regs);
+42
kernel/tracepoint.c
··· 735 735 return ret; 736 736 } 737 737 __initcall(init_tracepoints); 738 + 739 + /** 740 + * for_each_tracepoint_in_module - iteration on all tracepoints in a module 741 + * @mod: module 742 + * @fct: callback 743 + * @priv: private data 744 + */ 745 + void for_each_tracepoint_in_module(struct module *mod, 746 + void (*fct)(struct tracepoint *tp, 747 + struct module *mod, void *priv), 748 + void *priv) 749 + { 750 + tracepoint_ptr_t *begin, *end, *iter; 751 + 752 + lockdep_assert_held(&tracepoint_module_list_mutex); 753 + 754 + if (!mod) 755 + return; 756 + 757 + begin = mod->tracepoints_ptrs; 758 + end = mod->tracepoints_ptrs + mod->num_tracepoints; 759 + 760 + for (iter = begin; iter < end; iter++) 761 + fct(tracepoint_ptr_deref(iter), mod, priv); 762 + } 763 + 764 + /** 765 + * for_each_module_tracepoint - iteration on all tracepoints in all modules 766 + * @fct: callback 767 + * @priv: private data 768 + */ 769 + void for_each_module_tracepoint(void (*fct)(struct tracepoint *tp, 770 + struct module *mod, void *priv), 771 + void *priv) 772 + { 773 + struct tp_module *tp_mod; 774 + 775 + mutex_lock(&tracepoint_module_list_mutex); 776 + list_for_each_entry(tp_mod, &tracepoint_module_list, list) 777 + for_each_tracepoint_in_module(tp_mod->mod, fct, priv); 778 + mutex_unlock(&tracepoint_module_list_mutex); 779 + } 738 780 #endif /* CONFIG_MODULES */ 739 781 740 782 /**
+1
tools/testing/selftests/ftrace/config
··· 20 20 CONFIG_PROBE_EVENTS_BTF_ARGS=y 21 21 CONFIG_SAMPLES=y 22 22 CONFIG_SAMPLE_FTRACE_DIRECT=m 23 + CONFIG_SAMPLE_TRACE_EVENTS=m 23 24 CONFIG_SAMPLE_TRACE_PRINTK=m 24 25 CONFIG_SCHED_TRACER=y 25 26 CONFIG_STACK_TRACER=y
+61
tools/testing/selftests/ftrace/test.d/dynevent/add_remove_tprobe_module.tc
··· 1 + #!/bin/sh 2 + # SPDX-License-Identifier: GPL-2.0 3 + # description: Generic dynamic event - add/remove tracepoint probe events on module 4 + # requires: dynamic_events "t[:[<group>/][<event>]] <tracepoint> [<args>]":README 5 + 6 + rmmod trace-events-sample ||: 7 + if ! modprobe trace-events-sample ; then 8 + echo "No trace-events sample module - please make CONFIG_SAMPLE_TRACE_EVENTS=m" 9 + exit_unresolved; 10 + fi 11 + trap "rmmod trace-events-sample" EXIT 12 + 13 + echo 0 > events/enable 14 + echo > dynamic_events 15 + 16 + TRACEPOINT1=foo_bar 17 + TRACEPOINT2=foo_bar_with_cond 18 + 19 + echo "t:myevent1 $TRACEPOINT1" >> dynamic_events 20 + echo "t:myevent2 $TRACEPOINT2" >> dynamic_events 21 + 22 + grep -q myevent1 dynamic_events 23 + grep -q myevent2 dynamic_events 24 + test -d events/tracepoints/myevent1 25 + test -d events/tracepoints/myevent2 26 + 27 + echo "-:myevent2" >> dynamic_events 28 + 29 + grep -q myevent1 dynamic_events 30 + ! grep -q myevent2 dynamic_events 31 + 32 + echo > dynamic_events 33 + 34 + clear_trace 35 + 36 + :;: "Try to put a probe on a tracepoint in non-loaded module" ;: 37 + rmmod trace-events-sample 38 + 39 + echo "t:myevent1 $TRACEPOINT1" >> dynamic_events 40 + echo "t:myevent2 $TRACEPOINT2" >> dynamic_events 41 + 42 + grep -q myevent1 dynamic_events 43 + grep -q myevent2 dynamic_events 44 + test -d events/tracepoints/myevent1 45 + test -d events/tracepoints/myevent2 46 + 47 + echo 1 > events/tracepoints/enable 48 + 49 + modprobe trace-events-sample 50 + 51 + sleep 2 52 + 53 + grep -q "myevent1" trace 54 + grep -q "myevent2" trace 55 + 56 + rmmod trace-events-sample 57 + trap "" EXIT 58 + 59 + echo 0 > events/tracepoints/enable 60 + echo > dynamic_events 61 + clear_trace
-1
tools/testing/selftests/ftrace/test.d/dynevent/tprobe_syntax_errors.tc
··· 9 9 10 10 check_error 't^100 kfree' # BAD_MAXACT_TYPE 11 11 12 - check_error 't ^non_exist_tracepoint' # NO_TRACEPOINT 13 12 check_error 't:^/bar kfree' # NO_GROUP_NAME 14 13 check_error 't:^12345678901234567890123456789012345678901234567890123456789012345/bar kfree' # GROUP_TOO_LONG 15 14