Commit | Line | Data |
---|---|---|
02119ee5 | 1 | /* |
a90917c3 | 2 | * lttng-probes.c |
02119ee5 | 3 | * |
02119ee5 | 4 | * Holds LTTng probes registry. |
17baffe2 | 5 | * |
886d51a3 MD |
6 | * Copyright (C) 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
7 | * | |
8 | * This library is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License as published by the Free Software Foundation; only | |
11 | * version 2.1 of the License. | |
12 | * | |
13 | * This library is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | * Lesser General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU Lesser General Public | |
19 | * License along with this library; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
02119ee5 MD |
21 | */ |
22 | ||
23 | #include <linux/module.h> | |
24 | #include <linux/list.h> | |
25 | #include <linux/mutex.h> | |
271b6681 | 26 | #include <linux/seq_file.h> |
02119ee5 | 27 | |
241ae9a8 | 28 | #include <lttng-events.h> |
02119ee5 | 29 | |
3c997079 MD |
30 | /* |
31 | * probe list is protected by sessions lock. | |
32 | */ | |
33 | static LIST_HEAD(_probe_list); | |
34 | ||
35 | /* | |
36 | * List of probes registered by not yet processed. | |
37 | */ | |
38 | static LIST_HEAD(lazy_probe_init); | |
02119ee5 | 39 | |
3c997079 MD |
40 | /* |
41 | * lazy_nesting counter ensures we don't trigger lazy probe registration | |
42 | * fixup while we are performing the fixup. It is protected by the | |
43 | * sessions lock. | |
44 | */ | |
45 | static int lazy_nesting; | |
46 | ||
114667d5 MD |
47 | DEFINE_PER_CPU(struct lttng_dynamic_len_stack, lttng_dynamic_len_stack); |
48 | ||
49 | EXPORT_PER_CPU_SYMBOL_GPL(lttng_dynamic_len_stack); | |
50 | ||
3c997079 MD |
51 | /* |
52 | * Called under sessions lock. | |
53 | */ | |
85a9ca7f | 54 | static |
3c997079 | 55 | int check_event_provider(struct lttng_probe_desc *desc) |
02119ee5 | 56 | { |
85a9ca7f | 57 | int i; |
3c997079 | 58 | size_t provider_name_len; |
02119ee5 | 59 | |
3c997079 MD |
60 | provider_name_len = strnlen(desc->provider, |
61 | LTTNG_KERNEL_SYM_NAME_LEN - 1); | |
62 | for (i = 0; i < desc->nr_events; i++) { | |
63 | if (strncmp(desc->event_desc[i]->name, | |
64 | desc->provider, | |
65 | provider_name_len)) | |
66 | return 0; /* provider mismatch */ | |
021153c0 MD |
67 | /* |
68 | * The event needs to contain at least provider name + _ + | |
69 | * one or more letter. | |
70 | */ | |
71 | if (strlen(desc->event_desc[i]->name) <= provider_name_len + 1) | |
72 | return 0; /* provider mismatch */ | |
73 | if (desc->event_desc[i]->name[provider_name_len] != '_') | |
74 | return 0; /* provider mismatch */ | |
3c997079 MD |
75 | } |
76 | return 1; | |
77 | } | |
78 | ||
79 | /* | |
80 | * Called under sessions lock. | |
81 | */ | |
82 | static | |
83 | void lttng_lazy_probe_register(struct lttng_probe_desc *desc) | |
84 | { | |
85 | struct lttng_probe_desc *iter; | |
86 | struct list_head *probe_list; | |
87 | ||
88 | /* | |
89 | * Each provider enforce that every event name begins with the | |
90 | * provider name. Check this in an assertion for extra | |
91 | * carefulness. This ensures we cannot have duplicate event | |
92 | * names across providers. | |
93 | */ | |
94 | WARN_ON_ONCE(!check_event_provider(desc)); | |
95 | ||
96 | /* | |
97 | * The provider ensures there are no duplicate event names. | |
98 | * Duplicated TRACEPOINT_EVENT event names would generate a | |
99 | * compile-time error due to duplicated symbol names. | |
100 | */ | |
101 | ||
102 | /* | |
103 | * We sort the providers by struct lttng_probe_desc pointer | |
104 | * address. | |
105 | */ | |
106 | probe_list = &_probe_list; | |
107 | list_for_each_entry_reverse(iter, probe_list, head) { | |
108 | BUG_ON(iter == desc); /* Should never be in the list twice */ | |
109 | if (iter < desc) { | |
110 | /* We belong to the location right after iter. */ | |
111 | list_add(&desc->head, &iter->head); | |
112 | goto desc_added; | |
85a9ca7f | 113 | } |
02119ee5 | 114 | } |
3c997079 MD |
115 | /* We should be added at the head of the list */ |
116 | list_add(&desc->head, probe_list); | |
117 | desc_added: | |
33a39a3c | 118 | pr_debug("LTTng: just registered probe %s containing %u events\n", |
3c997079 MD |
119 | desc->provider, desc->nr_events); |
120 | } | |
121 | ||
122 | /* | |
123 | * Called under sessions lock. | |
124 | */ | |
125 | static | |
126 | void fixup_lazy_probes(void) | |
127 | { | |
128 | struct lttng_probe_desc *iter, *tmp; | |
129 | int ret; | |
130 | ||
131 | lazy_nesting++; | |
132 | list_for_each_entry_safe(iter, tmp, | |
133 | &lazy_probe_init, lazy_init_head) { | |
134 | lttng_lazy_probe_register(iter); | |
135 | iter->lazy = 0; | |
136 | list_del(&iter->lazy_init_head); | |
137 | } | |
138 | ret = lttng_fix_pending_events(); | |
139 | WARN_ON_ONCE(ret); | |
140 | lazy_nesting--; | |
141 | } | |
142 | ||
143 | /* | |
144 | * Called under sessions lock. | |
145 | */ | |
146 | struct list_head *lttng_get_probe_list_head(void) | |
147 | { | |
148 | if (!lazy_nesting && !list_empty(&lazy_probe_init)) | |
149 | fixup_lazy_probes(); | |
150 | return &_probe_list; | |
151 | } | |
152 | ||
153 | static | |
154 | const struct lttng_probe_desc *find_provider(const char *provider) | |
155 | { | |
156 | struct lttng_probe_desc *iter; | |
157 | struct list_head *probe_list; | |
158 | ||
159 | probe_list = lttng_get_probe_list_head(); | |
160 | list_for_each_entry(iter, probe_list, head) { | |
161 | if (!strcmp(iter->provider, provider)) | |
162 | return iter; | |
163 | } | |
02119ee5 MD |
164 | return NULL; |
165 | } | |
166 | ||
a90917c3 | 167 | int lttng_probe_register(struct lttng_probe_desc *desc) |
02119ee5 | 168 | { |
02119ee5 | 169 | int ret = 0; |
02119ee5 | 170 | |
3c997079 MD |
171 | lttng_lock_sessions(); |
172 | ||
85a9ca7f | 173 | /* |
3c997079 | 174 | * Check if the provider has already been registered. |
85a9ca7f | 175 | */ |
3c997079 MD |
176 | if (find_provider(desc->provider)) { |
177 | ret = -EEXIST; | |
178 | goto end; | |
02119ee5 | 179 | } |
3c997079 MD |
180 | list_add(&desc->lazy_init_head, &lazy_probe_init); |
181 | desc->lazy = 1; | |
33a39a3c | 182 | pr_debug("LTTng: adding probe %s containing %u events to lazy registration list\n", |
3c997079 MD |
183 | desc->provider, desc->nr_events); |
184 | /* | |
185 | * If there is at least one active session, we need to register | |
186 | * the probe immediately, since we cannot delay event | |
187 | * registration because they are needed ASAP. | |
188 | */ | |
189 | if (lttng_session_active()) | |
190 | fixup_lazy_probes(); | |
02119ee5 | 191 | end: |
3c997079 | 192 | lttng_unlock_sessions(); |
02119ee5 MD |
193 | return ret; |
194 | } | |
a90917c3 | 195 | EXPORT_SYMBOL_GPL(lttng_probe_register); |
02119ee5 | 196 | |
a90917c3 | 197 | void lttng_probe_unregister(struct lttng_probe_desc *desc) |
02119ee5 | 198 | { |
3c997079 MD |
199 | lttng_lock_sessions(); |
200 | if (!desc->lazy) | |
201 | list_del(&desc->head); | |
202 | else | |
203 | list_del(&desc->lazy_init_head); | |
33a39a3c | 204 | pr_debug("LTTng: just unregistered probe %s\n", desc->provider); |
3c997079 | 205 | lttng_unlock_sessions(); |
02119ee5 | 206 | } |
a90917c3 | 207 | EXPORT_SYMBOL_GPL(lttng_probe_unregister); |
02119ee5 | 208 | |
3c997079 MD |
209 | /* |
210 | * TODO: this is O(nr_probes * nb_events), could be faster. | |
211 | * Called with sessions lock held. | |
212 | */ | |
213 | static | |
214 | const struct lttng_event_desc *find_event(const char *name) | |
215 | { | |
216 | struct lttng_probe_desc *probe_desc; | |
217 | int i; | |
218 | ||
219 | list_for_each_entry(probe_desc, &_probe_list, head) { | |
220 | for (i = 0; i < probe_desc->nr_events; i++) { | |
221 | if (!strcmp(probe_desc->event_desc[i]->name, name)) | |
222 | return probe_desc->event_desc[i]; | |
223 | } | |
224 | } | |
225 | return NULL; | |
226 | } | |
227 | ||
228 | /* | |
229 | * Called with sessions lock held. | |
230 | */ | |
a90917c3 | 231 | const struct lttng_event_desc *lttng_event_get(const char *name) |
02119ee5 | 232 | { |
85a9ca7f | 233 | const struct lttng_event_desc *event; |
02119ee5 MD |
234 | int ret; |
235 | ||
85a9ca7f MD |
236 | event = find_event(name); |
237 | if (!event) | |
c099397a | 238 | return NULL; |
dc7f600a | 239 | ret = try_module_get(event->owner); |
02119ee5 | 240 | WARN_ON_ONCE(!ret); |
85a9ca7f | 241 | return event; |
02119ee5 | 242 | } |
a90917c3 | 243 | EXPORT_SYMBOL_GPL(lttng_event_get); |
02119ee5 | 244 | |
3c997079 MD |
245 | /* |
246 | * Called with sessions lock held. | |
247 | */ | |
a90917c3 | 248 | void lttng_event_put(const struct lttng_event_desc *event) |
02119ee5 | 249 | { |
dc7f600a | 250 | module_put(event->owner); |
02119ee5 | 251 | } |
a90917c3 | 252 | EXPORT_SYMBOL_GPL(lttng_event_put); |
271b6681 MD |
253 | |
254 | static | |
255 | void *tp_list_start(struct seq_file *m, loff_t *pos) | |
256 | { | |
257 | struct lttng_probe_desc *probe_desc; | |
a1031097 | 258 | struct list_head *probe_list; |
271b6681 MD |
259 | int iter = 0, i; |
260 | ||
3c997079 | 261 | lttng_lock_sessions(); |
a1031097 MD |
262 | probe_list = lttng_get_probe_list_head(); |
263 | list_for_each_entry(probe_desc, probe_list, head) { | |
271b6681 MD |
264 | for (i = 0; i < probe_desc->nr_events; i++) { |
265 | if (iter++ >= *pos) | |
f7bdf4db | 266 | return (void *) probe_desc->event_desc[i]; |
271b6681 MD |
267 | } |
268 | } | |
269 | /* End of list */ | |
270 | return NULL; | |
271 | } | |
272 | ||
273 | static | |
274 | void *tp_list_next(struct seq_file *m, void *p, loff_t *ppos) | |
275 | { | |
276 | struct lttng_probe_desc *probe_desc; | |
a1031097 | 277 | struct list_head *probe_list; |
271b6681 MD |
278 | int iter = 0, i; |
279 | ||
280 | (*ppos)++; | |
a1031097 MD |
281 | probe_list = lttng_get_probe_list_head(); |
282 | list_for_each_entry(probe_desc, probe_list, head) { | |
271b6681 MD |
283 | for (i = 0; i < probe_desc->nr_events; i++) { |
284 | if (iter++ >= *ppos) | |
f7bdf4db | 285 | return (void *) probe_desc->event_desc[i]; |
271b6681 MD |
286 | } |
287 | } | |
288 | /* End of list */ | |
289 | return NULL; | |
290 | } | |
291 | ||
292 | static | |
293 | void tp_list_stop(struct seq_file *m, void *p) | |
294 | { | |
3c997079 | 295 | lttng_unlock_sessions(); |
271b6681 MD |
296 | } |
297 | ||
298 | static | |
299 | int tp_list_show(struct seq_file *m, void *p) | |
300 | { | |
301 | const struct lttng_event_desc *probe_desc = p; | |
302 | ||
303 | seq_printf(m, "event { name = %s; };\n", | |
304 | probe_desc->name); | |
305 | return 0; | |
306 | } | |
307 | ||
308 | static | |
309 | const struct seq_operations lttng_tracepoint_list_seq_ops = { | |
310 | .start = tp_list_start, | |
311 | .next = tp_list_next, | |
312 | .stop = tp_list_stop, | |
313 | .show = tp_list_show, | |
314 | }; | |
315 | ||
316 | static | |
317 | int lttng_tracepoint_list_open(struct inode *inode, struct file *file) | |
318 | { | |
319 | return seq_open(file, <tng_tracepoint_list_seq_ops); | |
320 | } | |
321 | ||
322 | const struct file_operations lttng_tracepoint_list_fops = { | |
2e54c205 | 323 | .owner = THIS_MODULE, |
271b6681 MD |
324 | .open = lttng_tracepoint_list_open, |
325 | .read = seq_read, | |
326 | .llseek = seq_lseek, | |
a51729c7 | 327 | .release = seq_release, |
271b6681 | 328 | }; |
114667d5 MD |
329 | |
330 | int lttng_probes_init(void) | |
331 | { | |
332 | int cpu; | |
333 | ||
334 | for_each_possible_cpu(cpu) | |
335 | per_cpu_ptr(<tng_dynamic_len_stack, cpu)->offset = 0; | |
336 | return 0; | |
337 | } |