Commit | Line | Data |
---|---|---|
9dad1eb8 | 1 | /* |
c1f20530 | 2 | * tracer.c |
9dad1eb8 PMF |
3 | * |
4 | * (C) Copyright 2005-2008 - | |
5 | * Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca) | |
6 | * | |
34e4b7db PMF |
7 | * This library is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 | * | |
9dad1eb8 PMF |
21 | * Inspired from LTT : |
22 | * Karim Yaghmour (karim@opersys.com) | |
23 | * Tom Zanussi (zanussi@us.ibm.com) | |
24 | * Bob Wisniewski (bob@watson.ibm.com) | |
25 | * And from K42 : | |
26 | * Bob Wisniewski (bob@watson.ibm.com) | |
27 | * | |
28 | * Changelog: | |
29 | * 22/09/06, Move to the marker/probes mechanism. | |
30 | * 19/10/05, Complete lockless mechanism. | |
31 | * 27/05/05, Modular redesign and rewrite. | |
32 | */ | |
33 | ||
b5b073e2 | 34 | #include <urcu-bp.h> |
b7ea1a1c | 35 | #include <urcu/rculist.h> |
4268fdcd | 36 | |
518d7abb PMF |
37 | #include <ust/clock.h> |
38 | ||
b6bf28ec | 39 | #include "tracercore.h" |
c93858f1 | 40 | #include "tracer.h" |
30ffe279 | 41 | #include "usterr_signal_safe.h" |
b6bf28ec | 42 | |
223f2e7c | 43 | struct chan_info_struct chan_infos[] = { |
9dad1eb8 PMF |
44 | [LTT_CHANNEL_METADATA] = { |
45 | LTT_METADATA_CHANNEL, | |
46 | LTT_DEFAULT_SUBBUF_SIZE_LOW, | |
47 | LTT_DEFAULT_N_SUBBUFS_LOW, | |
48 | }, | |
b6bf28ec PMF |
49 | [LTT_CHANNEL_UST] = { |
50 | LTT_UST_CHANNEL, | |
9dad1eb8 PMF |
51 | LTT_DEFAULT_SUBBUF_SIZE_HIGH, |
52 | LTT_DEFAULT_N_SUBBUFS_HIGH, | |
53 | }, | |
9dad1eb8 PMF |
54 | }; |
55 | ||
56 | static enum ltt_channels get_channel_type_from_name(const char *name) | |
57 | { | |
58 | int i; | |
59 | ||
60 | if (!name) | |
b6bf28ec | 61 | return LTT_CHANNEL_UST; |
9dad1eb8 PMF |
62 | |
63 | for (i = 0; i < ARRAY_SIZE(chan_infos); i++) | |
64 | if (chan_infos[i].name && !strcmp(name, chan_infos[i].name)) | |
65 | return (enum ltt_channels)i; | |
66 | ||
b6bf28ec | 67 | return LTT_CHANNEL_UST; |
9dad1eb8 PMF |
68 | } |
69 | ||
0222e121 | 70 | static CDS_LIST_HEAD(ltt_transport_list); |
8d6300d3 NC |
71 | /* transport mutex, nests inside traces mutex (ltt_lock_traces) */ |
72 | static DEFINE_MUTEX(ltt_transport_mutex); | |
9dad1eb8 PMF |
73 | /** |
74 | * ltt_transport_register - LTT transport registration | |
75 | * @transport: transport structure | |
76 | * | |
77 | * Registers a transport which can be used as output to extract the data out of | |
78 | * LTTng. The module calling this registration function must ensure that no | |
79 | * trap-inducing code will be executed by the transport functions. E.g. | |
80 | * vmalloc_sync_all() must be called between a vmalloc and the moment the memory | |
81 | * is made visible to the transport function. This registration acts as a | |
82 | * vmalloc_sync_all. Therefore, only if the module allocates virtual memory | |
83 | * after its registration must it synchronize the TLBs. | |
84 | */ | |
5f54827b PMF |
85 | void ltt_transport_register(struct ltt_transport *transport) |
86 | { | |
8d6300d3 | 87 | pthread_mutex_lock(<t_transport_mutex); |
0222e121 | 88 | cds_list_add_tail(&transport->node, <t_transport_list); |
8d6300d3 | 89 | pthread_mutex_unlock(<t_transport_mutex); |
5f54827b | 90 | } |
9dad1eb8 PMF |
91 | |
92 | /** | |
93 | * ltt_transport_unregister - LTT transport unregistration | |
94 | * @transport: transport structure | |
95 | */ | |
bb07823d PMF |
96 | void ltt_transport_unregister(struct ltt_transport *transport) |
97 | { | |
8d6300d3 | 98 | pthread_mutex_lock(<t_transport_mutex); |
0222e121 | 99 | cds_list_del(&transport->node); |
8d6300d3 | 100 | pthread_mutex_unlock(<t_transport_mutex); |
bb07823d | 101 | } |
9dad1eb8 PMF |
102 | |
103 | static inline int is_channel_overwrite(enum ltt_channels chan, | |
104 | enum trace_mode mode) | |
105 | { | |
106 | switch (mode) { | |
107 | case LTT_TRACE_NORMAL: | |
108 | return 0; | |
109 | case LTT_TRACE_FLIGHT: | |
110 | switch (chan) { | |
111 | case LTT_CHANNEL_METADATA: | |
112 | return 0; | |
113 | default: | |
114 | return 1; | |
115 | } | |
116 | case LTT_TRACE_HYBRID: | |
117 | switch (chan) { | |
b6bf28ec | 118 | case LTT_CHANNEL_METADATA: |
9dad1eb8 | 119 | return 0; |
b6bf28ec PMF |
120 | default: |
121 | return 1; | |
9dad1eb8 PMF |
122 | } |
123 | default: | |
124 | return 0; | |
125 | } | |
126 | } | |
127 | ||
b73a4c47 | 128 | static void trace_async_wakeup(struct ust_trace *trace) |
9dad1eb8 PMF |
129 | { |
130 | int i; | |
b5b073e2 | 131 | struct ust_channel *chan; |
9dad1eb8 PMF |
132 | |
133 | /* Must check each channel for pending read wakeup */ | |
134 | for (i = 0; i < trace->nr_channels; i++) { | |
135 | chan = &trace->channels[i]; | |
136 | if (chan->active) | |
137 | trace->ops->wakeup_channel(chan); | |
138 | } | |
139 | } | |
140 | ||
9dad1eb8 PMF |
141 | /** |
142 | * _ltt_trace_find - find a trace by given name. | |
143 | * trace_name: trace name | |
144 | * | |
145 | * Returns a pointer to the trace structure, NULL if not found. | |
146 | */ | |
b73a4c47 | 147 | struct ust_trace *_ltt_trace_find(const char *trace_name) |
9dad1eb8 | 148 | { |
b73a4c47 | 149 | struct ust_trace *trace; |
9dad1eb8 | 150 | |
0222e121 | 151 | cds_list_for_each_entry(trace, <t_traces.head, list) |
9dad1eb8 PMF |
152 | if (!strncmp(trace->trace_name, trace_name, NAME_MAX)) |
153 | return trace; | |
154 | ||
155 | return NULL; | |
156 | } | |
157 | ||
158 | /* _ltt_trace_find_setup : | |
159 | * find a trace in setup list by given name. | |
160 | * | |
161 | * Returns a pointer to the trace structure, NULL if not found. | |
162 | */ | |
b73a4c47 | 163 | struct ust_trace *_ltt_trace_find_setup(const char *trace_name) |
9dad1eb8 | 164 | { |
b73a4c47 | 165 | struct ust_trace *trace; |
9dad1eb8 | 166 | |
0222e121 | 167 | cds_list_for_each_entry(trace, <t_traces.setup_head, list) |
9dad1eb8 PMF |
168 | if (!strncmp(trace->trace_name, trace_name, NAME_MAX)) |
169 | return trace; | |
170 | ||
171 | return NULL; | |
172 | } | |
9dad1eb8 PMF |
173 | |
174 | /** | |
175 | * ltt_release_transport - Release an LTT transport | |
176 | * @kref : reference count on the transport | |
177 | */ | |
205f7ca7 | 178 | void ltt_release_transport(struct urcu_ref *urcu_ref) |
9dad1eb8 | 179 | { |
841f7e9c | 180 | return; |
9dad1eb8 | 181 | } |
9dad1eb8 PMF |
182 | |
183 | /** | |
184 | * ltt_release_trace - Release a LTT trace | |
185 | * @kref : reference count on the trace | |
186 | */ | |
205f7ca7 | 187 | void ltt_release_trace(struct urcu_ref *urcu_ref) |
9dad1eb8 | 188 | { |
205f7ca7 DG |
189 | struct ust_trace *trace = _ust_container_of(urcu_ref, |
190 | struct ust_trace, urcu_ref); | |
9dad1eb8 | 191 | ltt_channels_trace_free(trace->channels); |
909bc43f | 192 | free(trace); |
9dad1eb8 | 193 | } |
9dad1eb8 PMF |
194 | |
195 | static inline void prepare_chan_size_num(unsigned int *subbuf_size, | |
196 | unsigned int *n_subbufs) | |
197 | { | |
b73a4c47 PMF |
198 | /* Make sure the subbuffer size is larger than a page */ |
199 | *subbuf_size = max_t(unsigned int, *subbuf_size, PAGE_SIZE); | |
200 | ||
201 | /* round to next power of 2 */ | |
9dad1eb8 PMF |
202 | *subbuf_size = 1 << get_count_order(*subbuf_size); |
203 | *n_subbufs = 1 << get_count_order(*n_subbufs); | |
204 | ||
205 | /* Subbuf size and number must both be power of two */ | |
206 | WARN_ON(hweight32(*subbuf_size) != 1); | |
207 | WARN_ON(hweight32(*n_subbufs) != 1); | |
208 | } | |
209 | ||
210 | int _ltt_trace_setup(const char *trace_name) | |
211 | { | |
212 | int err = 0; | |
b73a4c47 | 213 | struct ust_trace *new_trace = NULL; |
9dad1eb8 PMF |
214 | int metadata_index; |
215 | unsigned int chan; | |
216 | enum ltt_channels chantype; | |
217 | ||
218 | if (_ltt_trace_find_setup(trace_name)) { | |
c1f20530 | 219 | ERR("Trace name %s already used", trace_name); |
9dad1eb8 PMF |
220 | err = -EEXIST; |
221 | goto traces_error; | |
222 | } | |
223 | ||
224 | if (_ltt_trace_find(trace_name)) { | |
c1f20530 | 225 | ERR("Trace name %s already used", trace_name); |
9dad1eb8 PMF |
226 | err = -EEXIST; |
227 | goto traces_error; | |
228 | } | |
229 | ||
909bc43f | 230 | new_trace = zmalloc(sizeof(struct ust_trace)); |
9dad1eb8 | 231 | if (!new_trace) { |
c1f20530 | 232 | ERR("Unable to allocate memory for trace %s", trace_name); |
9dad1eb8 PMF |
233 | err = -ENOMEM; |
234 | goto traces_error; | |
235 | } | |
236 | strncpy(new_trace->trace_name, trace_name, NAME_MAX); | |
237 | new_trace->channels = ltt_channels_trace_alloc(&new_trace->nr_channels, | |
8649cd59 PMF |
238 | ust_channels_overwrite_by_default, |
239 | ust_channels_request_collection_by_default, 1); | |
9dad1eb8 | 240 | if (!new_trace->channels) { |
c1f20530 | 241 | ERR("Unable to allocate memory for chaninfo %s\n", trace_name); |
9dad1eb8 PMF |
242 | err = -ENOMEM; |
243 | goto trace_free; | |
244 | } | |
245 | ||
246 | /* | |
247 | * Force metadata channel to active, no overwrite. | |
248 | */ | |
249 | metadata_index = ltt_channels_get_index_from_name("metadata"); | |
250 | WARN_ON(metadata_index < 0); | |
251 | new_trace->channels[metadata_index].overwrite = 0; | |
252 | new_trace->channels[metadata_index].active = 1; | |
253 | ||
254 | /* | |
255 | * Set hardcoded tracer defaults for some channels | |
256 | */ | |
257 | for (chan = 0; chan < new_trace->nr_channels; chan++) { | |
258 | if (!(new_trace->channels[chan].active)) | |
259 | continue; | |
260 | ||
261 | chantype = get_channel_type_from_name( | |
262 | ltt_channels_get_name_from_index(chan)); | |
263 | new_trace->channels[chan].subbuf_size = | |
264 | chan_infos[chantype].def_subbufsize; | |
265 | new_trace->channels[chan].subbuf_cnt = | |
266 | chan_infos[chantype].def_subbufcount; | |
267 | } | |
268 | ||
0222e121 | 269 | cds_list_add(&new_trace->list, <t_traces.setup_head); |
9dad1eb8 PMF |
270 | return 0; |
271 | ||
272 | trace_free: | |
909bc43f | 273 | free(new_trace); |
9dad1eb8 PMF |
274 | traces_error: |
275 | return err; | |
276 | } | |
9dad1eb8 PMF |
277 | |
278 | ||
279 | int ltt_trace_setup(const char *trace_name) | |
280 | { | |
281 | int ret; | |
282 | ltt_lock_traces(); | |
283 | ret = _ltt_trace_setup(trace_name); | |
284 | ltt_unlock_traces(); | |
285 | return ret; | |
286 | } | |
9dad1eb8 PMF |
287 | |
288 | /* must be called from within a traces lock. */ | |
b73a4c47 | 289 | static void _ltt_trace_free(struct ust_trace *trace) |
9dad1eb8 | 290 | { |
0222e121 | 291 | cds_list_del(&trace->list); |
909bc43f | 292 | free(trace); |
9dad1eb8 PMF |
293 | } |
294 | ||
295 | int ltt_trace_set_type(const char *trace_name, const char *trace_type) | |
296 | { | |
297 | int err = 0; | |
b73a4c47 | 298 | struct ust_trace *trace; |
9dad1eb8 PMF |
299 | struct ltt_transport *tran_iter, *transport = NULL; |
300 | ||
301 | ltt_lock_traces(); | |
302 | ||
303 | trace = _ltt_trace_find_setup(trace_name); | |
304 | if (!trace) { | |
c1f20530 | 305 | ERR("Trace not found %s", trace_name); |
9dad1eb8 PMF |
306 | err = -ENOENT; |
307 | goto traces_error; | |
308 | } | |
309 | ||
8d6300d3 | 310 | pthread_mutex_lock(<t_transport_mutex); |
0222e121 | 311 | cds_list_for_each_entry(tran_iter, <t_transport_list, node) { |
9dad1eb8 PMF |
312 | if (!strcmp(tran_iter->name, trace_type)) { |
313 | transport = tran_iter; | |
314 | break; | |
315 | } | |
316 | } | |
8d6300d3 NC |
317 | pthread_mutex_unlock(<t_transport_mutex); |
318 | ||
9dad1eb8 | 319 | if (!transport) { |
c1f20530 | 320 | ERR("Transport %s is not present", trace_type); |
9dad1eb8 PMF |
321 | err = -EINVAL; |
322 | goto traces_error; | |
323 | } | |
324 | ||
325 | trace->transport = transport; | |
326 | ||
327 | traces_error: | |
328 | ltt_unlock_traces(); | |
329 | return err; | |
330 | } | |
9dad1eb8 PMF |
331 | |
332 | int ltt_trace_set_channel_subbufsize(const char *trace_name, | |
333 | const char *channel_name, unsigned int size) | |
334 | { | |
335 | int err = 0; | |
b73a4c47 | 336 | struct ust_trace *trace; |
9dad1eb8 PMF |
337 | int index; |
338 | ||
339 | ltt_lock_traces(); | |
340 | ||
341 | trace = _ltt_trace_find_setup(trace_name); | |
342 | if (!trace) { | |
c1f20530 | 343 | ERR("Trace not found %s", trace_name); |
9dad1eb8 PMF |
344 | err = -ENOENT; |
345 | goto traces_error; | |
346 | } | |
347 | ||
348 | index = ltt_channels_get_index_from_name(channel_name); | |
349 | if (index < 0) { | |
c1f20530 | 350 | ERR("Channel %s not found", channel_name); |
9dad1eb8 PMF |
351 | err = -ENOENT; |
352 | goto traces_error; | |
353 | } | |
354 | trace->channels[index].subbuf_size = size; | |
355 | ||
356 | traces_error: | |
357 | ltt_unlock_traces(); | |
358 | return err; | |
359 | } | |
9dad1eb8 PMF |
360 | |
361 | int ltt_trace_set_channel_subbufcount(const char *trace_name, | |
362 | const char *channel_name, unsigned int cnt) | |
363 | { | |
364 | int err = 0; | |
b73a4c47 | 365 | struct ust_trace *trace; |
9dad1eb8 PMF |
366 | int index; |
367 | ||
368 | ltt_lock_traces(); | |
369 | ||
370 | trace = _ltt_trace_find_setup(trace_name); | |
371 | if (!trace) { | |
c1f20530 | 372 | ERR("Trace not found %s", trace_name); |
9dad1eb8 PMF |
373 | err = -ENOENT; |
374 | goto traces_error; | |
375 | } | |
376 | ||
377 | index = ltt_channels_get_index_from_name(channel_name); | |
378 | if (index < 0) { | |
c1f20530 | 379 | ERR("Channel %s not found", channel_name); |
9dad1eb8 PMF |
380 | err = -ENOENT; |
381 | goto traces_error; | |
382 | } | |
383 | trace->channels[index].subbuf_cnt = cnt; | |
384 | ||
385 | traces_error: | |
386 | ltt_unlock_traces(); | |
387 | return err; | |
388 | } | |
9dad1eb8 PMF |
389 | |
390 | int ltt_trace_set_channel_enable(const char *trace_name, | |
391 | const char *channel_name, unsigned int enable) | |
392 | { | |
393 | int err = 0; | |
b73a4c47 | 394 | struct ust_trace *trace; |
9dad1eb8 PMF |
395 | int index; |
396 | ||
397 | ltt_lock_traces(); | |
398 | ||
399 | trace = _ltt_trace_find_setup(trace_name); | |
400 | if (!trace) { | |
c1f20530 | 401 | ERR("Trace not found %s", trace_name); |
9dad1eb8 PMF |
402 | err = -ENOENT; |
403 | goto traces_error; | |
404 | } | |
405 | ||
406 | /* | |
407 | * Datas in metadata channel(marker info) is necessary to be able to | |
408 | * read the trace, we always enable this channel. | |
409 | */ | |
410 | if (!enable && !strcmp(channel_name, "metadata")) { | |
c1f20530 | 411 | ERR("Trying to disable metadata channel"); |
9dad1eb8 PMF |
412 | err = -EINVAL; |
413 | goto traces_error; | |
414 | } | |
415 | ||
416 | index = ltt_channels_get_index_from_name(channel_name); | |
417 | if (index < 0) { | |
c1f20530 | 418 | ERR("Channel %s not found", channel_name); |
9dad1eb8 PMF |
419 | err = -ENOENT; |
420 | goto traces_error; | |
421 | } | |
422 | ||
423 | trace->channels[index].active = enable; | |
424 | ||
425 | traces_error: | |
426 | ltt_unlock_traces(); | |
427 | return err; | |
428 | } | |
9dad1eb8 PMF |
429 | |
430 | int ltt_trace_set_channel_overwrite(const char *trace_name, | |
431 | const char *channel_name, unsigned int overwrite) | |
432 | { | |
433 | int err = 0; | |
b73a4c47 | 434 | struct ust_trace *trace; |
9dad1eb8 PMF |
435 | int index; |
436 | ||
437 | ltt_lock_traces(); | |
438 | ||
439 | trace = _ltt_trace_find_setup(trace_name); | |
440 | if (!trace) { | |
c1f20530 | 441 | ERR("Trace not found %s", trace_name); |
9dad1eb8 PMF |
442 | err = -ENOENT; |
443 | goto traces_error; | |
444 | } | |
445 | ||
446 | /* | |
447 | * Always put the metadata channel in non-overwrite mode : | |
448 | * This is a very low traffic channel and it can't afford to have its | |
449 | * data overwritten : this data (marker info) is necessary to be | |
450 | * able to read the trace. | |
451 | */ | |
452 | if (overwrite && !strcmp(channel_name, "metadata")) { | |
c1f20530 | 453 | ERR("Trying to set metadata channel to overwrite mode"); |
9dad1eb8 PMF |
454 | err = -EINVAL; |
455 | goto traces_error; | |
456 | } | |
457 | ||
458 | index = ltt_channels_get_index_from_name(channel_name); | |
459 | if (index < 0) { | |
c1f20530 | 460 | ERR("Channel %s not found", channel_name); |
9dad1eb8 PMF |
461 | err = -ENOENT; |
462 | goto traces_error; | |
463 | } | |
464 | ||
465 | trace->channels[index].overwrite = overwrite; | |
466 | ||
467 | traces_error: | |
468 | ltt_unlock_traces(); | |
469 | return err; | |
470 | } | |
9dad1eb8 PMF |
471 | |
472 | int ltt_trace_alloc(const char *trace_name) | |
473 | { | |
474 | int err = 0; | |
b73a4c47 | 475 | struct ust_trace *trace; |
c697d411 | 476 | unsigned int subbuf_size, subbuf_cnt; |
9dad1eb8 PMF |
477 | int chan; |
478 | const char *channel_name; | |
479 | ||
480 | ltt_lock_traces(); | |
481 | ||
763f41e5 DS |
482 | if (_ltt_trace_find(trace_name)) { /* Trace already allocated */ |
483 | err = 1; | |
484 | goto traces_error; | |
485 | } | |
486 | ||
9dad1eb8 PMF |
487 | trace = _ltt_trace_find_setup(trace_name); |
488 | if (!trace) { | |
c1f20530 | 489 | ERR("Trace not found %s", trace_name); |
9dad1eb8 PMF |
490 | err = -ENOENT; |
491 | goto traces_error; | |
492 | } | |
493 | ||
205f7ca7 DG |
494 | urcu_ref_init(&trace->urcu_ref); |
495 | urcu_ref_init(&trace->ltt_transport_urcu_ref); | |
9dad1eb8 | 496 | trace->active = 0; |
9dad1eb8 PMF |
497 | trace->freq_scale = trace_clock_freq_scale(); |
498 | ||
499 | if (!trace->transport) { | |
c1f20530 | 500 | ERR("Transport is not set"); |
9dad1eb8 PMF |
501 | err = -EINVAL; |
502 | goto transport_error; | |
503 | } | |
9dad1eb8 PMF |
504 | trace->ops = &trace->transport->ops; |
505 | ||
9dad1eb8 PMF |
506 | trace->start_freq = trace_clock_frequency(); |
507 | trace->start_tsc = trace_clock_read64(); | |
204141ee | 508 | gettimeofday(&trace->start_time, NULL); //ust// changed /* FIXME: is this ok? */ |
9dad1eb8 PMF |
509 | |
510 | for (chan = 0; chan < trace->nr_channels; chan++) { | |
511 | if (!(trace->channels[chan].active)) | |
512 | continue; | |
513 | ||
514 | channel_name = ltt_channels_get_name_from_index(chan); | |
515 | WARN_ON(!channel_name); | |
516 | subbuf_size = trace->channels[chan].subbuf_size; | |
517 | subbuf_cnt = trace->channels[chan].subbuf_cnt; | |
518 | prepare_chan_size_num(&subbuf_size, &subbuf_cnt); | |
519 | err = trace->ops->create_channel(trace_name, trace, | |
9dad1eb8 PMF |
520 | channel_name, |
521 | &trace->channels[chan], | |
522 | subbuf_size, | |
523 | subbuf_cnt, | |
524 | trace->channels[chan].overwrite); | |
525 | if (err != 0) { | |
c1f20530 | 526 | ERR("Cannot create channel %s", channel_name); |
9dad1eb8 PMF |
527 | goto create_channel_error; |
528 | } | |
529 | } | |
530 | ||
0222e121 | 531 | cds_list_del(&trace->list); |
0222e121 | 532 | cds_list_add_rcu(&trace->list, <t_traces.head); |
9dad1eb8 PMF |
533 | |
534 | ltt_unlock_traces(); | |
535 | ||
536 | return 0; | |
537 | ||
538 | create_channel_error: | |
539 | for (chan--; chan >= 0; chan--) | |
540 | if (trace->channels[chan].active) | |
541 | trace->ops->remove_channel(&trace->channels[chan]); | |
542 | ||
9dad1eb8 | 543 | transport_error: |
9dad1eb8 PMF |
544 | traces_error: |
545 | ltt_unlock_traces(); | |
546 | return err; | |
547 | } | |
9dad1eb8 | 548 | |
9dad1eb8 | 549 | /* Must be called while sure that trace is in the list. */ |
b73a4c47 | 550 | static int _ltt_trace_destroy(struct ust_trace *trace) |
9dad1eb8 PMF |
551 | { |
552 | int err = -EPERM; | |
553 | ||
554 | if (trace == NULL) { | |
555 | err = -ENOENT; | |
556 | goto traces_error; | |
557 | } | |
558 | if (trace->active) { | |
c1f20530 | 559 | ERR("Can't destroy trace %s : tracer is active", trace->trace_name); |
9dad1eb8 PMF |
560 | err = -EBUSY; |
561 | goto active_error; | |
562 | } | |
841f7e9c | 563 | |
0222e121 | 564 | cds_list_del_rcu(&trace->list); |
a3272941 | 565 | synchronize_rcu(); |
841f7e9c | 566 | |
9dad1eb8 PMF |
567 | return 0; |
568 | ||
9dad1eb8 PMF |
569 | active_error: |
570 | traces_error: | |
571 | return err; | |
572 | } | |
573 | ||
574 | /* Sleepable part of the destroy */ | |
31d392f1 | 575 | static void __ltt_trace_destroy(struct ust_trace *trace, int drop) |
9dad1eb8 PMF |
576 | { |
577 | int i; | |
b5b073e2 | 578 | struct ust_channel *chan; |
9dad1eb8 | 579 | |
31d392f1 PMF |
580 | if(!drop) { |
581 | for (i = 0; i < trace->nr_channels; i++) { | |
582 | chan = &trace->channels[i]; | |
583 | if (chan->active) | |
584 | trace->ops->finish_channel(chan); | |
585 | } | |
9dad1eb8 PMF |
586 | } |
587 | ||
9dad1eb8 PMF |
588 | /* |
589 | * The currently destroyed trace is not in the trace list anymore, | |
590 | * so it's safe to call the async wakeup ourself. It will deliver | |
591 | * the last subbuffers. | |
592 | */ | |
593 | trace_async_wakeup(trace); | |
594 | ||
595 | for (i = 0; i < trace->nr_channels; i++) { | |
596 | chan = &trace->channels[i]; | |
597 | if (chan->active) | |
598 | trace->ops->remove_channel(chan); | |
599 | } | |
600 | ||
205f7ca7 | 601 | urcu_ref_put(&trace->ltt_transport_urcu_ref, ltt_release_transport); |
9dad1eb8 | 602 | |
205f7ca7 | 603 | urcu_ref_put(&trace->urcu_ref, ltt_release_trace); |
9dad1eb8 PMF |
604 | } |
605 | ||
31d392f1 | 606 | int ltt_trace_destroy(const char *trace_name, int drop) |
9dad1eb8 PMF |
607 | { |
608 | int err = 0; | |
b73a4c47 | 609 | struct ust_trace *trace; |
9dad1eb8 PMF |
610 | |
611 | ltt_lock_traces(); | |
612 | ||
613 | trace = _ltt_trace_find(trace_name); | |
614 | if (trace) { | |
615 | err = _ltt_trace_destroy(trace); | |
616 | if (err) | |
617 | goto error; | |
618 | ||
619 | ltt_unlock_traces(); | |
620 | ||
31d392f1 | 621 | __ltt_trace_destroy(trace, drop); |
9dad1eb8 PMF |
622 | |
623 | return 0; | |
624 | } | |
625 | ||
626 | trace = _ltt_trace_find_setup(trace_name); | |
627 | if (trace) { | |
628 | _ltt_trace_free(trace); | |
629 | ltt_unlock_traces(); | |
630 | return 0; | |
631 | } | |
632 | ||
633 | err = -ENOENT; | |
634 | ||
9dad1eb8 PMF |
635 | error: |
636 | ltt_unlock_traces(); | |
637 | return err; | |
638 | } | |
9dad1eb8 PMF |
639 | |
640 | /* must be called from within a traces lock. */ | |
b73a4c47 | 641 | static int _ltt_trace_start(struct ust_trace *trace) |
9dad1eb8 PMF |
642 | { |
643 | int err = 0; | |
644 | ||
645 | if (trace == NULL) { | |
646 | err = -ENOENT; | |
647 | goto traces_error; | |
648 | } | |
649 | if (trace->active) | |
c1f20530 | 650 | DBG("Tracing already active for trace %s", trace->trace_name); |
9dad1eb8 PMF |
651 | trace->active = 1; |
652 | /* Read by trace points without protection : be careful */ | |
653 | ltt_traces.num_active_traces++; | |
654 | return err; | |
655 | ||
9dad1eb8 PMF |
656 | traces_error: |
657 | return err; | |
658 | } | |
659 | ||
660 | int ltt_trace_start(const char *trace_name) | |
661 | { | |
662 | int err = 0; | |
b73a4c47 | 663 | struct ust_trace *trace; |
9dad1eb8 PMF |
664 | |
665 | ltt_lock_traces(); | |
666 | ||
667 | trace = _ltt_trace_find(trace_name); | |
668 | err = _ltt_trace_start(trace); | |
669 | if (err) | |
670 | goto no_trace; | |
671 | ||
672 | ltt_unlock_traces(); | |
673 | ||
674 | /* | |
d558d653 | 675 | * Call the process-wide state dump. |
9dad1eb8 PMF |
676 | * Notice that there is no protection on the trace : that's exactly |
677 | * why we iterate on the list and check for trace equality instead of | |
d558d653 MD |
678 | * directly using this trace handle inside the logging function: we want |
679 | * to record events only in a single trace in the trace session list. | |
9dad1eb8 PMF |
680 | */ |
681 | ||
9c67dc50 | 682 | ltt_dump_marker_state(trace); |
9dad1eb8 | 683 | |
9dad1eb8 PMF |
684 | return err; |
685 | ||
686 | /* Error handling */ | |
687 | no_trace: | |
688 | ltt_unlock_traces(); | |
689 | return err; | |
690 | } | |
9dad1eb8 PMF |
691 | |
692 | /* must be called from within traces lock */ | |
b73a4c47 | 693 | static int _ltt_trace_stop(struct ust_trace *trace) |
9dad1eb8 PMF |
694 | { |
695 | int err = -EPERM; | |
696 | ||
697 | if (trace == NULL) { | |
698 | err = -ENOENT; | |
699 | goto traces_error; | |
700 | } | |
701 | if (!trace->active) | |
c1f20530 | 702 | DBG("LTT : Tracing not active for trace %s", trace->trace_name); |
9dad1eb8 PMF |
703 | if (trace->active) { |
704 | trace->active = 0; | |
705 | ltt_traces.num_active_traces--; | |
9dad1eb8 | 706 | } |
9dad1eb8 PMF |
707 | return 0; |
708 | ||
9dad1eb8 PMF |
709 | traces_error: |
710 | return err; | |
711 | } | |
712 | ||
713 | int ltt_trace_stop(const char *trace_name) | |
714 | { | |
715 | int err = 0; | |
b73a4c47 | 716 | struct ust_trace *trace; |
9dad1eb8 PMF |
717 | |
718 | ltt_lock_traces(); | |
719 | trace = _ltt_trace_find(trace_name); | |
720 | err = _ltt_trace_stop(trace); | |
721 | ltt_unlock_traces(); | |
722 | return err; | |
723 | } |