diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-02-10 07:58:28 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-02-10 07:58:28 -0500 |
commit | ae216dd239765afd592f65d94d8430244cf77ed1 (patch) | |
tree | a8e203cd9260be48d07e1484f87023d7d3dbae64 /kernel | |
parent | f9915bfef3c64ea0b0b960dd1b999b584a7ef460 (diff) | |
parent | 34cd4998d38f9bd04f34b78a7cb0c7f1bee00bd9 (diff) |
Merge branch 'tip/tracing/ftrace' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-trace into tracing/ftrace
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/trace/trace.c | 219 | ||||
-rw-r--r-- | kernel/trace/trace.h | 6 |
2 files changed, 196 insertions, 29 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 5b1e9a9e9906..d89821283b47 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/fs.h> | 31 | #include <linux/fs.h> |
32 | #include <linux/kprobes.h> | 32 | #include <linux/kprobes.h> |
33 | #include <linux/writeback.h> | 33 | #include <linux/writeback.h> |
34 | #include <linux/splice.h> | ||
34 | 35 | ||
35 | #include <linux/stacktrace.h> | 36 | #include <linux/stacktrace.h> |
36 | #include <linux/ring_buffer.h> | 37 | #include <linux/ring_buffer.h> |
@@ -364,6 +365,25 @@ ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, size_t cnt) | |||
364 | return cnt; | 365 | return cnt; |
365 | } | 366 | } |
366 | 367 | ||
368 | ssize_t trace_seq_to_buffer(struct trace_seq *s, void *buf, size_t cnt) | ||
369 | { | ||
370 | int len; | ||
371 | void *ret; | ||
372 | |||
373 | if (s->len <= s->readpos) | ||
374 | return -EBUSY; | ||
375 | |||
376 | len = s->len - s->readpos; | ||
377 | if (cnt > len) | ||
378 | cnt = len; | ||
379 | ret = memcpy(buf, s->buffer + s->readpos, cnt); | ||
380 | if (!ret) | ||
381 | return -EFAULT; | ||
382 | |||
383 | s->readpos += len; | ||
384 | return cnt; | ||
385 | } | ||
386 | |||
367 | static void | 387 | static void |
368 | trace_print_seq(struct seq_file *m, struct trace_seq *s) | 388 | trace_print_seq(struct seq_file *m, struct trace_seq *s) |
369 | { | 389 | { |
@@ -2368,37 +2388,15 @@ tracing_poll_pipe(struct file *filp, poll_table *poll_table) | |||
2368 | } | 2388 | } |
2369 | } | 2389 | } |
2370 | 2390 | ||
2371 | /* | 2391 | /* Must be called with trace_types_lock mutex held. */ |
2372 | * Consumer reader. | 2392 | static int tracing_wait_pipe(struct file *filp) |
2373 | */ | ||
2374 | static ssize_t | ||
2375 | tracing_read_pipe(struct file *filp, char __user *ubuf, | ||
2376 | size_t cnt, loff_t *ppos) | ||
2377 | { | 2393 | { |
2378 | struct trace_iterator *iter = filp->private_data; | 2394 | struct trace_iterator *iter = filp->private_data; |
2379 | ssize_t sret; | ||
2380 | |||
2381 | /* return any leftover data */ | ||
2382 | sret = trace_seq_to_user(&iter->seq, ubuf, cnt); | ||
2383 | if (sret != -EBUSY) | ||
2384 | return sret; | ||
2385 | |||
2386 | trace_seq_reset(&iter->seq); | ||
2387 | 2395 | ||
2388 | mutex_lock(&trace_types_lock); | ||
2389 | if (iter->trace->read) { | ||
2390 | sret = iter->trace->read(iter, filp, ubuf, cnt, ppos); | ||
2391 | if (sret) | ||
2392 | goto out; | ||
2393 | } | ||
2394 | |||
2395 | waitagain: | ||
2396 | sret = 0; | ||
2397 | while (trace_empty(iter)) { | 2396 | while (trace_empty(iter)) { |
2398 | 2397 | ||
2399 | if ((filp->f_flags & O_NONBLOCK)) { | 2398 | if ((filp->f_flags & O_NONBLOCK)) { |
2400 | sret = -EAGAIN; | 2399 | return -EAGAIN; |
2401 | goto out; | ||
2402 | } | 2400 | } |
2403 | 2401 | ||
2404 | /* | 2402 | /* |
@@ -2423,12 +2421,11 @@ waitagain: | |||
2423 | iter->tr->waiter = NULL; | 2421 | iter->tr->waiter = NULL; |
2424 | 2422 | ||
2425 | if (signal_pending(current)) { | 2423 | if (signal_pending(current)) { |
2426 | sret = -EINTR; | 2424 | return -EINTR; |
2427 | goto out; | ||
2428 | } | 2425 | } |
2429 | 2426 | ||
2430 | if (iter->trace != current_trace) | 2427 | if (iter->trace != current_trace) |
2431 | goto out; | 2428 | return 0; |
2432 | 2429 | ||
2433 | /* | 2430 | /* |
2434 | * We block until we read something and tracing is disabled. | 2431 | * We block until we read something and tracing is disabled. |
@@ -2445,9 +2442,43 @@ waitagain: | |||
2445 | continue; | 2442 | continue; |
2446 | } | 2443 | } |
2447 | 2444 | ||
2445 | return 1; | ||
2446 | } | ||
2447 | |||
2448 | /* | ||
2449 | * Consumer reader. | ||
2450 | */ | ||
2451 | static ssize_t | ||
2452 | tracing_read_pipe(struct file *filp, char __user *ubuf, | ||
2453 | size_t cnt, loff_t *ppos) | ||
2454 | { | ||
2455 | struct trace_iterator *iter = filp->private_data; | ||
2456 | ssize_t sret; | ||
2457 | |||
2458 | /* return any leftover data */ | ||
2459 | sret = trace_seq_to_user(&iter->seq, ubuf, cnt); | ||
2460 | if (sret != -EBUSY) | ||
2461 | return sret; | ||
2462 | |||
2463 | trace_seq_reset(&iter->seq); | ||
2464 | |||
2465 | mutex_lock(&trace_types_lock); | ||
2466 | if (iter->trace->read) { | ||
2467 | sret = iter->trace->read(iter, filp, ubuf, cnt, ppos); | ||
2468 | if (sret) | ||
2469 | goto out; | ||
2470 | } | ||
2471 | |||
2472 | waitagain: | ||
2473 | sret = tracing_wait_pipe(filp); | ||
2474 | if (sret <= 0) | ||
2475 | goto out; | ||
2476 | |||
2448 | /* stop when tracing is finished */ | 2477 | /* stop when tracing is finished */ |
2449 | if (trace_empty(iter)) | 2478 | if (trace_empty(iter)) { |
2479 | sret = 0; | ||
2450 | goto out; | 2480 | goto out; |
2481 | } | ||
2451 | 2482 | ||
2452 | if (cnt >= PAGE_SIZE) | 2483 | if (cnt >= PAGE_SIZE) |
2453 | cnt = PAGE_SIZE - 1; | 2484 | cnt = PAGE_SIZE - 1; |
@@ -2493,6 +2524,135 @@ out: | |||
2493 | return sret; | 2524 | return sret; |
2494 | } | 2525 | } |
2495 | 2526 | ||
2527 | static void tracing_pipe_buf_release(struct pipe_inode_info *pipe, | ||
2528 | struct pipe_buffer *buf) | ||
2529 | { | ||
2530 | __free_page(buf->page); | ||
2531 | } | ||
2532 | |||
2533 | static void tracing_spd_release_pipe(struct splice_pipe_desc *spd, | ||
2534 | unsigned int idx) | ||
2535 | { | ||
2536 | __free_page(spd->pages[idx]); | ||
2537 | } | ||
2538 | |||
2539 | static struct pipe_buf_operations tracing_pipe_buf_ops = { | ||
2540 | .can_merge = 0, | ||
2541 | .map = generic_pipe_buf_map, | ||
2542 | .unmap = generic_pipe_buf_unmap, | ||
2543 | .confirm = generic_pipe_buf_confirm, | ||
2544 | .release = tracing_pipe_buf_release, | ||
2545 | .steal = generic_pipe_buf_steal, | ||
2546 | .get = generic_pipe_buf_get, | ||
2547 | }; | ||
2548 | |||
2549 | static size_t | ||
2550 | tracing_fill_pipe_page(struct page *pages, size_t rem, | ||
2551 | struct trace_iterator *iter) | ||
2552 | { | ||
2553 | size_t count; | ||
2554 | int ret; | ||
2555 | |||
2556 | /* Seq buffer is page-sized, exactly what we need. */ | ||
2557 | for (;;) { | ||
2558 | count = iter->seq.len; | ||
2559 | ret = print_trace_line(iter); | ||
2560 | count = iter->seq.len - count; | ||
2561 | if (rem < count) { | ||
2562 | rem = 0; | ||
2563 | iter->seq.len -= count; | ||
2564 | break; | ||
2565 | } | ||
2566 | if (ret == TRACE_TYPE_PARTIAL_LINE) { | ||
2567 | iter->seq.len -= count; | ||
2568 | break; | ||
2569 | } | ||
2570 | |||
2571 | trace_consume(iter); | ||
2572 | rem -= count; | ||
2573 | if (!find_next_entry_inc(iter)) { | ||
2574 | rem = 0; | ||
2575 | iter->ent = NULL; | ||
2576 | break; | ||
2577 | } | ||
2578 | } | ||
2579 | |||
2580 | return rem; | ||
2581 | } | ||
2582 | |||
2583 | static ssize_t tracing_splice_read_pipe(struct file *filp, | ||
2584 | loff_t *ppos, | ||
2585 | struct pipe_inode_info *pipe, | ||
2586 | size_t len, | ||
2587 | unsigned int flags) | ||
2588 | { | ||
2589 | struct page *pages[PIPE_BUFFERS]; | ||
2590 | struct partial_page partial[PIPE_BUFFERS]; | ||
2591 | struct trace_iterator *iter = filp->private_data; | ||
2592 | struct splice_pipe_desc spd = { | ||
2593 | .pages = pages, | ||
2594 | .partial = partial, | ||
2595 | .nr_pages = 0, /* This gets updated below. */ | ||
2596 | .flags = flags, | ||
2597 | .ops = &tracing_pipe_buf_ops, | ||
2598 | .spd_release = tracing_spd_release_pipe, | ||
2599 | }; | ||
2600 | ssize_t ret; | ||
2601 | size_t rem; | ||
2602 | unsigned int i; | ||
2603 | |||
2604 | mutex_lock(&trace_types_lock); | ||
2605 | |||
2606 | if (iter->trace->splice_read) { | ||
2607 | ret = iter->trace->splice_read(iter, filp, | ||
2608 | ppos, pipe, len, flags); | ||
2609 | if (ret) | ||
2610 | goto out_err; | ||
2611 | } | ||
2612 | |||
2613 | ret = tracing_wait_pipe(filp); | ||
2614 | if (ret <= 0) | ||
2615 | goto out_err; | ||
2616 | |||
2617 | if (!iter->ent && !find_next_entry_inc(iter)) { | ||
2618 | ret = -EFAULT; | ||
2619 | goto out_err; | ||
2620 | } | ||
2621 | |||
2622 | /* Fill as many pages as possible. */ | ||
2623 | for (i = 0, rem = len; i < PIPE_BUFFERS && rem; i++) { | ||
2624 | pages[i] = alloc_page(GFP_KERNEL); | ||
2625 | if (!pages[i]) | ||
2626 | break; | ||
2627 | |||
2628 | rem = tracing_fill_pipe_page(pages[i], rem, iter); | ||
2629 | |||
2630 | /* Copy the data into the page, so we can start over. */ | ||
2631 | ret = trace_seq_to_buffer(&iter->seq, | ||
2632 | page_address(pages[i]), | ||
2633 | iter->seq.len); | ||
2634 | if (ret < 0) { | ||
2635 | __free_page(pages[i]); | ||
2636 | break; | ||
2637 | } | ||
2638 | partial[i].offset = 0; | ||
2639 | partial[i].len = iter->seq.len; | ||
2640 | |||
2641 | trace_seq_reset(&iter->seq); | ||
2642 | } | ||
2643 | |||
2644 | mutex_unlock(&trace_types_lock); | ||
2645 | |||
2646 | spd.nr_pages = i; | ||
2647 | |||
2648 | return splice_to_pipe(pipe, &spd); | ||
2649 | |||
2650 | out_err: | ||
2651 | mutex_unlock(&trace_types_lock); | ||
2652 | |||
2653 | return ret; | ||
2654 | } | ||
2655 | |||
2496 | static ssize_t | 2656 | static ssize_t |
2497 | tracing_entries_read(struct file *filp, char __user *ubuf, | 2657 | tracing_entries_read(struct file *filp, char __user *ubuf, |
2498 | size_t cnt, loff_t *ppos) | 2658 | size_t cnt, loff_t *ppos) |
@@ -2656,6 +2816,7 @@ static struct file_operations tracing_pipe_fops = { | |||
2656 | .open = tracing_open_pipe, | 2816 | .open = tracing_open_pipe, |
2657 | .poll = tracing_poll_pipe, | 2817 | .poll = tracing_poll_pipe, |
2658 | .read = tracing_read_pipe, | 2818 | .read = tracing_read_pipe, |
2819 | .splice_read = tracing_splice_read_pipe, | ||
2659 | .release = tracing_release_pipe, | 2820 | .release = tracing_release_pipe, |
2660 | }; | 2821 | }; |
2661 | 2822 | ||
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 7b0518adf6d7..dbff0207b213 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -353,6 +353,12 @@ struct tracer { | |||
353 | ssize_t (*read)(struct trace_iterator *iter, | 353 | ssize_t (*read)(struct trace_iterator *iter, |
354 | struct file *filp, char __user *ubuf, | 354 | struct file *filp, char __user *ubuf, |
355 | size_t cnt, loff_t *ppos); | 355 | size_t cnt, loff_t *ppos); |
356 | ssize_t (*splice_read)(struct trace_iterator *iter, | ||
357 | struct file *filp, | ||
358 | loff_t *ppos, | ||
359 | struct pipe_inode_info *pipe, | ||
360 | size_t len, | ||
361 | unsigned int flags); | ||
356 | #ifdef CONFIG_FTRACE_STARTUP_TEST | 362 | #ifdef CONFIG_FTRACE_STARTUP_TEST |
357 | int (*selftest)(struct tracer *trace, | 363 | int (*selftest)(struct tracer *trace, |
358 | struct trace_array *tr); | 364 | struct trace_array *tr); |