aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2009-02-25 00:13:16 -0500
committerIngo Molnar <mingo@elte.hu>2009-02-25 07:40:58 -0500
commitd7350c3f45694104e820041969c8185c5f99e57c (patch)
tree7aaed9e59f6d33c82e0b62c21f9d1bda9f094b4e /kernel/trace
parentb04cc6b1f6398b0e0b60d37e27ce51b4899672ec (diff)
tracing/core: make the read callbacks reentrants
Now that several per-cpu files can be read or spliced at the same, we want the read/splice callbacks for tracing files to be reentrants. Until now, a single global mutex (trace_types_lock) serialized the access to tracing_read_pipe(), tracing_splice_read_pipe(), and the seq helpers. Ie: it means that if a user tries to read trace_pipe0 and trace_pipe1 at the same time, the access to the function tracing_read_pipe() is contended and one reader must wait for the other to finish its read call. The trace_type_lock mutex is mostly here to serialize the access to the global current tracer (current_trace), which can be changed concurrently. Although the iter struct keeps a private pointer to this tracer, its callbacks can be changed by another function. The method used here is to not keep anymore private reference to the tracer inside the iterator but to make a copy of it inside the iterator. Then it checks on subsequents read calls if the tracer has changed. This is not costly because the current tracer is not expected to be changed often, so we use a branch prediction for that. Moreover, we add a private mutex to the iterator (there is one iterator per file descriptor) to serialize the accesses in case of multiple consumers per file descriptor (which would be a silly idea from the user). Note that this is not to protect the ring buffer, since the ring buffer already serializes the readers accesses. This is to prevent from traces weirdness in case of concurrent consumers. But these mutexes can be dropped anyway, that would not result in any crash. Just tell me what you think about it. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/trace')
-rw-r--r--kernel/trace/trace.c101
-rw-r--r--kernel/trace/trace.h3
2 files changed, 85 insertions, 19 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index aa58b7bc847c..d8d899f3bd6f 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -1294,20 +1294,32 @@ static void *s_next(struct seq_file *m, void *v, loff_t *pos)
1294 return ent; 1294 return ent;
1295} 1295}
1296 1296
1297/*
1298 * No necessary locking here. The worst thing which can
1299 * happen is loosing events consumed at the same time
1300 * by a trace_pipe reader.
1301 * Other than that, we don't risk to crash the ring buffer
1302 * because it serializes the readers.
1303 *
1304 * The current tracer is copied to avoid a global locking
1305 * all around.
1306 */
1297static void *s_start(struct seq_file *m, loff_t *pos) 1307static void *s_start(struct seq_file *m, loff_t *pos)
1298{ 1308{
1299 struct trace_iterator *iter = m->private; 1309 struct trace_iterator *iter = m->private;
1310 static struct tracer *old_tracer;
1300 int cpu_file = iter->cpu_file; 1311 int cpu_file = iter->cpu_file;
1301 void *p = NULL; 1312 void *p = NULL;
1302 loff_t l = 0; 1313 loff_t l = 0;
1303 int cpu; 1314 int cpu;
1304 1315
1316 /* copy the tracer to avoid using a global lock all around */
1305 mutex_lock(&trace_types_lock); 1317 mutex_lock(&trace_types_lock);
1306 1318 if (unlikely(old_tracer != current_trace && current_trace)) {
1307 if (!current_trace || current_trace != iter->trace) { 1319 old_tracer = current_trace;
1308 mutex_unlock(&trace_types_lock); 1320 *iter->trace = *current_trace;
1309 return NULL;
1310 } 1321 }
1322 mutex_unlock(&trace_types_lock);
1311 1323
1312 atomic_inc(&trace_record_cmdline_disabled); 1324 atomic_inc(&trace_record_cmdline_disabled);
1313 1325
@@ -1341,7 +1353,6 @@ static void *s_start(struct seq_file *m, loff_t *pos)
1341static void s_stop(struct seq_file *m, void *p) 1353static void s_stop(struct seq_file *m, void *p)
1342{ 1354{
1343 atomic_dec(&trace_record_cmdline_disabled); 1355 atomic_dec(&trace_record_cmdline_disabled);
1344 mutex_unlock(&trace_types_lock);
1345} 1356}
1346 1357
1347static void print_lat_help_header(struct seq_file *m) 1358static void print_lat_help_header(struct seq_file *m)
@@ -1691,13 +1702,25 @@ __tracing_open(struct inode *inode, struct file *file, int *ret)
1691 goto out; 1702 goto out;
1692 } 1703 }
1693 1704
1705 /*
1706 * We make a copy of the current tracer to avoid concurrent
1707 * changes on it while we are reading.
1708 */
1694 mutex_lock(&trace_types_lock); 1709 mutex_lock(&trace_types_lock);
1710 iter->trace = kzalloc(sizeof(*iter->trace), GFP_KERNEL);
1711 if (!iter->trace) {
1712 *ret = -ENOMEM;
1713 goto fail;
1714 }
1715 if (current_trace)
1716 *iter->trace = *current_trace;
1717
1695 if (current_trace && current_trace->print_max) 1718 if (current_trace && current_trace->print_max)
1696 iter->tr = &max_tr; 1719 iter->tr = &max_tr;
1697 else 1720 else
1698 iter->tr = &global_trace; 1721 iter->tr = &global_trace;
1699 iter->trace = current_trace;
1700 iter->pos = -1; 1722 iter->pos = -1;
1723 mutex_init(&iter->mutex);
1701 iter->cpu_file = cpu_file; 1724 iter->cpu_file = cpu_file;
1702 1725
1703 /* Notify the tracer early; before we stop tracing. */ 1726 /* Notify the tracer early; before we stop tracing. */
@@ -1747,8 +1770,9 @@ __tracing_open(struct inode *inode, struct file *file, int *ret)
1747 if (iter->buffer_iter[cpu]) 1770 if (iter->buffer_iter[cpu])
1748 ring_buffer_read_finish(iter->buffer_iter[cpu]); 1771 ring_buffer_read_finish(iter->buffer_iter[cpu]);
1749 } 1772 }
1750fail: 1773 fail:
1751 mutex_unlock(&trace_types_lock); 1774 mutex_unlock(&trace_types_lock);
1775 kfree(iter->trace);
1752 kfree(iter); 1776 kfree(iter);
1753 1777
1754 return ERR_PTR(-ENOMEM); 1778 return ERR_PTR(-ENOMEM);
@@ -1783,6 +1807,8 @@ static int tracing_release(struct inode *inode, struct file *file)
1783 mutex_unlock(&trace_types_lock); 1807 mutex_unlock(&trace_types_lock);
1784 1808
1785 seq_release(inode, file); 1809 seq_release(inode, file);
1810 mutex_destroy(&iter->mutex);
1811 kfree(iter->trace);
1786 kfree(iter); 1812 kfree(iter);
1787 return 0; 1813 return 0;
1788} 1814}
@@ -2392,10 +2418,21 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
2392 goto out; 2418 goto out;
2393 } 2419 }
2394 2420
2421 /*
2422 * We make a copy of the current tracer to avoid concurrent
2423 * changes on it while we are reading.
2424 */
2425 iter->trace = kmalloc(sizeof(*iter->trace), GFP_KERNEL);
2426 if (!iter->trace) {
2427 ret = -ENOMEM;
2428 goto fail;
2429 }
2430 if (current_trace)
2431 *iter->trace = *current_trace;
2432
2395 if (!alloc_cpumask_var(&iter->started, GFP_KERNEL)) { 2433 if (!alloc_cpumask_var(&iter->started, GFP_KERNEL)) {
2396 kfree(iter);
2397 ret = -ENOMEM; 2434 ret = -ENOMEM;
2398 goto out; 2435 goto fail;
2399 } 2436 }
2400 2437
2401 /* trace pipe does not show start of buffer */ 2438 /* trace pipe does not show start of buffer */
@@ -2403,7 +2440,7 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
2403 2440
2404 iter->cpu_file = cpu_file; 2441 iter->cpu_file = cpu_file;
2405 iter->tr = &global_trace; 2442 iter->tr = &global_trace;
2406 iter->trace = current_trace; 2443 mutex_init(&iter->mutex);
2407 filp->private_data = iter; 2444 filp->private_data = iter;
2408 2445
2409 if (iter->trace->pipe_open) 2446 if (iter->trace->pipe_open)
@@ -2412,6 +2449,12 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
2412out: 2449out:
2413 mutex_unlock(&trace_types_lock); 2450 mutex_unlock(&trace_types_lock);
2414 return ret; 2451 return ret;
2452
2453fail:
2454 kfree(iter->trace);
2455 kfree(iter);
2456 mutex_unlock(&trace_types_lock);
2457 return ret;
2415} 2458}
2416 2459
2417static int tracing_release_pipe(struct inode *inode, struct file *file) 2460static int tracing_release_pipe(struct inode *inode, struct file *file)
@@ -2428,6 +2471,8 @@ static int tracing_release_pipe(struct inode *inode, struct file *file)
2428 mutex_unlock(&trace_types_lock); 2471 mutex_unlock(&trace_types_lock);
2429 2472
2430 free_cpumask_var(iter->started); 2473 free_cpumask_var(iter->started);
2474 mutex_destroy(&iter->mutex);
2475 kfree(iter->trace);
2431 kfree(iter); 2476 kfree(iter);
2432 2477
2433 return 0; 2478 return 0;
@@ -2497,18 +2542,15 @@ static int tracing_wait_pipe(struct file *filp)
2497 return -EAGAIN; 2542 return -EAGAIN;
2498 } 2543 }
2499 2544
2500 mutex_unlock(&trace_types_lock); 2545 mutex_unlock(&iter->mutex);
2501 2546
2502 iter->trace->wait_pipe(iter); 2547 iter->trace->wait_pipe(iter);
2503 2548
2504 mutex_lock(&trace_types_lock); 2549 mutex_lock(&iter->mutex);
2505 2550
2506 if (signal_pending(current)) 2551 if (signal_pending(current))
2507 return -EINTR; 2552 return -EINTR;
2508 2553
2509 if (iter->trace != current_trace)
2510 return 0;
2511
2512 /* 2554 /*
2513 * We block until we read something and tracing is disabled. 2555 * We block until we read something and tracing is disabled.
2514 * We still block if tracing is disabled, but we have never 2556 * We still block if tracing is disabled, but we have never
@@ -2533,6 +2575,7 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
2533 size_t cnt, loff_t *ppos) 2575 size_t cnt, loff_t *ppos)
2534{ 2576{
2535 struct trace_iterator *iter = filp->private_data; 2577 struct trace_iterator *iter = filp->private_data;
2578 static struct tracer *old_tracer;
2536 ssize_t sret; 2579 ssize_t sret;
2537 2580
2538 /* return any leftover data */ 2581 /* return any leftover data */
@@ -2542,7 +2585,20 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
2542 2585
2543 trace_seq_reset(&iter->seq); 2586 trace_seq_reset(&iter->seq);
2544 2587
2588 /* copy the tracer to avoid using a global lock all around */
2545 mutex_lock(&trace_types_lock); 2589 mutex_lock(&trace_types_lock);
2590 if (unlikely(old_tracer != current_trace && current_trace)) {
2591 old_tracer = current_trace;
2592 *iter->trace = *current_trace;
2593 }
2594 mutex_unlock(&trace_types_lock);
2595
2596 /*
2597 * Avoid more than one consumer on a single file descriptor
2598 * This is just a matter of traces coherency, the ring buffer itself
2599 * is protected.
2600 */
2601 mutex_lock(&iter->mutex);
2546 if (iter->trace->read) { 2602 if (iter->trace->read) {
2547 sret = iter->trace->read(iter, filp, ubuf, cnt, ppos); 2603 sret = iter->trace->read(iter, filp, ubuf, cnt, ppos);
2548 if (sret) 2604 if (sret)
@@ -2599,7 +2655,7 @@ waitagain:
2599 goto waitagain; 2655 goto waitagain;
2600 2656
2601out: 2657out:
2602 mutex_unlock(&trace_types_lock); 2658 mutex_unlock(&iter->mutex);
2603 2659
2604 return sret; 2660 return sret;
2605} 2661}
@@ -2676,11 +2732,20 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
2676 .ops = &tracing_pipe_buf_ops, 2732 .ops = &tracing_pipe_buf_ops,
2677 .spd_release = tracing_spd_release_pipe, 2733 .spd_release = tracing_spd_release_pipe,
2678 }; 2734 };
2735 static struct tracer *old_tracer;
2679 ssize_t ret; 2736 ssize_t ret;
2680 size_t rem; 2737 size_t rem;
2681 unsigned int i; 2738 unsigned int i;
2682 2739
2740 /* copy the tracer to avoid using a global lock all around */
2683 mutex_lock(&trace_types_lock); 2741 mutex_lock(&trace_types_lock);
2742 if (unlikely(old_tracer != current_trace && current_trace)) {
2743 old_tracer = current_trace;
2744 *iter->trace = *current_trace;
2745 }
2746 mutex_unlock(&trace_types_lock);
2747
2748 mutex_lock(&iter->mutex);
2684 2749
2685 if (iter->trace->splice_read) { 2750 if (iter->trace->splice_read) {
2686 ret = iter->trace->splice_read(iter, filp, 2751 ret = iter->trace->splice_read(iter, filp,
@@ -2720,14 +2785,14 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
2720 trace_seq_reset(&iter->seq); 2785 trace_seq_reset(&iter->seq);
2721 } 2786 }
2722 2787
2723 mutex_unlock(&trace_types_lock); 2788 mutex_unlock(&iter->mutex);
2724 2789
2725 spd.nr_pages = i; 2790 spd.nr_pages = i;
2726 2791
2727 return splice_to_pipe(pipe, &spd); 2792 return splice_to_pipe(pipe, &spd);
2728 2793
2729out_err: 2794out_err:
2730 mutex_unlock(&trace_types_lock); 2795 mutex_unlock(&iter->mutex);
2731 2796
2732 return ret; 2797 return ret;
2733} 2798}
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 508235a39da6..632191770aac 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -405,8 +405,9 @@ struct trace_iterator {
405 struct trace_array *tr; 405 struct trace_array *tr;
406 struct tracer *trace; 406 struct tracer *trace;
407 void *private; 407 void *private;
408 struct ring_buffer_iter *buffer_iter[NR_CPUS];
409 int cpu_file; 408 int cpu_file;
409 struct mutex mutex;
410 struct ring_buffer_iter *buffer_iter[NR_CPUS];
410 411
411 /* The below is zeroed out in pipe_read */ 412 /* The below is zeroed out in pipe_read */
412 struct trace_seq seq; 413 struct trace_seq seq;