blob: ac6830d8292b221f9676f5d3b15b0efdf9658642 [file] [log] [blame]
Steven Rostedt520509432009-08-17 16:18:05 +02001/*
2 * Copyright (C) 2008,2009, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
Arnaldo Carvalho de Meloc168fbf2011-11-16 12:55:59 -020021#include <ctype.h>
22#include "util.h"
Steven Rostedt520509432009-08-17 16:18:05 +020023#include <dirent.h>
Ulrich Drepper659d8cf2009-12-19 16:40:28 -050024#include <mntent.h>
Steven Rostedt520509432009-08-17 16:18:05 +020025#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <stdarg.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <sys/wait.h>
32#include <pthread.h>
33#include <fcntl.h>
34#include <unistd.h>
Steven Rostedt520509432009-08-17 16:18:05 +020035#include <errno.h>
Frederic Weisbecker1ef2ed12009-08-28 03:09:58 +020036#include <stdbool.h>
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -020037#include <linux/list.h>
Arnaldo Carvalho de Meloe2561362009-11-21 14:31:26 -020038#include <linux/kernel.h>
Steven Rostedt520509432009-08-17 16:18:05 +020039
Frederic Weisbecker1ef2ed12009-08-28 03:09:58 +020040#include "../perf.h"
Steven Rostedt520509432009-08-17 16:18:05 +020041#include "trace-event.h"
Xiao Guangrong61be3e52009-12-28 16:48:30 +080042#include "debugfs.h"
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -020043#include "evsel.h"
Steven Rostedt520509432009-08-17 16:18:05 +020044
Steven Rostedt520509432009-08-17 16:18:05 +020045#define VERSION "0.5"
46
Steven Rostedt520509432009-08-17 16:18:05 +020047#define TRACE_CTRL "tracing_on"
48#define TRACE "trace"
49#define AVAILABLE "available_tracers"
50#define CURRENT "current_tracer"
51#define ITER_CTRL "trace_options"
52#define MAX_LATENCY "tracing_max_latency"
53
54unsigned int page_size;
55
56static const char *output_file = "trace.info";
57static int output_fd;
58
59struct event_list {
60 struct event_list *next;
61 const char *event;
62};
63
64struct events {
65 struct events *sibling;
66 struct events *children;
67 struct events *next;
68 char *name;
69};
70
71
Steven Rostedt520509432009-08-17 16:18:05 +020072void *malloc_or_die(unsigned int size)
73{
74 void *data;
75
76 data = malloc(size);
77 if (!data)
78 die("malloc");
79 return data;
80}
81
82static const char *find_debugfs(void)
83{
Xiao Guangrong61be3e52009-12-28 16:48:30 +080084 const char *path = debugfs_mount(NULL);
Steven Rostedt520509432009-08-17 16:18:05 +020085
Xiao Guangrong61be3e52009-12-28 16:48:30 +080086 if (!path)
87 die("Your kernel not support debugfs filesystem");
Steven Rostedt520509432009-08-17 16:18:05 +020088
Xiao Guangrong61be3e52009-12-28 16:48:30 +080089 return path;
Steven Rostedt520509432009-08-17 16:18:05 +020090}
91
92/*
93 * Finds the path to the debugfs/tracing
94 * Allocates the string and stores it.
95 */
96static const char *find_tracing_dir(void)
97{
98 static char *tracing;
99 static int tracing_found;
100 const char *debugfs;
101
102 if (tracing_found)
103 return tracing;
104
105 debugfs = find_debugfs();
106
107 tracing = malloc_or_die(strlen(debugfs) + 9);
108
109 sprintf(tracing, "%s/tracing", debugfs);
110
111 tracing_found = 1;
112 return tracing;
113}
114
115static char *get_tracing_file(const char *name)
116{
117 const char *tracing;
118 char *file;
119
120 tracing = find_tracing_dir();
121 if (!tracing)
122 return NULL;
123
124 file = malloc_or_die(strlen(tracing) + strlen(name) + 2);
125
126 sprintf(file, "%s/%s", tracing, name);
127 return file;
128}
129
130static void put_tracing_file(char *file)
131{
132 free(file);
133}
134
Tom Zanussi92155452010-04-01 23:59:21 -0500135static ssize_t calc_data_size;
136
Steven Rostedt520509432009-08-17 16:18:05 +0200137static ssize_t write_or_die(const void *buf, size_t len)
138{
139 int ret;
140
Tom Zanussi92155452010-04-01 23:59:21 -0500141 if (calc_data_size) {
142 calc_data_size += len;
143 return len;
144 }
145
Steven Rostedt520509432009-08-17 16:18:05 +0200146 ret = write(output_fd, buf, len);
147 if (ret < 0)
148 die("writing to '%s'", output_file);
149
150 return ret;
151}
152
153int bigendian(void)
154{
155 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
156 unsigned int *ptr;
157
Ingo Molnar65014ab2009-09-02 14:55:55 +0200158 ptr = (unsigned int *)(void *)str;
Steven Rostedt520509432009-08-17 16:18:05 +0200159 return *ptr == 0x01020304;
160}
161
Sonny Rao259032b2011-07-14 13:34:43 +1000162/* unfortunately, you can not stat debugfs or proc files for size */
163static void record_file(const char *file, size_t hdr_sz)
Steven Rostedt520509432009-08-17 16:18:05 +0200164{
165 unsigned long long size = 0;
Sonny Rao259032b2011-07-14 13:34:43 +1000166 char buf[BUFSIZ], *sizep;
167 off_t hdr_pos = lseek(output_fd, 0, SEEK_CUR);
168 int r, fd;
169
170 fd = open(file, O_RDONLY);
171 if (fd < 0)
172 die("Can't read '%s'", file);
173
174 /* put in zeros for file size, then fill true size later */
Jiri Olsa29208e52011-10-20 15:59:43 +0200175 if (hdr_sz)
176 write_or_die(&size, hdr_sz);
Steven Rostedt520509432009-08-17 16:18:05 +0200177
178 do {
179 r = read(fd, buf, BUFSIZ);
180 if (r > 0) {
181 size += r;
182 write_or_die(buf, r);
183 }
184 } while (r > 0);
Steven Rostedt520509432009-08-17 16:18:05 +0200185 close(fd);
186
Sonny Rao259032b2011-07-14 13:34:43 +1000187 /* ugh, handle big-endian hdr_size == 4 */
188 sizep = (char*)&size;
189 if (bigendian())
190 sizep += sizeof(u64) - hdr_sz;
Steven Rostedt520509432009-08-17 16:18:05 +0200191
Jiri Olsa29208e52011-10-20 15:59:43 +0200192 if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0)
Sonny Rao259032b2011-07-14 13:34:43 +1000193 die("writing to %s", output_file);
Steven Rostedt520509432009-08-17 16:18:05 +0200194}
195
196static void read_header_files(void)
197{
Steven Rostedt520509432009-08-17 16:18:05 +0200198 char *path;
Sonny Rao259032b2011-07-14 13:34:43 +1000199 struct stat st;
Steven Rostedt520509432009-08-17 16:18:05 +0200200
201 path = get_tracing_file("events/header_page");
Sonny Rao259032b2011-07-14 13:34:43 +1000202 if (stat(path, &st) < 0)
Steven Rostedt520509432009-08-17 16:18:05 +0200203 die("can't read '%s'", path);
204
Steven Rostedt520509432009-08-17 16:18:05 +0200205 write_or_die("header_page", 12);
Sonny Rao259032b2011-07-14 13:34:43 +1000206 record_file(path, 8);
Steven Rostedt520509432009-08-17 16:18:05 +0200207 put_tracing_file(path);
208
209 path = get_tracing_file("events/header_event");
Sonny Rao259032b2011-07-14 13:34:43 +1000210 if (stat(path, &st) < 0)
Steven Rostedt520509432009-08-17 16:18:05 +0200211 die("can't read '%s'", path);
212
Steven Rostedt520509432009-08-17 16:18:05 +0200213 write_or_die("header_event", 13);
Sonny Rao259032b2011-07-14 13:34:43 +1000214 record_file(path, 8);
Steven Rostedt520509432009-08-17 16:18:05 +0200215 put_tracing_file(path);
216}
217
Frederic Weisbecker1ef2ed12009-08-28 03:09:58 +0200218static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
219{
220 while (tps) {
221 if (!strcmp(sys, tps->name))
222 return true;
223 tps = tps->next;
224 }
225
226 return false;
227}
228
229static void copy_event_system(const char *sys, struct tracepoint_path *tps)
Steven Rostedt520509432009-08-17 16:18:05 +0200230{
Steven Rostedt520509432009-08-17 16:18:05 +0200231 struct dirent *dent;
232 struct stat st;
233 char *format;
234 DIR *dir;
235 int count = 0;
236 int ret;
237
238 dir = opendir(sys);
239 if (!dir)
240 die("can't read directory '%s'", sys);
241
242 while ((dent = readdir(dir))) {
Ulrich Drepper659d8cf2009-12-19 16:40:28 -0500243 if (dent->d_type != DT_DIR ||
244 strcmp(dent->d_name, ".") == 0 ||
Frederic Weisbecker1ef2ed12009-08-28 03:09:58 +0200245 strcmp(dent->d_name, "..") == 0 ||
246 !name_in_tp_list(dent->d_name, tps))
Steven Rostedt520509432009-08-17 16:18:05 +0200247 continue;
248 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
249 sprintf(format, "%s/%s/format", sys, dent->d_name);
250 ret = stat(format, &st);
251 free(format);
252 if (ret < 0)
253 continue;
254 count++;
255 }
256
257 write_or_die(&count, 4);
258
259 rewinddir(dir);
260 while ((dent = readdir(dir))) {
Ulrich Drepper659d8cf2009-12-19 16:40:28 -0500261 if (dent->d_type != DT_DIR ||
262 strcmp(dent->d_name, ".") == 0 ||
Frederic Weisbecker1ef2ed12009-08-28 03:09:58 +0200263 strcmp(dent->d_name, "..") == 0 ||
264 !name_in_tp_list(dent->d_name, tps))
Steven Rostedt520509432009-08-17 16:18:05 +0200265 continue;
266 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
267 sprintf(format, "%s/%s/format", sys, dent->d_name);
268 ret = stat(format, &st);
269
Sonny Rao259032b2011-07-14 13:34:43 +1000270 if (ret >= 0)
271 record_file(format, 8);
Steven Rostedt520509432009-08-17 16:18:05 +0200272
273 free(format);
274 }
Xiao Guangrong99674112009-12-28 16:49:38 +0800275 closedir(dir);
Steven Rostedt520509432009-08-17 16:18:05 +0200276}
277
Frederic Weisbecker1ef2ed12009-08-28 03:09:58 +0200278static void read_ftrace_files(struct tracepoint_path *tps)
Steven Rostedt520509432009-08-17 16:18:05 +0200279{
280 char *path;
281
282 path = get_tracing_file("events/ftrace");
283
Frederic Weisbecker1ef2ed12009-08-28 03:09:58 +0200284 copy_event_system(path, tps);
Steven Rostedt520509432009-08-17 16:18:05 +0200285
286 put_tracing_file(path);
287}
288
Frederic Weisbecker1ef2ed12009-08-28 03:09:58 +0200289static bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
290{
291 while (tps) {
292 if (!strcmp(sys, tps->system))
293 return true;
294 tps = tps->next;
295 }
296
297 return false;
298}
299
300static void read_event_files(struct tracepoint_path *tps)
Steven Rostedt520509432009-08-17 16:18:05 +0200301{
302 struct dirent *dent;
303 struct stat st;
304 char *path;
305 char *sys;
306 DIR *dir;
307 int count = 0;
308 int ret;
309
310 path = get_tracing_file("events");
311
312 dir = opendir(path);
313 if (!dir)
314 die("can't read directory '%s'", path);
315
316 while ((dent = readdir(dir))) {
Ulrich Drepper659d8cf2009-12-19 16:40:28 -0500317 if (dent->d_type != DT_DIR ||
318 strcmp(dent->d_name, ".") == 0 ||
Steven Rostedt520509432009-08-17 16:18:05 +0200319 strcmp(dent->d_name, "..") == 0 ||
Frederic Weisbecker1ef2ed12009-08-28 03:09:58 +0200320 strcmp(dent->d_name, "ftrace") == 0 ||
321 !system_in_tp_list(dent->d_name, tps))
Steven Rostedt520509432009-08-17 16:18:05 +0200322 continue;
Ulrich Drepper659d8cf2009-12-19 16:40:28 -0500323 count++;
Steven Rostedt520509432009-08-17 16:18:05 +0200324 }
325
326 write_or_die(&count, 4);
327
328 rewinddir(dir);
329 while ((dent = readdir(dir))) {
Ulrich Drepper659d8cf2009-12-19 16:40:28 -0500330 if (dent->d_type != DT_DIR ||
331 strcmp(dent->d_name, ".") == 0 ||
Steven Rostedt520509432009-08-17 16:18:05 +0200332 strcmp(dent->d_name, "..") == 0 ||
Frederic Weisbecker1ef2ed12009-08-28 03:09:58 +0200333 strcmp(dent->d_name, "ftrace") == 0 ||
334 !system_in_tp_list(dent->d_name, tps))
Steven Rostedt520509432009-08-17 16:18:05 +0200335 continue;
336 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
337 sprintf(sys, "%s/%s", path, dent->d_name);
338 ret = stat(sys, &st);
339 if (ret >= 0) {
Ulrich Drepper659d8cf2009-12-19 16:40:28 -0500340 write_or_die(dent->d_name, strlen(dent->d_name) + 1);
341 copy_event_system(sys, tps);
Steven Rostedt520509432009-08-17 16:18:05 +0200342 }
343 free(sys);
344 }
345
Xiao Guangrong99674112009-12-28 16:49:38 +0800346 closedir(dir);
Steven Rostedt520509432009-08-17 16:18:05 +0200347 put_tracing_file(path);
348}
349
350static void read_proc_kallsyms(void)
351{
Sonny Rao259032b2011-07-14 13:34:43 +1000352 unsigned int size;
Steven Rostedt520509432009-08-17 16:18:05 +0200353 const char *path = "/proc/kallsyms";
354 struct stat st;
355 int ret;
356
357 ret = stat(path, &st);
358 if (ret < 0) {
359 /* not found */
360 size = 0;
361 write_or_die(&size, 4);
362 return;
363 }
Sonny Rao259032b2011-07-14 13:34:43 +1000364 record_file(path, 4);
Steven Rostedt520509432009-08-17 16:18:05 +0200365}
366
367static void read_ftrace_printk(void)
368{
Sonny Rao259032b2011-07-14 13:34:43 +1000369 unsigned int size;
Li Zefan6706ccf2009-09-17 16:34:23 +0800370 char *path;
Steven Rostedt520509432009-08-17 16:18:05 +0200371 struct stat st;
372 int ret;
373
374 path = get_tracing_file("printk_formats");
375 ret = stat(path, &st);
376 if (ret < 0) {
377 /* not found */
378 size = 0;
379 write_or_die(&size, 4);
Li Zefan6706ccf2009-09-17 16:34:23 +0800380 goto out;
Steven Rostedt520509432009-08-17 16:18:05 +0200381 }
Sonny Rao259032b2011-07-14 13:34:43 +1000382 record_file(path, 4);
383
Li Zefan6706ccf2009-09-17 16:34:23 +0800384out:
385 put_tracing_file(path);
Steven Rostedt520509432009-08-17 16:18:05 +0200386}
387
Frederic Weisbecker1ef2ed12009-08-28 03:09:58 +0200388static struct tracepoint_path *
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -0200389get_tracepoints_path(struct list_head *pattrs)
Frederic Weisbecker1ef2ed12009-08-28 03:09:58 +0200390{
391 struct tracepoint_path path, *ppath = &path;
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -0200392 struct perf_evsel *pos;
393 int nr_tracepoints = 0;
Frederic Weisbecker1ef2ed12009-08-28 03:09:58 +0200394
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -0200395 list_for_each_entry(pos, pattrs, node) {
396 if (pos->attr.type != PERF_TYPE_TRACEPOINT)
Frederic Weisbecker1ef2ed12009-08-28 03:09:58 +0200397 continue;
Arnaldo Carvalho de Meloe2561362009-11-21 14:31:26 -0200398 ++nr_tracepoints;
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -0200399 ppath->next = tracepoint_id_to_path(pos->attr.config);
Frederic Weisbecker1ef2ed12009-08-28 03:09:58 +0200400 if (!ppath->next)
401 die("%s\n", "No memory to alloc tracepoints list");
402 ppath = ppath->next;
403 }
404
Arnaldo Carvalho de Meloe2561362009-11-21 14:31:26 -0200405 return nr_tracepoints > 0 ? path.next : NULL;
Frederic Weisbecker1ef2ed12009-08-28 03:09:58 +0200406}
Arnaldo Carvalho de Meloe2561362009-11-21 14:31:26 -0200407
Jiri Olsa29208e52011-10-20 15:59:43 +0200408static void
409put_tracepoints_path(struct tracepoint_path *tps)
410{
411 while (tps) {
412 struct tracepoint_path *t = tps;
413
414 tps = tps->next;
415 free(t->name);
416 free(t->system);
417 free(t);
418 }
419}
420
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -0200421bool have_tracepoints(struct list_head *pattrs)
Tom Zanussi63e0c772010-05-03 00:14:48 -0500422{
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -0200423 struct perf_evsel *pos;
Tom Zanussidb620b12010-05-04 22:20:16 -0500424
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -0200425 list_for_each_entry(pos, pattrs, node)
426 if (pos->attr.type == PERF_TYPE_TRACEPOINT)
Tom Zanussidb620b12010-05-04 22:20:16 -0500427 return true;
428
429 return false;
Tom Zanussi63e0c772010-05-03 00:14:48 -0500430}
431
Jiri Olsa29208e52011-10-20 15:59:43 +0200432static void tracing_data_header(void)
Steven Rostedt520509432009-08-17 16:18:05 +0200433{
Jiri Olsa29208e52011-10-20 15:59:43 +0200434 char buf[20];
Arnaldo Carvalho de Meloe2561362009-11-21 14:31:26 -0200435
Jiri Olsa29208e52011-10-20 15:59:43 +0200436 /* just guessing this is someone's birthday.. ;) */
Steven Rostedt520509432009-08-17 16:18:05 +0200437 buf[0] = 23;
438 buf[1] = 8;
439 buf[2] = 68;
440 memcpy(buf + 3, "tracing", 7);
441
442 write_or_die(buf, 10);
443
444 write_or_die(VERSION, strlen(VERSION) + 1);
445
446 /* save endian */
447 if (bigendian())
448 buf[0] = 1;
449 else
450 buf[0] = 0;
451
452 write_or_die(buf, 1);
453
454 /* save size of long */
455 buf[0] = sizeof(long);
456 write_or_die(buf, 1);
457
458 /* save page_size */
Arnaldo Carvalho de Melo1b759622010-01-14 18:30:04 -0200459 page_size = sysconf(_SC_PAGESIZE);
Steven Rostedt520509432009-08-17 16:18:05 +0200460 write_or_die(&page_size, 4);
Jiri Olsa29208e52011-10-20 15:59:43 +0200461}
Steven Rostedt520509432009-08-17 16:18:05 +0200462
Jiri Olsa29208e52011-10-20 15:59:43 +0200463struct tracing_data *tracing_data_get(struct list_head *pattrs,
464 int fd, bool temp)
465{
466 struct tracepoint_path *tps;
467 struct tracing_data *tdata;
468
469 output_fd = fd;
470
471 tps = get_tracepoints_path(pattrs);
472 if (!tps)
473 return NULL;
474
475 tdata = malloc_or_die(sizeof(*tdata));
476 tdata->temp = temp;
477 tdata->size = 0;
478
479 if (temp) {
480 int temp_fd;
481
482 snprintf(tdata->temp_file, sizeof(tdata->temp_file),
483 "/tmp/perf-XXXXXX");
484 if (!mkstemp(tdata->temp_file))
485 die("Can't make temp file");
486
487 temp_fd = open(tdata->temp_file, O_RDWR);
488 if (temp_fd < 0)
489 die("Can't read '%s'", tdata->temp_file);
490
491 /*
492 * Set the temp file the default output, so all the
493 * tracing data are stored into it.
494 */
495 output_fd = temp_fd;
496 }
497
498 tracing_data_header();
Steven Rostedt520509432009-08-17 16:18:05 +0200499 read_header_files();
Frederic Weisbecker1ef2ed12009-08-28 03:09:58 +0200500 read_ftrace_files(tps);
501 read_event_files(tps);
Steven Rostedt520509432009-08-17 16:18:05 +0200502 read_proc_kallsyms();
503 read_ftrace_printk();
Arnaldo Carvalho de Meloe2561362009-11-21 14:31:26 -0200504
Jiri Olsa29208e52011-10-20 15:59:43 +0200505 /*
506 * All tracing data are stored by now, we can restore
507 * the default output file in case we used temp file.
508 */
509 if (temp) {
510 tdata->size = lseek(output_fd, 0, SEEK_CUR);
511 close(output_fd);
512 output_fd = fd;
513 }
514
515 put_tracepoints_path(tps);
516 return tdata;
Steven Rostedt520509432009-08-17 16:18:05 +0200517}
Tom Zanussi92155452010-04-01 23:59:21 -0500518
Jiri Olsa29208e52011-10-20 15:59:43 +0200519void tracing_data_put(struct tracing_data *tdata)
Tom Zanussi92155452010-04-01 23:59:21 -0500520{
Jiri Olsa29208e52011-10-20 15:59:43 +0200521 if (tdata->temp) {
522 record_file(tdata->temp_file, 0);
523 unlink(tdata->temp_file);
524 }
Tom Zanussi92155452010-04-01 23:59:21 -0500525
Jiri Olsa29208e52011-10-20 15:59:43 +0200526 free(tdata);
527}
Tom Zanussi92155452010-04-01 23:59:21 -0500528
Jiri Olsa29208e52011-10-20 15:59:43 +0200529int read_tracing_data(int fd, struct list_head *pattrs)
530{
531 struct tracing_data *tdata;
Tom Zanussi92155452010-04-01 23:59:21 -0500532
Jiri Olsa29208e52011-10-20 15:59:43 +0200533 /*
534 * We work over the real file, so we can write data
535 * directly, no temp file is needed.
536 */
537 tdata = tracing_data_get(pattrs, fd, false);
538 if (!tdata)
539 return -ENOMEM;
540
541 tracing_data_put(tdata);
542 return 0;
Tom Zanussi92155452010-04-01 23:59:21 -0500543}