aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/asm-generic/vmlinux.lds.h6
-rw-r--r--include/linux/module.h17
-rw-r--r--include/linux/tracepoint.h127
-rw-r--r--init/Kconfig7
-rw-r--r--kernel/Makefile1
-rw-r--r--kernel/module.c66
-rw-r--r--kernel/tracepoint.c476
7 files changed, 698 insertions, 2 deletions
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 7440a0dceddb..3d8e472a09c8 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -52,7 +52,10 @@
52 . = ALIGN(8); \ 52 . = ALIGN(8); \
53 VMLINUX_SYMBOL(__start___markers) = .; \ 53 VMLINUX_SYMBOL(__start___markers) = .; \
54 *(__markers) \ 54 *(__markers) \
55 VMLINUX_SYMBOL(__stop___markers) = .; 55 VMLINUX_SYMBOL(__stop___markers) = .; \
56 VMLINUX_SYMBOL(__start___tracepoints) = .; \
57 *(__tracepoints) \
58 VMLINUX_SYMBOL(__stop___tracepoints) = .;
56 59
57#define RO_DATA(align) \ 60#define RO_DATA(align) \
58 . = ALIGN((align)); \ 61 . = ALIGN((align)); \
@@ -61,6 +64,7 @@
61 *(.rodata) *(.rodata.*) \ 64 *(.rodata) *(.rodata.*) \
62 *(__vermagic) /* Kernel version magic */ \ 65 *(__vermagic) /* Kernel version magic */ \
63 *(__markers_strings) /* Markers: strings */ \ 66 *(__markers_strings) /* Markers: strings */ \
67 *(__tracepoints_strings)/* Tracepoints: strings */ \
64 } \ 68 } \
65 \ 69 \
66 .rodata1 : AT(ADDR(.rodata1) - LOAD_OFFSET) { \ 70 .rodata1 : AT(ADDR(.rodata1) - LOAD_OFFSET) { \
diff --git a/include/linux/module.h b/include/linux/module.h
index 68e09557c951..8b6113503863 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -16,6 +16,7 @@
16#include <linux/kobject.h> 16#include <linux/kobject.h>
17#include <linux/moduleparam.h> 17#include <linux/moduleparam.h>
18#include <linux/marker.h> 18#include <linux/marker.h>
19#include <linux/tracepoint.h>
19#include <asm/local.h> 20#include <asm/local.h>
20 21
21#include <asm/module.h> 22#include <asm/module.h>
@@ -331,6 +332,10 @@ struct module
331 struct marker *markers; 332 struct marker *markers;
332 unsigned int num_markers; 333 unsigned int num_markers;
333#endif 334#endif
335#ifdef CONFIG_TRACEPOINTS
336 struct tracepoint *tracepoints;
337 unsigned int num_tracepoints;
338#endif
334 339
335#ifdef CONFIG_MODULE_UNLOAD 340#ifdef CONFIG_MODULE_UNLOAD
336 /* What modules depend on me? */ 341 /* What modules depend on me? */
@@ -454,6 +459,9 @@ extern void print_modules(void);
454 459
455extern void module_update_markers(void); 460extern void module_update_markers(void);
456 461
462extern void module_update_tracepoints(void);
463extern int module_get_iter_tracepoints(struct tracepoint_iter *iter);
464
457#else /* !CONFIG_MODULES... */ 465#else /* !CONFIG_MODULES... */
458#define EXPORT_SYMBOL(sym) 466#define EXPORT_SYMBOL(sym)
459#define EXPORT_SYMBOL_GPL(sym) 467#define EXPORT_SYMBOL_GPL(sym)
@@ -558,6 +566,15 @@ static inline void module_update_markers(void)
558{ 566{
559} 567}
560 568
569static inline void module_update_tracepoints(void)
570{
571}
572
573static inline int module_get_iter_tracepoints(struct tracepoint_iter *iter)
574{
575 return 0;
576}
577
561#endif /* CONFIG_MODULES */ 578#endif /* CONFIG_MODULES */
562 579
563struct device_driver; 580struct device_driver;
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
new file mode 100644
index 000000000000..e623a6fca5c3
--- /dev/null
+++ b/include/linux/tracepoint.h
@@ -0,0 +1,127 @@
1#ifndef _LINUX_TRACEPOINT_H
2#define _LINUX_TRACEPOINT_H
3
4/*
5 * Kernel Tracepoint API.
6 *
7 * See Documentation/tracepoint.txt.
8 *
9 * (C) Copyright 2008 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
10 *
11 * Heavily inspired from the Linux Kernel Markers.
12 *
13 * This file is released under the GPLv2.
14 * See the file COPYING for more details.
15 */
16
17#include <linux/types.h>
18#include <linux/rcupdate.h>
19
20struct module;
21struct tracepoint;
22
23struct tracepoint {
24 const char *name; /* Tracepoint name */
25 int state; /* State. */
26 void **funcs;
27} __attribute__((aligned(8)));
28
29
30#define TPPROTO(args...) args
31#define TPARGS(args...) args
32
33#ifdef CONFIG_TRACEPOINTS
34
35/*
36 * it_func[0] is never NULL because there is at least one element in the array
37 * when the array itself is non NULL.
38 */
39#define __DO_TRACE(tp, proto, args) \
40 do { \
41 void **it_func; \
42 \
43 rcu_read_lock_sched(); \
44 it_func = rcu_dereference((tp)->funcs); \
45 if (it_func) { \
46 do { \
47 ((void(*)(proto))(*it_func))(args); \
48 } while (*(++it_func)); \
49 } \
50 rcu_read_unlock_sched(); \
51 } while (0)
52
53/*
54 * Make sure the alignment of the structure in the __tracepoints section will
55 * not add unwanted padding between the beginning of the section and the
56 * structure. Force alignment to the same alignment as the section start.
57 */
58#define DEFINE_TRACE(name, proto, args) \
59 static inline void trace_##name(proto) \
60 { \
61 static const char __tpstrtab_##name[] \
62 __attribute__((section("__tracepoints_strings"))) \
63 = #name ":" #proto; \
64 static struct tracepoint __tracepoint_##name \
65 __attribute__((section("__tracepoints"), aligned(8))) = \
66 { __tpstrtab_##name, 0, NULL }; \
67 if (unlikely(__tracepoint_##name.state)) \
68 __DO_TRACE(&__tracepoint_##name, \
69 TPPROTO(proto), TPARGS(args)); \
70 } \
71 static inline int register_trace_##name(void (*probe)(proto)) \
72 { \
73 return tracepoint_probe_register(#name ":" #proto, \
74 (void *)probe); \
75 } \
76 static inline void unregister_trace_##name(void (*probe)(proto))\
77 { \
78 tracepoint_probe_unregister(#name ":" #proto, \
79 (void *)probe); \
80 }
81
82extern void tracepoint_update_probe_range(struct tracepoint *begin,
83 struct tracepoint *end);
84
85#else /* !CONFIG_TRACEPOINTS */
86#define DEFINE_TRACE(name, proto, args) \
87 static inline void _do_trace_##name(struct tracepoint *tp, proto) \
88 { } \
89 static inline void trace_##name(proto) \
90 { } \
91 static inline int register_trace_##name(void (*probe)(proto)) \
92 { \
93 return -ENOSYS; \
94 } \
95 static inline void unregister_trace_##name(void (*probe)(proto))\
96 { }
97
98static inline void tracepoint_update_probe_range(struct tracepoint *begin,
99 struct tracepoint *end)
100{ }
101#endif /* CONFIG_TRACEPOINTS */
102
103/*
104 * Connect a probe to a tracepoint.
105 * Internal API, should not be used directly.
106 */
107extern int tracepoint_probe_register(const char *name, void *probe);
108
109/*
110 * Disconnect a probe from a tracepoint.
111 * Internal API, should not be used directly.
112 */
113extern int tracepoint_probe_unregister(const char *name, void *probe);
114
115struct tracepoint_iter {
116 struct module *module;
117 struct tracepoint *tracepoint;
118};
119
120extern void tracepoint_iter_start(struct tracepoint_iter *iter);
121extern void tracepoint_iter_next(struct tracepoint_iter *iter);
122extern void tracepoint_iter_stop(struct tracepoint_iter *iter);
123extern void tracepoint_iter_reset(struct tracepoint_iter *iter);
124extern int tracepoint_get_iter_range(struct tracepoint **tracepoint,
125 struct tracepoint *begin, struct tracepoint *end);
126
127#endif
diff --git a/init/Kconfig b/init/Kconfig
index c11da38837e5..70082678a914 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -771,6 +771,13 @@ config PROFILING
771 Say Y here to enable the extended profiling support mechanisms used 771 Say Y here to enable the extended profiling support mechanisms used
772 by profilers such as OProfile. 772 by profilers such as OProfile.
773 773
774config TRACEPOINTS
775 bool "Activate tracepoints"
776 default y
777 help
778 Place an empty function call at each tracepoint site. Can be
779 dynamically changed for a probe function.
780
774config MARKERS 781config MARKERS
775 bool "Activate markers" 782 bool "Activate markers"
776 help 783 help
diff --git a/kernel/Makefile b/kernel/Makefile
index 4e1d7df7c3e2..8f9ce7ec21b6 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -83,6 +83,7 @@ obj-$(CONFIG_SYSCTL) += utsname_sysctl.o
83obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o 83obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
84obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o 84obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o
85obj-$(CONFIG_MARKERS) += marker.o 85obj-$(CONFIG_MARKERS) += marker.o
86obj-$(CONFIG_TRACEPOINTS) += tracepoint.o
86obj-$(CONFIG_LATENCYTOP) += latencytop.o 87obj-$(CONFIG_LATENCYTOP) += latencytop.o
87obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o 88obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
88obj-$(CONFIG_FTRACE) += trace/ 89obj-$(CONFIG_FTRACE) += trace/
diff --git a/kernel/module.c b/kernel/module.c
index 9db11911e04b..661d73db786e 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -46,6 +46,7 @@
46#include <asm/cacheflush.h> 46#include <asm/cacheflush.h>
47#include <linux/license.h> 47#include <linux/license.h>
48#include <asm/sections.h> 48#include <asm/sections.h>
49#include <linux/tracepoint.h>
49 50
50#if 0 51#if 0
51#define DEBUGP printk 52#define DEBUGP printk
@@ -1831,6 +1832,8 @@ static noinline struct module *load_module(void __user *umod,
1831#endif 1832#endif
1832 unsigned int markersindex; 1833 unsigned int markersindex;
1833 unsigned int markersstringsindex; 1834 unsigned int markersstringsindex;
1835 unsigned int tracepointsindex;
1836 unsigned int tracepointsstringsindex;
1834 struct module *mod; 1837 struct module *mod;
1835 long err = 0; 1838 long err = 0;
1836 void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ 1839 void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
@@ -2117,6 +2120,9 @@ static noinline struct module *load_module(void __user *umod,
2117 markersindex = find_sec(hdr, sechdrs, secstrings, "__markers"); 2120 markersindex = find_sec(hdr, sechdrs, secstrings, "__markers");
2118 markersstringsindex = find_sec(hdr, sechdrs, secstrings, 2121 markersstringsindex = find_sec(hdr, sechdrs, secstrings,
2119 "__markers_strings"); 2122 "__markers_strings");
2123 tracepointsindex = find_sec(hdr, sechdrs, secstrings, "__tracepoints");
2124 tracepointsstringsindex = find_sec(hdr, sechdrs, secstrings,
2125 "__tracepoints_strings");
2120 2126
2121 /* Now do relocations. */ 2127 /* Now do relocations. */
2122 for (i = 1; i < hdr->e_shnum; i++) { 2128 for (i = 1; i < hdr->e_shnum; i++) {
@@ -2144,6 +2150,12 @@ static noinline struct module *load_module(void __user *umod,
2144 mod->num_markers = 2150 mod->num_markers =
2145 sechdrs[markersindex].sh_size / sizeof(*mod->markers); 2151 sechdrs[markersindex].sh_size / sizeof(*mod->markers);
2146#endif 2152#endif
2153#ifdef CONFIG_TRACEPOINTS
2154 mod->tracepoints = (void *)sechdrs[tracepointsindex].sh_addr;
2155 mod->num_tracepoints =
2156 sechdrs[tracepointsindex].sh_size / sizeof(*mod->tracepoints);
2157#endif
2158
2147 2159
2148 /* Find duplicate symbols */ 2160 /* Find duplicate symbols */
2149 err = verify_export_symbols(mod); 2161 err = verify_export_symbols(mod);
@@ -2162,11 +2174,16 @@ static noinline struct module *load_module(void __user *umod,
2162 2174
2163 add_kallsyms(mod, sechdrs, symindex, strindex, secstrings); 2175 add_kallsyms(mod, sechdrs, symindex, strindex, secstrings);
2164 2176
2177 if (!mod->taints) {
2165#ifdef CONFIG_MARKERS 2178#ifdef CONFIG_MARKERS
2166 if (!mod->taints)
2167 marker_update_probe_range(mod->markers, 2179 marker_update_probe_range(mod->markers,
2168 mod->markers + mod->num_markers); 2180 mod->markers + mod->num_markers);
2169#endif 2181#endif
2182#ifdef CONFIG_TRACEPOINTS
2183 tracepoint_update_probe_range(mod->tracepoints,
2184 mod->tracepoints + mod->num_tracepoints);
2185#endif
2186 }
2170 err = module_finalize(hdr, sechdrs, mod); 2187 err = module_finalize(hdr, sechdrs, mod);
2171 if (err < 0) 2188 if (err < 0)
2172 goto cleanup; 2189 goto cleanup;
@@ -2717,3 +2734,50 @@ void module_update_markers(void)
2717 mutex_unlock(&module_mutex); 2734 mutex_unlock(&module_mutex);
2718} 2735}
2719#endif 2736#endif
2737
2738#ifdef CONFIG_TRACEPOINTS
2739void module_update_tracepoints(void)
2740{
2741 struct module *mod;
2742
2743 mutex_lock(&module_mutex);
2744 list_for_each_entry(mod, &modules, list)
2745 if (!mod->taints)
2746 tracepoint_update_probe_range(mod->tracepoints,
2747 mod->tracepoints + mod->num_tracepoints);
2748 mutex_unlock(&module_mutex);
2749}
2750
2751/*
2752 * Returns 0 if current not found.
2753 * Returns 1 if current found.
2754 */
2755int module_get_iter_tracepoints(struct tracepoint_iter *iter)
2756{
2757 struct module *iter_mod;
2758 int found = 0;
2759
2760 mutex_lock(&module_mutex);
2761 list_for_each_entry(iter_mod, &modules, list) {
2762 if (!iter_mod->taints) {
2763 /*
2764 * Sorted module list
2765 */
2766 if (iter_mod < iter->module)
2767 continue;
2768 else if (iter_mod > iter->module)
2769 iter->tracepoint = NULL;
2770 found = tracepoint_get_iter_range(&iter->tracepoint,
2771 iter_mod->tracepoints,
2772 iter_mod->tracepoints
2773 + iter_mod->num_tracepoints);
2774 if (found) {
2775 iter->module = iter_mod;
2776 break;
2777 }
2778 }
2779 }
2780 mutex_unlock(&module_mutex);
2781 return found;
2782}
2783#endif
diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c
new file mode 100644
index 000000000000..42e86ddbd2a0
--- /dev/null
+++ b/kernel/tracepoint.c
@@ -0,0 +1,476 @@
1/*
2 * Copyright (C) 2008 Mathieu Desnoyers
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18#include <linux/module.h>
19#include <linux/mutex.h>
20#include <linux/types.h>
21#include <linux/jhash.h>
22#include <linux/list.h>
23#include <linux/rcupdate.h>
24#include <linux/tracepoint.h>
25#include <linux/err.h>
26#include <linux/slab.h>
27
28extern struct tracepoint __start___tracepoints[];
29extern struct tracepoint __stop___tracepoints[];
30
31/* Set to 1 to enable tracepoint debug output */
32static const int tracepoint_debug;
33
34/*
35 * tracepoints_mutex nests inside module_mutex. Tracepoints mutex protects the
36 * builtin and module tracepoints and the hash table.
37 */
38static DEFINE_MUTEX(tracepoints_mutex);
39
40/*
41 * Tracepoint hash table, containing the active tracepoints.
42 * Protected by tracepoints_mutex.
43 */
44#define TRACEPOINT_HASH_BITS 6
45#define TRACEPOINT_TABLE_SIZE (1 << TRACEPOINT_HASH_BITS)
46
47/*
48 * Note about RCU :
49 * It is used to to delay the free of multiple probes array until a quiescent
50 * state is reached.
51 * Tracepoint entries modifications are protected by the tracepoints_mutex.
52 */
53struct tracepoint_entry {
54 struct hlist_node hlist;
55 void **funcs;
56 int refcount; /* Number of times armed. 0 if disarmed. */
57 struct rcu_head rcu;
58 void *oldptr;
59 unsigned char rcu_pending:1;
60 char name[0];
61};
62
63static struct hlist_head tracepoint_table[TRACEPOINT_TABLE_SIZE];
64
65static void free_old_closure(struct rcu_head *head)
66{
67 struct tracepoint_entry *entry = container_of(head,
68 struct tracepoint_entry, rcu);
69 kfree(entry->oldptr);
70 /* Make sure we free the data before setting the pending flag to 0 */
71 smp_wmb();
72 entry->rcu_pending = 0;
73}
74
75static void tracepoint_entry_free_old(struct tracepoint_entry *entry, void *old)
76{
77 if (!old)
78 return;
79 entry->oldptr = old;
80 entry->rcu_pending = 1;
81 /* write rcu_pending before calling the RCU callback */
82 smp_wmb();
83#ifdef CONFIG_PREEMPT_RCU
84 synchronize_sched(); /* Until we have the call_rcu_sched() */
85#endif
86 call_rcu(&entry->rcu, free_old_closure);
87}
88
89static void debug_print_probes(struct tracepoint_entry *entry)
90{
91 int i;
92
93 if (!tracepoint_debug)
94 return;
95
96 for (i = 0; entry->funcs[i]; i++)
97 printk(KERN_DEBUG "Probe %d : %p\n", i, entry->funcs[i]);
98}
99
100static void *
101tracepoint_entry_add_probe(struct tracepoint_entry *entry, void *probe)
102{
103 int nr_probes = 0;
104 void **old, **new;
105
106 WARN_ON(!probe);
107
108 debug_print_probes(entry);
109 old = entry->funcs;
110 if (old) {
111 /* (N -> N+1), (N != 0, 1) probes */
112 for (nr_probes = 0; old[nr_probes]; nr_probes++)
113 if (old[nr_probes] == probe)
114 return ERR_PTR(-EEXIST);
115 }
116 /* + 2 : one for new probe, one for NULL func */
117 new = kzalloc((nr_probes + 2) * sizeof(void *), GFP_KERNEL);
118 if (new == NULL)
119 return ERR_PTR(-ENOMEM);
120 if (old)
121 memcpy(new, old, nr_probes * sizeof(void *));
122 new[nr_probes] = probe;
123 entry->refcount = nr_probes + 1;
124 entry->funcs = new;
125 debug_print_probes(entry);
126 return old;
127}
128
129static void *
130tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe)
131{
132 int nr_probes = 0, nr_del = 0, i;
133 void **old, **new;
134
135 old = entry->funcs;
136
137 debug_print_probes(entry);
138 /* (N -> M), (N > 1, M >= 0) probes */
139 for (nr_probes = 0; old[nr_probes]; nr_probes++) {
140 if ((!probe || old[nr_probes] == probe))
141 nr_del++;
142 }
143
144 if (nr_probes - nr_del == 0) {
145 /* N -> 0, (N > 1) */
146 entry->funcs = NULL;
147 entry->refcount = 0;
148 debug_print_probes(entry);
149 return old;
150 } else {
151 int j = 0;
152 /* N -> M, (N > 1, M > 0) */
153 /* + 1 for NULL */
154 new = kzalloc((nr_probes - nr_del + 1)
155 * sizeof(void *), GFP_KERNEL);
156 if (new == NULL)
157 return ERR_PTR(-ENOMEM);
158 for (i = 0; old[i]; i++)
159 if ((probe && old[i] != probe))
160 new[j++] = old[i];
161 entry->refcount = nr_probes - nr_del;
162 entry->funcs = new;
163 }
164 debug_print_probes(entry);
165 return old;
166}
167
168/*
169 * Get tracepoint if the tracepoint is present in the tracepoint hash table.
170 * Must be called with tracepoints_mutex held.
171 * Returns NULL if not present.
172 */
173static struct tracepoint_entry *get_tracepoint(const char *name)
174{
175 struct hlist_head *head;
176 struct hlist_node *node;
177 struct tracepoint_entry *e;
178 u32 hash = jhash(name, strlen(name), 0);
179
180 head = &tracepoint_table[hash & ((1 << TRACEPOINT_HASH_BITS)-1)];
181 hlist_for_each_entry(e, node, head, hlist) {
182 if (!strcmp(name, e->name))
183 return e;
184 }
185 return NULL;
186}
187
188/*
189 * Add the tracepoint to the tracepoint hash table. Must be called with
190 * tracepoints_mutex held.
191 */
192static struct tracepoint_entry *add_tracepoint(const char *name)
193{
194 struct hlist_head *head;
195 struct hlist_node *node;
196 struct tracepoint_entry *e;
197 size_t name_len = strlen(name) + 1;
198 u32 hash = jhash(name, name_len-1, 0);
199
200 head = &tracepoint_table[hash & ((1 << TRACEPOINT_HASH_BITS)-1)];
201 hlist_for_each_entry(e, node, head, hlist) {
202 if (!strcmp(name, e->name)) {
203 printk(KERN_NOTICE
204 "tracepoint %s busy\n", name);
205 return ERR_PTR(-EEXIST); /* Already there */
206 }
207 }
208 /*
209 * Using kmalloc here to allocate a variable length element. Could
210 * cause some memory fragmentation if overused.
211 */
212 e = kmalloc(sizeof(struct tracepoint_entry) + name_len, GFP_KERNEL);
213 if (!e)
214 return ERR_PTR(-ENOMEM);
215 memcpy(&e->name[0], name, name_len);
216 e->funcs = NULL;
217 e->refcount = 0;
218 e->rcu_pending = 0;
219 hlist_add_head(&e->hlist, head);
220 return e;
221}
222
223/*
224 * Remove the tracepoint from the tracepoint hash table. Must be called with
225 * mutex_lock held.
226 */
227static int remove_tracepoint(const char *name)
228{
229 struct hlist_head *head;
230 struct hlist_node *node;
231 struct tracepoint_entry *e;
232 int found = 0;
233 size_t len = strlen(name) + 1;
234 u32 hash = jhash(name, len-1, 0);
235
236 head = &tracepoint_table[hash & ((1 << TRACEPOINT_HASH_BITS)-1)];
237 hlist_for_each_entry(e, node, head, hlist) {
238 if (!strcmp(name, e->name)) {
239 found = 1;
240 break;
241 }
242 }
243 if (!found)
244 return -ENOENT;
245 if (e->refcount)
246 return -EBUSY;
247 hlist_del(&e->hlist);
248 /* Make sure the call_rcu has been executed */
249 if (e->rcu_pending)
250 rcu_barrier();
251 kfree(e);
252 return 0;
253}
254
255/*
256 * Sets the probe callback corresponding to one tracepoint.
257 */
258static void set_tracepoint(struct tracepoint_entry **entry,
259 struct tracepoint *elem, int active)
260{
261 WARN_ON(strcmp((*entry)->name, elem->name) != 0);
262
263 /*
264 * rcu_assign_pointer has a smp_wmb() which makes sure that the new
265 * probe callbacks array is consistent before setting a pointer to it.
266 * This array is referenced by __DO_TRACE from
267 * include/linux/tracepoints.h. A matching smp_read_barrier_depends()
268 * is used.
269 */
270 rcu_assign_pointer(elem->funcs, (*entry)->funcs);
271 elem->state = active;
272}
273
274/*
275 * Disable a tracepoint and its probe callback.
276 * Note: only waiting an RCU period after setting elem->call to the empty
277 * function insures that the original callback is not used anymore. This insured
278 * by preempt_disable around the call site.
279 */
280static void disable_tracepoint(struct tracepoint *elem)
281{
282 elem->state = 0;
283}
284
285/**
286 * tracepoint_update_probe_range - Update a probe range
287 * @begin: beginning of the range
288 * @end: end of the range
289 *
290 * Updates the probe callback corresponding to a range of tracepoints.
291 */
292void tracepoint_update_probe_range(struct tracepoint *begin,
293 struct tracepoint *end)
294{
295 struct tracepoint *iter;
296 struct tracepoint_entry *mark_entry;
297
298 mutex_lock(&tracepoints_mutex);
299 for (iter = begin; iter < end; iter++) {
300 mark_entry = get_tracepoint(iter->name);
301 if (mark_entry) {
302 set_tracepoint(&mark_entry, iter,
303 !!mark_entry->refcount);
304 } else {
305 disable_tracepoint(iter);
306 }
307 }
308 mutex_unlock(&tracepoints_mutex);
309}
310
311/*
312 * Update probes, removing the faulty probes.
313 */
314static void tracepoint_update_probes(void)
315{
316 /* Core kernel tracepoints */
317 tracepoint_update_probe_range(__start___tracepoints,
318 __stop___tracepoints);
319 /* tracepoints in modules. */
320 module_update_tracepoints();
321}
322
323/**
324 * tracepoint_probe_register - Connect a probe to a tracepoint
325 * @name: tracepoint name
326 * @probe: probe handler
327 *
328 * Returns 0 if ok, error value on error.
329 * The probe address must at least be aligned on the architecture pointer size.
330 */
331int tracepoint_probe_register(const char *name, void *probe)
332{
333 struct tracepoint_entry *entry;
334 int ret = 0;
335 void *old;
336
337 mutex_lock(&tracepoints_mutex);
338 entry = get_tracepoint(name);
339 if (!entry) {
340 entry = add_tracepoint(name);
341 if (IS_ERR(entry)) {
342 ret = PTR_ERR(entry);
343 goto end;
344 }
345 }
346 /*
347 * If we detect that a call_rcu is pending for this tracepoint,
348 * make sure it's executed now.
349 */
350 if (entry->rcu_pending)
351 rcu_barrier();
352 old = tracepoint_entry_add_probe(entry, probe);
353 if (IS_ERR(old)) {
354 ret = PTR_ERR(old);
355 goto end;
356 }
357 mutex_unlock(&tracepoints_mutex);
358 tracepoint_update_probes(); /* may update entry */
359 mutex_lock(&tracepoints_mutex);
360 entry = get_tracepoint(name);
361 WARN_ON(!entry);
362 tracepoint_entry_free_old(entry, old);
363end:
364 mutex_unlock(&tracepoints_mutex);
365 return ret;
366}
367EXPORT_SYMBOL_GPL(tracepoint_probe_register);
368
369/**
370 * tracepoint_probe_unregister - Disconnect a probe from a tracepoint
371 * @name: tracepoint name
372 * @probe: probe function pointer
373 *
374 * We do not need to call a synchronize_sched to make sure the probes have
375 * finished running before doing a module unload, because the module unload
376 * itself uses stop_machine(), which insures that every preempt disabled section
377 * have finished.
378 */
379int tracepoint_probe_unregister(const char *name, void *probe)
380{
381 struct tracepoint_entry *entry;
382 void *old;
383 int ret = -ENOENT;
384
385 mutex_lock(&tracepoints_mutex);
386 entry = get_tracepoint(name);
387 if (!entry)
388 goto end;
389 if (entry->rcu_pending)
390 rcu_barrier();
391 old = tracepoint_entry_remove_probe(entry, probe);
392 mutex_unlock(&tracepoints_mutex);
393 tracepoint_update_probes(); /* may update entry */
394 mutex_lock(&tracepoints_mutex);
395 entry = get_tracepoint(name);
396 if (!entry)
397 goto end;
398 tracepoint_entry_free_old(entry, old);
399 remove_tracepoint(name); /* Ignore busy error message */
400 ret = 0;
401end:
402 mutex_unlock(&tracepoints_mutex);
403 return ret;
404}
405EXPORT_SYMBOL_GPL(tracepoint_probe_unregister);
406
407/**
408 * tracepoint_get_iter_range - Get a next tracepoint iterator given a range.
409 * @tracepoint: current tracepoints (in), next tracepoint (out)
410 * @begin: beginning of the range
411 * @end: end of the range
412 *
413 * Returns whether a next tracepoint has been found (1) or not (0).
414 * Will return the first tracepoint in the range if the input tracepoint is
415 * NULL.
416 */
417int tracepoint_get_iter_range(struct tracepoint **tracepoint,
418 struct tracepoint *begin, struct tracepoint *end)
419{
420 if (!*tracepoint && begin != end) {
421 *tracepoint = begin;
422 return 1;
423 }
424 if (*tracepoint >= begin && *tracepoint < end)
425 return 1;
426 return 0;
427}
428EXPORT_SYMBOL_GPL(tracepoint_get_iter_range);
429
430static void tracepoint_get_iter(struct tracepoint_iter *iter)
431{
432 int found = 0;
433
434 /* Core kernel tracepoints */
435 if (!iter->module) {
436 found = tracepoint_get_iter_range(&iter->tracepoint,
437 __start___tracepoints, __stop___tracepoints);
438 if (found)
439 goto end;
440 }
441 /* tracepoints in modules. */
442 found = module_get_iter_tracepoints(iter);
443end:
444 if (!found)
445 tracepoint_iter_reset(iter);
446}
447
448void tracepoint_iter_start(struct tracepoint_iter *iter)
449{
450 tracepoint_get_iter(iter);
451}
452EXPORT_SYMBOL_GPL(tracepoint_iter_start);
453
454void tracepoint_iter_next(struct tracepoint_iter *iter)
455{
456 iter->tracepoint++;
457 /*
458 * iter->tracepoint may be invalid because we blindly incremented it.
459 * Make sure it is valid by marshalling on the tracepoints, getting the
460 * tracepoints from following modules if necessary.
461 */
462 tracepoint_get_iter(iter);
463}
464EXPORT_SYMBOL_GPL(tracepoint_iter_next);
465
466void tracepoint_iter_stop(struct tracepoint_iter *iter)
467{
468}
469EXPORT_SYMBOL_GPL(tracepoint_iter_stop);
470
471void tracepoint_iter_reset(struct tracepoint_iter *iter)
472{
473 iter->module = NULL;
474 iter->tracepoint = NULL;
475}
476EXPORT_SYMBOL_GPL(tracepoint_iter_reset);