]>
Commit | Line | Data |
---|---|---|
52050943 SR |
1 | /* |
2 | * Copyright (C) 2008,2009, Steven Rostedt <[email protected]> | |
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 | */ | |
c168fbfb | 21 | #include "util.h" |
52050943 | 22 | #include <dirent.h> |
659d8cfb | 23 | #include <mntent.h> |
52050943 SR |
24 | #include <stdio.h> |
25 | #include <stdlib.h> | |
26 | #include <string.h> | |
27 | #include <stdarg.h> | |
28 | #include <sys/types.h> | |
29 | #include <sys/stat.h> | |
30 | #include <sys/wait.h> | |
31 | #include <pthread.h> | |
32 | #include <fcntl.h> | |
33 | #include <unistd.h> | |
52050943 | 34 | #include <errno.h> |
1ef2ed10 | 35 | #include <stdbool.h> |
69aad6f1 | 36 | #include <linux/list.h> |
e2561368 | 37 | #include <linux/kernel.h> |
52050943 | 38 | |
1ef2ed10 | 39 | #include "../perf.h" |
52050943 | 40 | #include "trace-event.h" |
553873e1 | 41 | #include <api/fs/debugfs.h> |
69aad6f1 | 42 | #include "evsel.h" |
52050943 | 43 | |
52050943 SR |
44 | #define VERSION "0.5" |
45 | ||
52050943 SR |
46 | static int output_fd; |
47 | ||
52050943 | 48 | |
52050943 SR |
49 | int bigendian(void) |
50 | { | |
51 | unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0}; | |
52 | unsigned int *ptr; | |
53 | ||
65014ab3 | 54 | ptr = (unsigned int *)(void *)str; |
52050943 SR |
55 | return *ptr == 0x01020304; |
56 | } | |
57 | ||
259032bf | 58 | /* unfortunately, you can not stat debugfs or proc files for size */ |
8755d5e2 | 59 | static int record_file(const char *file, ssize_t hdr_sz) |
52050943 SR |
60 | { |
61 | unsigned long long size = 0; | |
259032bf SR |
62 | char buf[BUFSIZ], *sizep; |
63 | off_t hdr_pos = lseek(output_fd, 0, SEEK_CUR); | |
64 | int r, fd; | |
8755d5e2 | 65 | int err = -EIO; |
52050943 SR |
66 | |
67 | fd = open(file, O_RDONLY); | |
7f42b950 NK |
68 | if (fd < 0) { |
69 | pr_debug("Can't read '%s'", file); | |
70 | return -errno; | |
71 | } | |
52050943 | 72 | |
259032bf | 73 | /* put in zeros for file size, then fill true size later */ |
8755d5e2 NK |
74 | if (hdr_sz) { |
75 | if (write(output_fd, &size, hdr_sz) != hdr_sz) | |
76 | goto out; | |
77 | } | |
52050943 SR |
78 | |
79 | do { | |
80 | r = read(fd, buf, BUFSIZ); | |
259032bf | 81 | if (r > 0) { |
52050943 | 82 | size += r; |
8755d5e2 NK |
83 | if (write(output_fd, buf, r) != r) |
84 | goto out; | |
259032bf | 85 | } |
52050943 | 86 | } while (r > 0); |
52050943 | 87 | |
259032bf SR |
88 | /* ugh, handle big-endian hdr_size == 4 */ |
89 | sizep = (char*)&size; | |
90 | if (bigendian()) | |
91 | sizep += sizeof(u64) - hdr_sz; | |
92 | ||
7f42b950 NK |
93 | if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) { |
94 | pr_debug("writing file size failed\n"); | |
95 | goto out; | |
96 | } | |
8755d5e2 NK |
97 | |
98 | err = 0; | |
99 | out: | |
100 | close(fd); | |
101 | return err; | |
52050943 SR |
102 | } |
103 | ||
077f159d | 104 | static int record_header_files(void) |
52050943 | 105 | { |
52050943 | 106 | char *path; |
259032bf | 107 | struct stat st; |
8755d5e2 | 108 | int err = -EIO; |
52050943 SR |
109 | |
110 | path = get_tracing_file("events/header_page"); | |
7f42b950 NK |
111 | if (!path) { |
112 | pr_debug("can't get tracing/events/header_page"); | |
113 | return -ENOMEM; | |
114 | } | |
454f8c7d | 115 | |
7f42b950 NK |
116 | if (stat(path, &st) < 0) { |
117 | pr_debug("can't read '%s'", path); | |
118 | goto out; | |
119 | } | |
52050943 | 120 | |
8755d5e2 NK |
121 | if (write(output_fd, "header_page", 12) != 12) { |
122 | pr_debug("can't write header_page\n"); | |
123 | goto out; | |
124 | } | |
125 | ||
126 | if (record_file(path, 8) < 0) { | |
127 | pr_debug("can't record header_page file\n"); | |
128 | goto out; | |
129 | } | |
130 | ||
52050943 SR |
131 | put_tracing_file(path); |
132 | ||
133 | path = get_tracing_file("events/header_event"); | |
7f42b950 NK |
134 | if (!path) { |
135 | pr_debug("can't get tracing/events/header_event"); | |
136 | err = -ENOMEM; | |
137 | goto out; | |
138 | } | |
454f8c7d | 139 | |
7f42b950 NK |
140 | if (stat(path, &st) < 0) { |
141 | pr_debug("can't read '%s'", path); | |
142 | goto out; | |
143 | } | |
52050943 | 144 | |
8755d5e2 NK |
145 | if (write(output_fd, "header_event", 13) != 13) { |
146 | pr_debug("can't write header_event\n"); | |
147 | goto out; | |
148 | } | |
149 | ||
150 | if (record_file(path, 8) < 0) { | |
151 | pr_debug("can't record header_event file\n"); | |
152 | goto out; | |
153 | } | |
154 | ||
155 | err = 0; | |
156 | out: | |
52050943 | 157 | put_tracing_file(path); |
8755d5e2 | 158 | return err; |
52050943 SR |
159 | } |
160 | ||
1ef2ed10 FW |
161 | static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) |
162 | { | |
163 | while (tps) { | |
164 | if (!strcmp(sys, tps->name)) | |
165 | return true; | |
166 | tps = tps->next; | |
167 | } | |
168 | ||
169 | return false; | |
170 | } | |
171 | ||
5a6fd27a | 172 | static int copy_event_system(const char *sys, struct tracepoint_path *tps) |
52050943 | 173 | { |
52050943 SR |
174 | struct dirent *dent; |
175 | struct stat st; | |
176 | char *format; | |
177 | DIR *dir; | |
178 | int count = 0; | |
179 | int ret; | |
5a6fd27a | 180 | int err; |
52050943 SR |
181 | |
182 | dir = opendir(sys); | |
7f42b950 NK |
183 | if (!dir) { |
184 | pr_debug("can't read directory '%s'", sys); | |
185 | return -errno; | |
186 | } | |
52050943 SR |
187 | |
188 | while ((dent = readdir(dir))) { | |
659d8cfb UD |
189 | if (dent->d_type != DT_DIR || |
190 | strcmp(dent->d_name, ".") == 0 || | |
1ef2ed10 FW |
191 | strcmp(dent->d_name, "..") == 0 || |
192 | !name_in_tp_list(dent->d_name, tps)) | |
52050943 | 193 | continue; |
5a6fd27a NK |
194 | format = malloc(strlen(sys) + strlen(dent->d_name) + 10); |
195 | if (!format) { | |
196 | err = -ENOMEM; | |
197 | goto out; | |
198 | } | |
52050943 SR |
199 | sprintf(format, "%s/%s/format", sys, dent->d_name); |
200 | ret = stat(format, &st); | |
201 | free(format); | |
202 | if (ret < 0) | |
203 | continue; | |
204 | count++; | |
205 | } | |
206 | ||
8755d5e2 NK |
207 | if (write(output_fd, &count, 4) != 4) { |
208 | err = -EIO; | |
209 | pr_debug("can't write count\n"); | |
210 | goto out; | |
211 | } | |
52050943 SR |
212 | |
213 | rewinddir(dir); | |
214 | while ((dent = readdir(dir))) { | |
659d8cfb UD |
215 | if (dent->d_type != DT_DIR || |
216 | strcmp(dent->d_name, ".") == 0 || | |
1ef2ed10 FW |
217 | strcmp(dent->d_name, "..") == 0 || |
218 | !name_in_tp_list(dent->d_name, tps)) | |
52050943 | 219 | continue; |
5a6fd27a NK |
220 | format = malloc(strlen(sys) + strlen(dent->d_name) + 10); |
221 | if (!format) { | |
222 | err = -ENOMEM; | |
223 | goto out; | |
224 | } | |
52050943 SR |
225 | sprintf(format, "%s/%s/format", sys, dent->d_name); |
226 | ret = stat(format, &st); | |
227 | ||
8755d5e2 NK |
228 | if (ret >= 0) { |
229 | err = record_file(format, 8); | |
230 | if (err) { | |
231 | free(format); | |
232 | goto out; | |
233 | } | |
234 | } | |
52050943 SR |
235 | free(format); |
236 | } | |
5a6fd27a NK |
237 | err = 0; |
238 | out: | |
9967411e | 239 | closedir(dir); |
5a6fd27a | 240 | return err; |
52050943 SR |
241 | } |
242 | ||
077f159d | 243 | static int record_ftrace_files(struct tracepoint_path *tps) |
52050943 SR |
244 | { |
245 | char *path; | |
8755d5e2 | 246 | int ret; |
52050943 SR |
247 | |
248 | path = get_tracing_file("events/ftrace"); | |
7f42b950 NK |
249 | if (!path) { |
250 | pr_debug("can't get tracing/events/ftrace"); | |
251 | return -ENOMEM; | |
252 | } | |
52050943 | 253 | |
8755d5e2 | 254 | ret = copy_event_system(path, tps); |
52050943 SR |
255 | |
256 | put_tracing_file(path); | |
8755d5e2 NK |
257 | |
258 | return ret; | |
52050943 SR |
259 | } |
260 | ||
1ef2ed10 FW |
261 | static bool system_in_tp_list(char *sys, struct tracepoint_path *tps) |
262 | { | |
263 | while (tps) { | |
264 | if (!strcmp(sys, tps->system)) | |
265 | return true; | |
266 | tps = tps->next; | |
267 | } | |
268 | ||
269 | return false; | |
270 | } | |
271 | ||
077f159d | 272 | static int record_event_files(struct tracepoint_path *tps) |
52050943 SR |
273 | { |
274 | struct dirent *dent; | |
275 | struct stat st; | |
276 | char *path; | |
277 | char *sys; | |
278 | DIR *dir; | |
279 | int count = 0; | |
280 | int ret; | |
5a6fd27a | 281 | int err; |
52050943 SR |
282 | |
283 | path = get_tracing_file("events"); | |
7f42b950 NK |
284 | if (!path) { |
285 | pr_debug("can't get tracing/events"); | |
286 | return -ENOMEM; | |
287 | } | |
52050943 SR |
288 | |
289 | dir = opendir(path); | |
7f42b950 NK |
290 | if (!dir) { |
291 | err = -errno; | |
292 | pr_debug("can't read directory '%s'", path); | |
293 | goto out; | |
294 | } | |
52050943 SR |
295 | |
296 | while ((dent = readdir(dir))) { | |
659d8cfb UD |
297 | if (dent->d_type != DT_DIR || |
298 | strcmp(dent->d_name, ".") == 0 || | |
52050943 | 299 | strcmp(dent->d_name, "..") == 0 || |
1ef2ed10 FW |
300 | strcmp(dent->d_name, "ftrace") == 0 || |
301 | !system_in_tp_list(dent->d_name, tps)) | |
52050943 | 302 | continue; |
659d8cfb | 303 | count++; |
52050943 SR |
304 | } |
305 | ||
8755d5e2 NK |
306 | if (write(output_fd, &count, 4) != 4) { |
307 | err = -EIO; | |
308 | pr_debug("can't write count\n"); | |
309 | goto out; | |
310 | } | |
52050943 SR |
311 | |
312 | rewinddir(dir); | |
313 | while ((dent = readdir(dir))) { | |
659d8cfb UD |
314 | if (dent->d_type != DT_DIR || |
315 | strcmp(dent->d_name, ".") == 0 || | |
52050943 | 316 | strcmp(dent->d_name, "..") == 0 || |
1ef2ed10 FW |
317 | strcmp(dent->d_name, "ftrace") == 0 || |
318 | !system_in_tp_list(dent->d_name, tps)) | |
52050943 | 319 | continue; |
5a6fd27a NK |
320 | sys = malloc(strlen(path) + strlen(dent->d_name) + 2); |
321 | if (!sys) { | |
322 | err = -ENOMEM; | |
323 | goto out; | |
324 | } | |
52050943 SR |
325 | sprintf(sys, "%s/%s", path, dent->d_name); |
326 | ret = stat(sys, &st); | |
327 | if (ret >= 0) { | |
8755d5e2 NK |
328 | ssize_t size = strlen(dent->d_name) + 1; |
329 | ||
330 | if (write(output_fd, dent->d_name, size) != size || | |
331 | copy_event_system(sys, tps) < 0) { | |
332 | err = -EIO; | |
333 | free(sys); | |
334 | goto out; | |
335 | } | |
52050943 SR |
336 | } |
337 | free(sys); | |
338 | } | |
5a6fd27a NK |
339 | err = 0; |
340 | out: | |
9967411e | 341 | closedir(dir); |
52050943 | 342 | put_tracing_file(path); |
5a6fd27a NK |
343 | |
344 | return err; | |
52050943 SR |
345 | } |
346 | ||
077f159d | 347 | static int record_proc_kallsyms(void) |
52050943 | 348 | { |
259032bf | 349 | unsigned int size; |
52050943 SR |
350 | const char *path = "/proc/kallsyms"; |
351 | struct stat st; | |
8755d5e2 | 352 | int ret, err = 0; |
52050943 SR |
353 | |
354 | ret = stat(path, &st); | |
355 | if (ret < 0) { | |
356 | /* not found */ | |
357 | size = 0; | |
8755d5e2 NK |
358 | if (write(output_fd, &size, 4) != 4) |
359 | err = -EIO; | |
360 | return err; | |
52050943 | 361 | } |
8755d5e2 | 362 | return record_file(path, 4); |
52050943 SR |
363 | } |
364 | ||
077f159d | 365 | static int record_ftrace_printk(void) |
52050943 | 366 | { |
259032bf | 367 | unsigned int size; |
6706ccf8 | 368 | char *path; |
52050943 | 369 | struct stat st; |
8755d5e2 | 370 | int ret, err = 0; |
52050943 SR |
371 | |
372 | path = get_tracing_file("printk_formats"); | |
7f42b950 NK |
373 | if (!path) { |
374 | pr_debug("can't get tracing/printk_formats"); | |
375 | return -ENOMEM; | |
376 | } | |
454f8c7d | 377 | |
52050943 SR |
378 | ret = stat(path, &st); |
379 | if (ret < 0) { | |
380 | /* not found */ | |
381 | size = 0; | |
8755d5e2 NK |
382 | if (write(output_fd, &size, 4) != 4) |
383 | err = -EIO; | |
6706ccf8 | 384 | goto out; |
52050943 | 385 | } |
8755d5e2 | 386 | err = record_file(path, 4); |
259032bf | 387 | |
6706ccf8 LZ |
388 | out: |
389 | put_tracing_file(path); | |
8755d5e2 | 390 | return err; |
52050943 SR |
391 | } |
392 | ||
7f42b950 NK |
393 | static void |
394 | put_tracepoints_path(struct tracepoint_path *tps) | |
395 | { | |
396 | while (tps) { | |
397 | struct tracepoint_path *t = tps; | |
398 | ||
399 | tps = tps->next; | |
74cf249d ACM |
400 | zfree(&t->name); |
401 | zfree(&t->system); | |
7f42b950 NK |
402 | free(t); |
403 | } | |
404 | } | |
405 | ||
1ef2ed10 | 406 | static struct tracepoint_path * |
69aad6f1 | 407 | get_tracepoints_path(struct list_head *pattrs) |
1ef2ed10 FW |
408 | { |
409 | struct tracepoint_path path, *ppath = &path; | |
69aad6f1 ACM |
410 | struct perf_evsel *pos; |
411 | int nr_tracepoints = 0; | |
1ef2ed10 | 412 | |
69aad6f1 ACM |
413 | list_for_each_entry(pos, pattrs, node) { |
414 | if (pos->attr.type != PERF_TYPE_TRACEPOINT) | |
1ef2ed10 | 415 | continue; |
e2561368 | 416 | ++nr_tracepoints; |
e7c93f09 NK |
417 | |
418 | if (pos->name) { | |
419 | ppath->next = tracepoint_name_to_path(pos->name); | |
420 | if (ppath->next) | |
421 | goto next; | |
422 | ||
423 | if (strchr(pos->name, ':') == NULL) | |
424 | goto try_id; | |
425 | ||
426 | goto error; | |
427 | } | |
428 | ||
429 | try_id: | |
69aad6f1 | 430 | ppath->next = tracepoint_id_to_path(pos->attr.config); |
7f42b950 | 431 | if (!ppath->next) { |
e7c93f09 | 432 | error: |
7f42b950 NK |
433 | pr_debug("No memory to alloc tracepoints list\n"); |
434 | put_tracepoints_path(&path); | |
435 | return NULL; | |
436 | } | |
e7c93f09 | 437 | next: |
1ef2ed10 FW |
438 | ppath = ppath->next; |
439 | } | |
440 | ||
e2561368 | 441 | return nr_tracepoints > 0 ? path.next : NULL; |
1ef2ed10 | 442 | } |
e2561368 | 443 | |
69aad6f1 | 444 | bool have_tracepoints(struct list_head *pattrs) |
63e0c771 | 445 | { |
69aad6f1 | 446 | struct perf_evsel *pos; |
db620b1c | 447 | |
69aad6f1 ACM |
448 | list_for_each_entry(pos, pattrs, node) |
449 | if (pos->attr.type == PERF_TYPE_TRACEPOINT) | |
db620b1c TZ |
450 | return true; |
451 | ||
452 | return false; | |
63e0c771 TZ |
453 | } |
454 | ||
8755d5e2 | 455 | static int tracing_data_header(void) |
52050943 | 456 | { |
29208e57 | 457 | char buf[20]; |
8755d5e2 | 458 | ssize_t size; |
52050943 | 459 | |
29208e57 | 460 | /* just guessing this is someone's birthday.. ;) */ |
52050943 SR |
461 | buf[0] = 23; |
462 | buf[1] = 8; | |
463 | buf[2] = 68; | |
464 | memcpy(buf + 3, "tracing", 7); | |
465 | ||
8755d5e2 NK |
466 | if (write(output_fd, buf, 10) != 10) |
467 | return -1; | |
52050943 | 468 | |
8755d5e2 NK |
469 | size = strlen(VERSION) + 1; |
470 | if (write(output_fd, VERSION, size) != size) | |
471 | return -1; | |
52050943 SR |
472 | |
473 | /* save endian */ | |
474 | if (bigendian()) | |
475 | buf[0] = 1; | |
476 | else | |
477 | buf[0] = 0; | |
478 | ||
8755d5e2 NK |
479 | if (write(output_fd, buf, 1) != 1) |
480 | return -1; | |
52050943 SR |
481 | |
482 | /* save size of long */ | |
483 | buf[0] = sizeof(long); | |
8755d5e2 NK |
484 | if (write(output_fd, buf, 1) != 1) |
485 | return -1; | |
52050943 SR |
486 | |
487 | /* save page_size */ | |
8755d5e2 NK |
488 | if (write(output_fd, &page_size, 4) != 4) |
489 | return -1; | |
490 | ||
491 | return 0; | |
29208e57 JO |
492 | } |
493 | ||
494 | struct tracing_data *tracing_data_get(struct list_head *pattrs, | |
495 | int fd, bool temp) | |
496 | { | |
497 | struct tracepoint_path *tps; | |
498 | struct tracing_data *tdata; | |
8755d5e2 | 499 | int err; |
29208e57 JO |
500 | |
501 | output_fd = fd; | |
502 | ||
503 | tps = get_tracepoints_path(pattrs); | |
504 | if (!tps) | |
505 | return NULL; | |
52050943 | 506 | |
5a6fd27a NK |
507 | tdata = malloc(sizeof(*tdata)); |
508 | if (!tdata) | |
509 | return NULL; | |
510 | ||
29208e57 JO |
511 | tdata->temp = temp; |
512 | tdata->size = 0; | |
513 | ||
514 | if (temp) { | |
515 | int temp_fd; | |
516 | ||
517 | snprintf(tdata->temp_file, sizeof(tdata->temp_file), | |
518 | "/tmp/perf-XXXXXX"); | |
7f42b950 NK |
519 | if (!mkstemp(tdata->temp_file)) { |
520 | pr_debug("Can't make temp file"); | |
521 | return NULL; | |
522 | } | |
29208e57 JO |
523 | |
524 | temp_fd = open(tdata->temp_file, O_RDWR); | |
7f42b950 NK |
525 | if (temp_fd < 0) { |
526 | pr_debug("Can't read '%s'", tdata->temp_file); | |
527 | return NULL; | |
528 | } | |
29208e57 JO |
529 | |
530 | /* | |
531 | * Set the temp file the default output, so all the | |
532 | * tracing data are stored into it. | |
533 | */ | |
534 | output_fd = temp_fd; | |
535 | } | |
536 | ||
8755d5e2 NK |
537 | err = tracing_data_header(); |
538 | if (err) | |
539 | goto out; | |
077f159d | 540 | err = record_header_files(); |
8755d5e2 NK |
541 | if (err) |
542 | goto out; | |
077f159d | 543 | err = record_ftrace_files(tps); |
8755d5e2 NK |
544 | if (err) |
545 | goto out; | |
077f159d | 546 | err = record_event_files(tps); |
8755d5e2 NK |
547 | if (err) |
548 | goto out; | |
077f159d | 549 | err = record_proc_kallsyms(); |
8755d5e2 NK |
550 | if (err) |
551 | goto out; | |
077f159d | 552 | err = record_ftrace_printk(); |
e2561368 | 553 | |
8755d5e2 | 554 | out: |
29208e57 JO |
555 | /* |
556 | * All tracing data are stored by now, we can restore | |
557 | * the default output file in case we used temp file. | |
558 | */ | |
559 | if (temp) { | |
560 | tdata->size = lseek(output_fd, 0, SEEK_CUR); | |
561 | close(output_fd); | |
562 | output_fd = fd; | |
563 | } | |
564 | ||
04662523 ACM |
565 | if (err) |
566 | zfree(&tdata); | |
8755d5e2 | 567 | |
29208e57 JO |
568 | put_tracepoints_path(tps); |
569 | return tdata; | |
52050943 | 570 | } |
9215545e | 571 | |
8755d5e2 | 572 | int tracing_data_put(struct tracing_data *tdata) |
9215545e | 573 | { |
8755d5e2 NK |
574 | int err = 0; |
575 | ||
29208e57 | 576 | if (tdata->temp) { |
8755d5e2 | 577 | err = record_file(tdata->temp_file, 0); |
29208e57 JO |
578 | unlink(tdata->temp_file); |
579 | } | |
9215545e | 580 | |
29208e57 | 581 | free(tdata); |
8755d5e2 | 582 | return err; |
29208e57 | 583 | } |
9215545e | 584 | |
29208e57 JO |
585 | int read_tracing_data(int fd, struct list_head *pattrs) |
586 | { | |
8755d5e2 | 587 | int err; |
29208e57 | 588 | struct tracing_data *tdata; |
9215545e | 589 | |
29208e57 JO |
590 | /* |
591 | * We work over the real file, so we can write data | |
592 | * directly, no temp file is needed. | |
593 | */ | |
594 | tdata = tracing_data_get(pattrs, fd, false); | |
595 | if (!tdata) | |
596 | return -ENOMEM; | |
597 | ||
8755d5e2 NK |
598 | err = tracing_data_put(tdata); |
599 | return err; | |
9215545e | 600 | } |