diff options
Diffstat (limited to 'kernel/trace/trace.c')
-rw-r--r-- | kernel/trace/trace.c | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 3a89496dc99b..307524d784ec 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -339,6 +339,90 @@ void tracing_on(void) | |||
339 | } | 339 | } |
340 | EXPORT_SYMBOL_GPL(tracing_on); | 340 | EXPORT_SYMBOL_GPL(tracing_on); |
341 | 341 | ||
342 | #ifdef CONFIG_TRACER_SNAPSHOT | ||
343 | /** | ||
344 | * trace_snapshot - take a snapshot of the current buffer. | ||
345 | * | ||
346 | * This causes a swap between the snapshot buffer and the current live | ||
347 | * tracing buffer. You can use this to take snapshots of the live | ||
348 | * trace when some condition is triggered, but continue to trace. | ||
349 | * | ||
350 | * Note, make sure to allocate the snapshot with either | ||
351 | * a tracing_snapshot_alloc(), or by doing it manually | ||
352 | * with: echo 1 > /sys/kernel/debug/tracing/snapshot | ||
353 | * | ||
354 | * If the snapshot buffer is not allocated, it will stop tracing. | ||
355 | * Basically making a permanent snapshot. | ||
356 | */ | ||
357 | void tracing_snapshot(void) | ||
358 | { | ||
359 | struct trace_array *tr = &global_trace; | ||
360 | struct tracer *tracer = tr->current_trace; | ||
361 | unsigned long flags; | ||
362 | |||
363 | if (!tr->allocated_snapshot) { | ||
364 | trace_printk("*** SNAPSHOT NOT ALLOCATED ***\n"); | ||
365 | trace_printk("*** stopping trace here! ***\n"); | ||
366 | tracing_off(); | ||
367 | return; | ||
368 | } | ||
369 | |||
370 | /* Note, snapshot can not be used when the tracer uses it */ | ||
371 | if (tracer->use_max_tr) { | ||
372 | trace_printk("*** LATENCY TRACER ACTIVE ***\n"); | ||
373 | trace_printk("*** Can not use snapshot (sorry) ***\n"); | ||
374 | return; | ||
375 | } | ||
376 | |||
377 | local_irq_save(flags); | ||
378 | update_max_tr(tr, current, smp_processor_id()); | ||
379 | local_irq_restore(flags); | ||
380 | } | ||
381 | |||
382 | static int resize_buffer_duplicate_size(struct trace_buffer *trace_buf, | ||
383 | struct trace_buffer *size_buf, int cpu_id); | ||
384 | |||
385 | /** | ||
386 | * trace_snapshot_alloc - allocate and take a snapshot of the current buffer. | ||
387 | * | ||
388 | * This is similar to trace_snapshot(), but it will allocate the | ||
389 | * snapshot buffer if it isn't already allocated. Use this only | ||
390 | * where it is safe to sleep, as the allocation may sleep. | ||
391 | * | ||
392 | * This causes a swap between the snapshot buffer and the current live | ||
393 | * tracing buffer. You can use this to take snapshots of the live | ||
394 | * trace when some condition is triggered, but continue to trace. | ||
395 | */ | ||
396 | void tracing_snapshot_alloc(void) | ||
397 | { | ||
398 | struct trace_array *tr = &global_trace; | ||
399 | int ret; | ||
400 | |||
401 | if (!tr->allocated_snapshot) { | ||
402 | |||
403 | /* allocate spare buffer */ | ||
404 | ret = resize_buffer_duplicate_size(&tr->max_buffer, | ||
405 | &tr->trace_buffer, RING_BUFFER_ALL_CPUS); | ||
406 | if (WARN_ON(ret < 0)) | ||
407 | return; | ||
408 | |||
409 | tr->allocated_snapshot = true; | ||
410 | } | ||
411 | |||
412 | tracing_snapshot(); | ||
413 | } | ||
414 | #else | ||
415 | void tracing_snapshot(void) | ||
416 | { | ||
417 | WARN_ONCE(1, "Snapshot feature not enabled, but internal snapshot used"); | ||
418 | } | ||
419 | void tracing_snapshot_alloc(void) | ||
420 | { | ||
421 | /* Give warning */ | ||
422 | tracing_snapshot(); | ||
423 | } | ||
424 | #endif /* CONFIG_TRACER_SNAPSHOT */ | ||
425 | |||
342 | /** | 426 | /** |
343 | * tracing_off - turn off tracing buffers | 427 | * tracing_off - turn off tracing buffers |
344 | * | 428 | * |