Merge branch 'tracing-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'tracing-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (31 commits) ftrace: fix current_tracer error return tracing: fix a build error on alpha ftrace: use a real variable for ftrace_nop in x86 tracing/ftrace: make boot tracer select the sched_switch tracer tracepoint: check if the probe has been registered asm-generic: define DIE_OOPS in asm-generic trace: fix printk warning for u64 ftrace: warning in kernel/trace/ftrace.c ftrace: fix build failure ftrace, powerpc, sparc64, x86: remove notrace from arch ftrace file ftrace: remove ftrace hash ftrace: remove mcount set ftrace: remove daemon ftrace: disable dynamic ftrace for all archs that use daemon ftrace: add ftrace warn on to disable ftrace ftrace: only have ftrace_kill atomic ftrace: use probe_kernel ftrace: comment arch ftrace code ftrace: return error on failed modified text. ftrace: dynamic ftrace process only text section ...
This commit is contained in:
+2
-2
@@ -13,7 +13,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o \
|
||||
|
||||
CFLAGS_REMOVE_sched.o = -mno-spe
|
||||
|
||||
ifdef CONFIG_FTRACE
|
||||
ifdef CONFIG_FUNCTION_TRACER
|
||||
# Do not trace debug files and internal ftrace files
|
||||
CFLAGS_REMOVE_lockdep.o = -pg
|
||||
CFLAGS_REMOVE_lockdep_proc.o = -pg
|
||||
@@ -88,7 +88,7 @@ obj-$(CONFIG_MARKERS) += marker.o
|
||||
obj-$(CONFIG_TRACEPOINTS) += tracepoint.o
|
||||
obj-$(CONFIG_LATENCYTOP) += latencytop.o
|
||||
obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
|
||||
obj-$(CONFIG_FTRACE) += trace/
|
||||
obj-$(CONFIG_FUNCTION_TRACER) += trace/
|
||||
obj-$(CONFIG_TRACING) += trace/
|
||||
obj-$(CONFIG_SMP) += sched_cpupri.o
|
||||
|
||||
|
||||
+1
-1
@@ -474,7 +474,7 @@ static struct ctl_table kern_table[] = {
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec,
|
||||
},
|
||||
#ifdef CONFIG_FTRACE
|
||||
#ifdef CONFIG_FUNCTION_TRACER
|
||||
{
|
||||
.ctl_name = CTL_UNNUMBERED,
|
||||
.procname = "ftrace_enabled",
|
||||
|
||||
+14
-13
@@ -1,11 +1,12 @@
|
||||
#
|
||||
# Architectures that offer an FTRACE implementation should select HAVE_FTRACE:
|
||||
# Architectures that offer an FUNCTION_TRACER implementation should
|
||||
# select HAVE_FUNCTION_TRACER:
|
||||
#
|
||||
|
||||
config NOP_TRACER
|
||||
bool
|
||||
|
||||
config HAVE_FTRACE
|
||||
config HAVE_FUNCTION_TRACER
|
||||
bool
|
||||
select NOP_TRACER
|
||||
|
||||
@@ -28,9 +29,11 @@ config TRACING
|
||||
select STACKTRACE
|
||||
select TRACEPOINTS
|
||||
|
||||
config FTRACE
|
||||
menu "Tracers"
|
||||
|
||||
config FUNCTION_TRACER
|
||||
bool "Kernel Function Tracer"
|
||||
depends on HAVE_FTRACE
|
||||
depends on HAVE_FUNCTION_TRACER
|
||||
depends on DEBUG_KERNEL
|
||||
select FRAME_POINTER
|
||||
select TRACING
|
||||
@@ -49,7 +52,6 @@ config IRQSOFF_TRACER
|
||||
default n
|
||||
depends on TRACE_IRQFLAGS_SUPPORT
|
||||
depends on GENERIC_TIME
|
||||
depends on HAVE_FTRACE
|
||||
depends on DEBUG_KERNEL
|
||||
select TRACE_IRQFLAGS
|
||||
select TRACING
|
||||
@@ -73,7 +75,6 @@ config PREEMPT_TRACER
|
||||
default n
|
||||
depends on GENERIC_TIME
|
||||
depends on PREEMPT
|
||||
depends on HAVE_FTRACE
|
||||
depends on DEBUG_KERNEL
|
||||
select TRACING
|
||||
select TRACER_MAX_TRACE
|
||||
@@ -101,7 +102,6 @@ config SYSPROF_TRACER
|
||||
|
||||
config SCHED_TRACER
|
||||
bool "Scheduling Latency Tracer"
|
||||
depends on HAVE_FTRACE
|
||||
depends on DEBUG_KERNEL
|
||||
select TRACING
|
||||
select CONTEXT_SWITCH_TRACER
|
||||
@@ -112,7 +112,6 @@ config SCHED_TRACER
|
||||
|
||||
config CONTEXT_SWITCH_TRACER
|
||||
bool "Trace process context switches"
|
||||
depends on HAVE_FTRACE
|
||||
depends on DEBUG_KERNEL
|
||||
select TRACING
|
||||
select MARKERS
|
||||
@@ -122,9 +121,9 @@ config CONTEXT_SWITCH_TRACER
|
||||
|
||||
config BOOT_TRACER
|
||||
bool "Trace boot initcalls"
|
||||
depends on HAVE_FTRACE
|
||||
depends on DEBUG_KERNEL
|
||||
select TRACING
|
||||
select CONTEXT_SWITCH_TRACER
|
||||
help
|
||||
This tracer helps developers to optimize boot times: it records
|
||||
the timings of the initcalls and traces key events and the identity
|
||||
@@ -141,9 +140,9 @@ config BOOT_TRACER
|
||||
|
||||
config STACK_TRACER
|
||||
bool "Trace max stack"
|
||||
depends on HAVE_FTRACE
|
||||
depends on HAVE_FUNCTION_TRACER
|
||||
depends on DEBUG_KERNEL
|
||||
select FTRACE
|
||||
select FUNCTION_TRACER
|
||||
select STACKTRACE
|
||||
help
|
||||
This special tracer records the maximum stack footprint of the
|
||||
@@ -160,7 +159,7 @@ config STACK_TRACER
|
||||
|
||||
config DYNAMIC_FTRACE
|
||||
bool "enable/disable ftrace tracepoints dynamically"
|
||||
depends on FTRACE
|
||||
depends on FUNCTION_TRACER
|
||||
depends on HAVE_DYNAMIC_FTRACE
|
||||
depends on DEBUG_KERNEL
|
||||
default y
|
||||
@@ -170,7 +169,7 @@ config DYNAMIC_FTRACE
|
||||
with a No-Op instruction) as they are called. A table is
|
||||
created to dynamically enable them again.
|
||||
|
||||
This way a CONFIG_FTRACE kernel is slightly larger, but otherwise
|
||||
This way a CONFIG_FUNCTION_TRACER kernel is slightly larger, but otherwise
|
||||
has native performance as long as no tracing is active.
|
||||
|
||||
The changes to the code are done by a kernel thread that
|
||||
@@ -195,3 +194,5 @@ config FTRACE_STARTUP_TEST
|
||||
a series of tests are made to verify that the tracer is
|
||||
functioning properly. It will do tests on all the configured
|
||||
tracers of ftrace.
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
# Do not instrument the tracer itself:
|
||||
|
||||
ifdef CONFIG_FTRACE
|
||||
ifdef CONFIG_FUNCTION_TRACER
|
||||
ORIG_CFLAGS := $(KBUILD_CFLAGS)
|
||||
KBUILD_CFLAGS = $(subst -pg,,$(ORIG_CFLAGS))
|
||||
|
||||
@@ -10,13 +10,13 @@ CFLAGS_trace_selftest_dynamic.o = -pg
|
||||
obj-y += trace_selftest_dynamic.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_FTRACE) += libftrace.o
|
||||
obj-$(CONFIG_FUNCTION_TRACER) += libftrace.o
|
||||
obj-$(CONFIG_RING_BUFFER) += ring_buffer.o
|
||||
|
||||
obj-$(CONFIG_TRACING) += trace.o
|
||||
obj-$(CONFIG_CONTEXT_SWITCH_TRACER) += trace_sched_switch.o
|
||||
obj-$(CONFIG_SYSPROF_TRACER) += trace_sysprof.o
|
||||
obj-$(CONFIG_FTRACE) += trace_functions.o
|
||||
obj-$(CONFIG_FUNCTION_TRACER) += trace_functions.o
|
||||
obj-$(CONFIG_IRQSOFF_TRACER) += trace_irqsoff.o
|
||||
obj-$(CONFIG_PREEMPT_TRACER) += trace_irqsoff.o
|
||||
obj-$(CONFIG_SCHED_TRACER) += trace_sched_wakeup.o
|
||||
|
||||
+92
-516
@@ -25,13 +25,24 @@
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/hash.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#include <asm/ftrace.h>
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
#define FTRACE_WARN_ON(cond) \
|
||||
do { \
|
||||
if (WARN_ON(cond)) \
|
||||
ftrace_kill(); \
|
||||
} while (0)
|
||||
|
||||
#define FTRACE_WARN_ON_ONCE(cond) \
|
||||
do { \
|
||||
if (WARN_ON_ONCE(cond)) \
|
||||
ftrace_kill(); \
|
||||
} while (0)
|
||||
|
||||
/* ftrace_enabled is a method to turn ftrace on or off */
|
||||
int ftrace_enabled __read_mostly;
|
||||
static int last_ftrace_enabled;
|
||||
@@ -153,21 +164,8 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
|
||||
#ifndef CONFIG_FTRACE_MCOUNT_RECORD
|
||||
/*
|
||||
* The hash lock is only needed when the recording of the mcount
|
||||
* callers are dynamic. That is, by the caller themselves and
|
||||
* not recorded via the compilation.
|
||||
*/
|
||||
static DEFINE_SPINLOCK(ftrace_hash_lock);
|
||||
#define ftrace_hash_lock(flags) spin_lock_irqsave(&ftrace_hash_lock, flags)
|
||||
#define ftrace_hash_unlock(flags) \
|
||||
spin_unlock_irqrestore(&ftrace_hash_lock, flags)
|
||||
#else
|
||||
/* This is protected via the ftrace_lock with MCOUNT_RECORD. */
|
||||
#define ftrace_hash_lock(flags) do { (void)(flags); } while (0)
|
||||
#define ftrace_hash_unlock(flags) do { } while(0)
|
||||
# error Dynamic ftrace depends on MCOUNT_RECORD
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -178,8 +176,6 @@ static DEFINE_SPINLOCK(ftrace_hash_lock);
|
||||
*/
|
||||
static unsigned long mcount_addr = MCOUNT_ADDR;
|
||||
|
||||
static struct task_struct *ftraced_task;
|
||||
|
||||
enum {
|
||||
FTRACE_ENABLE_CALLS = (1 << 0),
|
||||
FTRACE_DISABLE_CALLS = (1 << 1),
|
||||
@@ -190,13 +186,9 @@ enum {
|
||||
|
||||
static int ftrace_filtered;
|
||||
static int tracing_on;
|
||||
static int frozen_record_count;
|
||||
|
||||
static struct hlist_head ftrace_hash[FTRACE_HASHSIZE];
|
||||
static LIST_HEAD(ftrace_new_addrs);
|
||||
|
||||
static DEFINE_PER_CPU(int, ftrace_shutdown_disable_cpu);
|
||||
|
||||
static DEFINE_MUTEX(ftraced_lock);
|
||||
static DEFINE_MUTEX(ftrace_regex_lock);
|
||||
|
||||
struct ftrace_page {
|
||||
@@ -214,16 +206,13 @@ struct ftrace_page {
|
||||
static struct ftrace_page *ftrace_pages_start;
|
||||
static struct ftrace_page *ftrace_pages;
|
||||
|
||||
static int ftraced_trigger;
|
||||
static int ftraced_suspend;
|
||||
static int ftraced_stop;
|
||||
|
||||
static int ftrace_record_suspend;
|
||||
|
||||
static struct dyn_ftrace *ftrace_free_records;
|
||||
|
||||
|
||||
#ifdef CONFIG_KPROBES
|
||||
|
||||
static int frozen_record_count;
|
||||
|
||||
static inline void freeze_record(struct dyn_ftrace *rec)
|
||||
{
|
||||
if (!(rec->flags & FTRACE_FL_FROZEN)) {
|
||||
@@ -250,72 +239,6 @@ static inline int record_frozen(struct dyn_ftrace *rec)
|
||||
# define record_frozen(rec) ({ 0; })
|
||||
#endif /* CONFIG_KPROBES */
|
||||
|
||||
int skip_trace(unsigned long ip)
|
||||
{
|
||||
unsigned long fl;
|
||||
struct dyn_ftrace *rec;
|
||||
struct hlist_node *t;
|
||||
struct hlist_head *head;
|
||||
|
||||
if (frozen_record_count == 0)
|
||||
return 0;
|
||||
|
||||
head = &ftrace_hash[hash_long(ip, FTRACE_HASHBITS)];
|
||||
hlist_for_each_entry_rcu(rec, t, head, node) {
|
||||
if (rec->ip == ip) {
|
||||
if (record_frozen(rec)) {
|
||||
if (rec->flags & FTRACE_FL_FAILED)
|
||||
return 1;
|
||||
|
||||
if (!(rec->flags & FTRACE_FL_CONVERTED))
|
||||
return 1;
|
||||
|
||||
if (!tracing_on || !ftrace_enabled)
|
||||
return 1;
|
||||
|
||||
if (ftrace_filtered) {
|
||||
fl = rec->flags & (FTRACE_FL_FILTER |
|
||||
FTRACE_FL_NOTRACE);
|
||||
if (!fl || (fl & FTRACE_FL_NOTRACE))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
ftrace_ip_in_hash(unsigned long ip, unsigned long key)
|
||||
{
|
||||
struct dyn_ftrace *p;
|
||||
struct hlist_node *t;
|
||||
int found = 0;
|
||||
|
||||
hlist_for_each_entry_rcu(p, t, &ftrace_hash[key], node) {
|
||||
if (p->ip == ip) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ftrace_add_hash(struct dyn_ftrace *node, unsigned long key)
|
||||
{
|
||||
hlist_add_head_rcu(&node->node, &ftrace_hash[key]);
|
||||
}
|
||||
|
||||
/* called from kstop_machine */
|
||||
static inline void ftrace_del_hash(struct dyn_ftrace *node)
|
||||
{
|
||||
hlist_del(&node->node);
|
||||
}
|
||||
|
||||
static void ftrace_free_rec(struct dyn_ftrace *rec)
|
||||
{
|
||||
rec->ip = (unsigned long)ftrace_free_records;
|
||||
@@ -346,7 +269,6 @@ void ftrace_release(void *start, unsigned long size)
|
||||
}
|
||||
}
|
||||
spin_unlock(&ftrace_lock);
|
||||
|
||||
}
|
||||
|
||||
static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip)
|
||||
@@ -358,10 +280,8 @@ static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip)
|
||||
rec = ftrace_free_records;
|
||||
|
||||
if (unlikely(!(rec->flags & FTRACE_FL_FREE))) {
|
||||
WARN_ON_ONCE(1);
|
||||
FTRACE_WARN_ON_ONCE(1);
|
||||
ftrace_free_records = NULL;
|
||||
ftrace_disabled = 1;
|
||||
ftrace_enabled = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -371,76 +291,36 @@ static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip)
|
||||
}
|
||||
|
||||
if (ftrace_pages->index == ENTRIES_PER_PAGE) {
|
||||
if (!ftrace_pages->next)
|
||||
return NULL;
|
||||
if (!ftrace_pages->next) {
|
||||
/* allocate another page */
|
||||
ftrace_pages->next =
|
||||
(void *)get_zeroed_page(GFP_KERNEL);
|
||||
if (!ftrace_pages->next)
|
||||
return NULL;
|
||||
}
|
||||
ftrace_pages = ftrace_pages->next;
|
||||
}
|
||||
|
||||
return &ftrace_pages->records[ftrace_pages->index++];
|
||||
}
|
||||
|
||||
static void
|
||||
static struct dyn_ftrace *
|
||||
ftrace_record_ip(unsigned long ip)
|
||||
{
|
||||
struct dyn_ftrace *node;
|
||||
unsigned long flags;
|
||||
unsigned long key;
|
||||
int resched;
|
||||
int cpu;
|
||||
struct dyn_ftrace *rec;
|
||||
|
||||
if (!ftrace_enabled || ftrace_disabled)
|
||||
return;
|
||||
return NULL;
|
||||
|
||||
resched = need_resched();
|
||||
preempt_disable_notrace();
|
||||
rec = ftrace_alloc_dyn_node(ip);
|
||||
if (!rec)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* We simply need to protect against recursion.
|
||||
* Use the the raw version of smp_processor_id and not
|
||||
* __get_cpu_var which can call debug hooks that can
|
||||
* cause a recursive crash here.
|
||||
*/
|
||||
cpu = raw_smp_processor_id();
|
||||
per_cpu(ftrace_shutdown_disable_cpu, cpu)++;
|
||||
if (per_cpu(ftrace_shutdown_disable_cpu, cpu) != 1)
|
||||
goto out;
|
||||
rec->ip = ip;
|
||||
|
||||
if (unlikely(ftrace_record_suspend))
|
||||
goto out;
|
||||
list_add(&rec->list, &ftrace_new_addrs);
|
||||
|
||||
key = hash_long(ip, FTRACE_HASHBITS);
|
||||
|
||||
WARN_ON_ONCE(key >= FTRACE_HASHSIZE);
|
||||
|
||||
if (ftrace_ip_in_hash(ip, key))
|
||||
goto out;
|
||||
|
||||
ftrace_hash_lock(flags);
|
||||
|
||||
/* This ip may have hit the hash before the lock */
|
||||
if (ftrace_ip_in_hash(ip, key))
|
||||
goto out_unlock;
|
||||
|
||||
node = ftrace_alloc_dyn_node(ip);
|
||||
if (!node)
|
||||
goto out_unlock;
|
||||
|
||||
node->ip = ip;
|
||||
|
||||
ftrace_add_hash(node, key);
|
||||
|
||||
ftraced_trigger = 1;
|
||||
|
||||
out_unlock:
|
||||
ftrace_hash_unlock(flags);
|
||||
out:
|
||||
per_cpu(ftrace_shutdown_disable_cpu, cpu)--;
|
||||
|
||||
/* prevent recursion with scheduler */
|
||||
if (resched)
|
||||
preempt_enable_no_resched_notrace();
|
||||
else
|
||||
preempt_enable_notrace();
|
||||
return rec;
|
||||
}
|
||||
|
||||
#define FTRACE_ADDR ((long)(ftrace_caller))
|
||||
@@ -559,7 +439,6 @@ static void ftrace_replace_code(int enable)
|
||||
rec->flags |= FTRACE_FL_FAILED;
|
||||
if ((system_state == SYSTEM_BOOTING) ||
|
||||
!core_kernel_text(rec->ip)) {
|
||||
ftrace_del_hash(rec);
|
||||
ftrace_free_rec(rec);
|
||||
}
|
||||
}
|
||||
@@ -567,15 +446,6 @@ static void ftrace_replace_code(int enable)
|
||||
}
|
||||
}
|
||||
|
||||
static void ftrace_shutdown_replenish(void)
|
||||
{
|
||||
if (ftrace_pages->next)
|
||||
return;
|
||||
|
||||
/* allocate another page */
|
||||
ftrace_pages->next = (void *)get_zeroed_page(GFP_KERNEL);
|
||||
}
|
||||
|
||||
static void print_ip_ins(const char *fmt, unsigned char *p)
|
||||
{
|
||||
int i;
|
||||
@@ -591,23 +461,23 @@ ftrace_code_disable(struct dyn_ftrace *rec)
|
||||
{
|
||||
unsigned long ip;
|
||||
unsigned char *nop, *call;
|
||||
int failed;
|
||||
int ret;
|
||||
|
||||
ip = rec->ip;
|
||||
|
||||
nop = ftrace_nop_replace();
|
||||
call = ftrace_call_replace(ip, mcount_addr);
|
||||
|
||||
failed = ftrace_modify_code(ip, call, nop);
|
||||
if (failed) {
|
||||
switch (failed) {
|
||||
case 1:
|
||||
WARN_ON_ONCE(1);
|
||||
ret = ftrace_modify_code(ip, call, nop);
|
||||
if (ret) {
|
||||
switch (ret) {
|
||||
case -EFAULT:
|
||||
FTRACE_WARN_ON_ONCE(1);
|
||||
pr_info("ftrace faulted on modifying ");
|
||||
print_ip_sym(ip);
|
||||
break;
|
||||
case 2:
|
||||
WARN_ON_ONCE(1);
|
||||
case -EINVAL:
|
||||
FTRACE_WARN_ON_ONCE(1);
|
||||
pr_info("ftrace failed to modify ");
|
||||
print_ip_sym(ip);
|
||||
print_ip_ins(" expected: ", call);
|
||||
@@ -615,6 +485,15 @@ ftrace_code_disable(struct dyn_ftrace *rec)
|
||||
print_ip_ins(" replace: ", nop);
|
||||
printk(KERN_CONT "\n");
|
||||
break;
|
||||
case -EPERM:
|
||||
FTRACE_WARN_ON_ONCE(1);
|
||||
pr_info("ftrace faulted on writing ");
|
||||
print_ip_sym(ip);
|
||||
break;
|
||||
default:
|
||||
FTRACE_WARN_ON_ONCE(1);
|
||||
pr_info("ftrace faulted on unknown error ");
|
||||
print_ip_sym(ip);
|
||||
}
|
||||
|
||||
rec->flags |= FTRACE_FL_FAILED;
|
||||
@@ -623,19 +502,11 @@ ftrace_code_disable(struct dyn_ftrace *rec)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int __ftrace_update_code(void *ignore);
|
||||
|
||||
static int __ftrace_modify_code(void *data)
|
||||
{
|
||||
unsigned long addr;
|
||||
int *command = data;
|
||||
|
||||
if (*command & FTRACE_ENABLE_CALLS) {
|
||||
/*
|
||||
* Update any recorded ips now that we have the
|
||||
* machine stopped
|
||||
*/
|
||||
__ftrace_update_code(NULL);
|
||||
ftrace_replace_code(1);
|
||||
tracing_on = 1;
|
||||
} else if (*command & FTRACE_DISABLE_CALLS) {
|
||||
@@ -646,14 +517,6 @@ static int __ftrace_modify_code(void *data)
|
||||
if (*command & FTRACE_UPDATE_TRACE_FUNC)
|
||||
ftrace_update_ftrace_func(ftrace_trace_function);
|
||||
|
||||
if (*command & FTRACE_ENABLE_MCOUNT) {
|
||||
addr = (unsigned long)ftrace_record_ip;
|
||||
ftrace_mcount_set(&addr);
|
||||
} else if (*command & FTRACE_DISABLE_MCOUNT) {
|
||||
addr = (unsigned long)ftrace_stub;
|
||||
ftrace_mcount_set(&addr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -662,26 +525,9 @@ static void ftrace_run_update_code(int command)
|
||||
stop_machine(__ftrace_modify_code, &command, NULL);
|
||||
}
|
||||
|
||||
void ftrace_disable_daemon(void)
|
||||
{
|
||||
/* Stop the daemon from calling kstop_machine */
|
||||
mutex_lock(&ftraced_lock);
|
||||
ftraced_stop = 1;
|
||||
mutex_unlock(&ftraced_lock);
|
||||
|
||||
ftrace_force_update();
|
||||
}
|
||||
|
||||
void ftrace_enable_daemon(void)
|
||||
{
|
||||
mutex_lock(&ftraced_lock);
|
||||
ftraced_stop = 0;
|
||||
mutex_unlock(&ftraced_lock);
|
||||
|
||||
ftrace_force_update();
|
||||
}
|
||||
|
||||
static ftrace_func_t saved_ftrace_func;
|
||||
static int ftrace_start;
|
||||
static DEFINE_MUTEX(ftrace_start_lock);
|
||||
|
||||
static void ftrace_startup(void)
|
||||
{
|
||||
@@ -690,9 +536,9 @@ static void ftrace_startup(void)
|
||||
if (unlikely(ftrace_disabled))
|
||||
return;
|
||||
|
||||
mutex_lock(&ftraced_lock);
|
||||
ftraced_suspend++;
|
||||
if (ftraced_suspend == 1)
|
||||
mutex_lock(&ftrace_start_lock);
|
||||
ftrace_start++;
|
||||
if (ftrace_start == 1)
|
||||
command |= FTRACE_ENABLE_CALLS;
|
||||
|
||||
if (saved_ftrace_func != ftrace_trace_function) {
|
||||
@@ -705,7 +551,7 @@ static void ftrace_startup(void)
|
||||
|
||||
ftrace_run_update_code(command);
|
||||
out:
|
||||
mutex_unlock(&ftraced_lock);
|
||||
mutex_unlock(&ftrace_start_lock);
|
||||
}
|
||||
|
||||
static void ftrace_shutdown(void)
|
||||
@@ -715,9 +561,9 @@ static void ftrace_shutdown(void)
|
||||
if (unlikely(ftrace_disabled))
|
||||
return;
|
||||
|
||||
mutex_lock(&ftraced_lock);
|
||||
ftraced_suspend--;
|
||||
if (!ftraced_suspend)
|
||||
mutex_lock(&ftrace_start_lock);
|
||||
ftrace_start--;
|
||||
if (!ftrace_start)
|
||||
command |= FTRACE_DISABLE_CALLS;
|
||||
|
||||
if (saved_ftrace_func != ftrace_trace_function) {
|
||||
@@ -730,7 +576,7 @@ static void ftrace_shutdown(void)
|
||||
|
||||
ftrace_run_update_code(command);
|
||||
out:
|
||||
mutex_unlock(&ftraced_lock);
|
||||
mutex_unlock(&ftrace_start_lock);
|
||||
}
|
||||
|
||||
static void ftrace_startup_sysctl(void)
|
||||
@@ -740,15 +586,15 @@ static void ftrace_startup_sysctl(void)
|
||||
if (unlikely(ftrace_disabled))
|
||||
return;
|
||||
|
||||
mutex_lock(&ftraced_lock);
|
||||
mutex_lock(&ftrace_start_lock);
|
||||
/* Force update next time */
|
||||
saved_ftrace_func = NULL;
|
||||
/* ftraced_suspend is true if we want ftrace running */
|
||||
if (ftraced_suspend)
|
||||
/* ftrace_start is true if we want ftrace running */
|
||||
if (ftrace_start)
|
||||
command |= FTRACE_ENABLE_CALLS;
|
||||
|
||||
ftrace_run_update_code(command);
|
||||
mutex_unlock(&ftraced_lock);
|
||||
mutex_unlock(&ftrace_start_lock);
|
||||
}
|
||||
|
||||
static void ftrace_shutdown_sysctl(void)
|
||||
@@ -758,112 +604,50 @@ static void ftrace_shutdown_sysctl(void)
|
||||
if (unlikely(ftrace_disabled))
|
||||
return;
|
||||
|
||||
mutex_lock(&ftraced_lock);
|
||||
/* ftraced_suspend is true if ftrace is running */
|
||||
if (ftraced_suspend)
|
||||
mutex_lock(&ftrace_start_lock);
|
||||
/* ftrace_start is true if ftrace is running */
|
||||
if (ftrace_start)
|
||||
command |= FTRACE_DISABLE_CALLS;
|
||||
|
||||
ftrace_run_update_code(command);
|
||||
mutex_unlock(&ftraced_lock);
|
||||
mutex_unlock(&ftrace_start_lock);
|
||||
}
|
||||
|
||||
static cycle_t ftrace_update_time;
|
||||
static unsigned long ftrace_update_cnt;
|
||||
unsigned long ftrace_update_tot_cnt;
|
||||
|
||||
static int __ftrace_update_code(void *ignore)
|
||||
static int ftrace_update_code(void)
|
||||
{
|
||||
int i, save_ftrace_enabled;
|
||||
struct dyn_ftrace *p, *t;
|
||||
cycle_t start, stop;
|
||||
struct dyn_ftrace *p;
|
||||
struct hlist_node *t, *n;
|
||||
struct hlist_head *head, temp_list;
|
||||
|
||||
/* Don't be recording funcs now */
|
||||
ftrace_record_suspend++;
|
||||
save_ftrace_enabled = ftrace_enabled;
|
||||
ftrace_enabled = 0;
|
||||
|
||||
start = ftrace_now(raw_smp_processor_id());
|
||||
ftrace_update_cnt = 0;
|
||||
|
||||
/* No locks needed, the machine is stopped! */
|
||||
for (i = 0; i < FTRACE_HASHSIZE; i++) {
|
||||
INIT_HLIST_HEAD(&temp_list);
|
||||
head = &ftrace_hash[i];
|
||||
list_for_each_entry_safe(p, t, &ftrace_new_addrs, list) {
|
||||
|
||||
/* all CPUS are stopped, we are safe to modify code */
|
||||
hlist_for_each_entry_safe(p, t, n, head, node) {
|
||||
/* Skip over failed records which have not been
|
||||
* freed. */
|
||||
if (p->flags & FTRACE_FL_FAILED)
|
||||
continue;
|
||||
/* If something went wrong, bail without enabling anything */
|
||||
if (unlikely(ftrace_disabled))
|
||||
return -1;
|
||||
|
||||
/* Unconverted records are always at the head of the
|
||||
* hash bucket. Once we encounter a converted record,
|
||||
* simply skip over to the next bucket. Saves ftraced
|
||||
* some processor cycles (ftrace does its bid for
|
||||
* global warming :-p ). */
|
||||
if (p->flags & (FTRACE_FL_CONVERTED))
|
||||
break;
|
||||
list_del_init(&p->list);
|
||||
|
||||
/* Ignore updates to this record's mcount site.
|
||||
* Reintroduce this record at the head of this
|
||||
* bucket to attempt to "convert" it again if
|
||||
* the kprobe on it is unregistered before the
|
||||
* next run. */
|
||||
if (get_kprobe((void *)p->ip)) {
|
||||
ftrace_del_hash(p);
|
||||
INIT_HLIST_NODE(&p->node);
|
||||
hlist_add_head(&p->node, &temp_list);
|
||||
freeze_record(p);
|
||||
continue;
|
||||
} else {
|
||||
unfreeze_record(p);
|
||||
}
|
||||
|
||||
/* convert record (i.e, patch mcount-call with NOP) */
|
||||
if (ftrace_code_disable(p)) {
|
||||
p->flags |= FTRACE_FL_CONVERTED;
|
||||
ftrace_update_cnt++;
|
||||
} else {
|
||||
if ((system_state == SYSTEM_BOOTING) ||
|
||||
!core_kernel_text(p->ip)) {
|
||||
ftrace_del_hash(p);
|
||||
ftrace_free_rec(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hlist_for_each_entry_safe(p, t, n, &temp_list, node) {
|
||||
hlist_del(&p->node);
|
||||
INIT_HLIST_NODE(&p->node);
|
||||
hlist_add_head(&p->node, head);
|
||||
}
|
||||
/* convert record (i.e, patch mcount-call with NOP) */
|
||||
if (ftrace_code_disable(p)) {
|
||||
p->flags |= FTRACE_FL_CONVERTED;
|
||||
ftrace_update_cnt++;
|
||||
} else
|
||||
ftrace_free_rec(p);
|
||||
}
|
||||
|
||||
stop = ftrace_now(raw_smp_processor_id());
|
||||
ftrace_update_time = stop - start;
|
||||
ftrace_update_tot_cnt += ftrace_update_cnt;
|
||||
ftraced_trigger = 0;
|
||||
|
||||
ftrace_enabled = save_ftrace_enabled;
|
||||
ftrace_record_suspend--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ftrace_update_code(void)
|
||||
{
|
||||
if (unlikely(ftrace_disabled) ||
|
||||
!ftrace_enabled || !ftraced_trigger)
|
||||
return 0;
|
||||
|
||||
stop_machine(__ftrace_update_code, NULL, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int __init ftrace_dyn_table_alloc(unsigned long num_to_init)
|
||||
{
|
||||
struct ftrace_page *pg;
|
||||
@@ -892,7 +676,7 @@ static int __init ftrace_dyn_table_alloc(unsigned long num_to_init)
|
||||
pg = ftrace_pages = ftrace_pages_start;
|
||||
|
||||
cnt = num_to_init / ENTRIES_PER_PAGE;
|
||||
pr_info("ftrace: allocating %ld hash entries in %d pages\n",
|
||||
pr_info("ftrace: allocating %ld entries in %d pages\n",
|
||||
num_to_init, cnt);
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
@@ -1401,10 +1185,10 @@ ftrace_regex_release(struct inode *inode, struct file *file, int enable)
|
||||
}
|
||||
|
||||
mutex_lock(&ftrace_sysctl_lock);
|
||||
mutex_lock(&ftraced_lock);
|
||||
if (iter->filtered && ftraced_suspend && ftrace_enabled)
|
||||
mutex_lock(&ftrace_start_lock);
|
||||
if (iter->filtered && ftrace_start && ftrace_enabled)
|
||||
ftrace_run_update_code(FTRACE_ENABLE_CALLS);
|
||||
mutex_unlock(&ftraced_lock);
|
||||
mutex_unlock(&ftrace_start_lock);
|
||||
mutex_unlock(&ftrace_sysctl_lock);
|
||||
|
||||
kfree(iter);
|
||||
@@ -1424,55 +1208,6 @@ ftrace_notrace_release(struct inode *inode, struct file *file)
|
||||
return ftrace_regex_release(inode, file, 0);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ftraced_read(struct file *filp, char __user *ubuf,
|
||||
size_t cnt, loff_t *ppos)
|
||||
{
|
||||
/* don't worry about races */
|
||||
char *buf = ftraced_stop ? "disabled\n" : "enabled\n";
|
||||
int r = strlen(buf);
|
||||
|
||||
return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ftraced_write(struct file *filp, const char __user *ubuf,
|
||||
size_t cnt, loff_t *ppos)
|
||||
{
|
||||
char buf[64];
|
||||
long val;
|
||||
int ret;
|
||||
|
||||
if (cnt >= sizeof(buf))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&buf, ubuf, cnt))
|
||||
return -EFAULT;
|
||||
|
||||
if (strncmp(buf, "enable", 6) == 0)
|
||||
val = 1;
|
||||
else if (strncmp(buf, "disable", 7) == 0)
|
||||
val = 0;
|
||||
else {
|
||||
buf[cnt] = 0;
|
||||
|
||||
ret = strict_strtoul(buf, 10, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val = !!val;
|
||||
}
|
||||
|
||||
if (val)
|
||||
ftrace_enable_daemon();
|
||||
else
|
||||
ftrace_disable_daemon();
|
||||
|
||||
filp->f_pos += cnt;
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static struct file_operations ftrace_avail_fops = {
|
||||
.open = ftrace_avail_open,
|
||||
.read = seq_read,
|
||||
@@ -1503,54 +1238,6 @@ static struct file_operations ftrace_notrace_fops = {
|
||||
.release = ftrace_notrace_release,
|
||||
};
|
||||
|
||||
static struct file_operations ftraced_fops = {
|
||||
.open = tracing_open_generic,
|
||||
.read = ftraced_read,
|
||||
.write = ftraced_write,
|
||||
};
|
||||
|
||||
/**
|
||||
* ftrace_force_update - force an update to all recording ftrace functions
|
||||
*/
|
||||
int ftrace_force_update(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely(ftrace_disabled))
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&ftrace_sysctl_lock);
|
||||
mutex_lock(&ftraced_lock);
|
||||
|
||||
/*
|
||||
* If ftraced_trigger is not set, then there is nothing
|
||||
* to update.
|
||||
*/
|
||||
if (ftraced_trigger && !ftrace_update_code())
|
||||
ret = -EBUSY;
|
||||
|
||||
mutex_unlock(&ftraced_lock);
|
||||
mutex_unlock(&ftrace_sysctl_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ftrace_force_shutdown(void)
|
||||
{
|
||||
struct task_struct *task;
|
||||
int command = FTRACE_DISABLE_CALLS | FTRACE_UPDATE_TRACE_FUNC;
|
||||
|
||||
mutex_lock(&ftraced_lock);
|
||||
task = ftraced_task;
|
||||
ftraced_task = NULL;
|
||||
ftraced_suspend = -1;
|
||||
ftrace_run_update_code(command);
|
||||
mutex_unlock(&ftraced_lock);
|
||||
|
||||
if (task)
|
||||
kthread_stop(task);
|
||||
}
|
||||
|
||||
static __init int ftrace_init_debugfs(void)
|
||||
{
|
||||
struct dentry *d_tracer;
|
||||
@@ -1581,17 +1268,11 @@ static __init int ftrace_init_debugfs(void)
|
||||
pr_warning("Could not create debugfs "
|
||||
"'set_ftrace_notrace' entry\n");
|
||||
|
||||
entry = debugfs_create_file("ftraced_enabled", 0644, d_tracer,
|
||||
NULL, &ftraced_fops);
|
||||
if (!entry)
|
||||
pr_warning("Could not create debugfs "
|
||||
"'ftraced_enabled' entry\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
fs_initcall(ftrace_init_debugfs);
|
||||
|
||||
#ifdef CONFIG_FTRACE_MCOUNT_RECORD
|
||||
static int ftrace_convert_nops(unsigned long *start,
|
||||
unsigned long *end)
|
||||
{
|
||||
@@ -1599,20 +1280,18 @@ static int ftrace_convert_nops(unsigned long *start,
|
||||
unsigned long addr;
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&ftrace_start_lock);
|
||||
p = start;
|
||||
while (p < end) {
|
||||
addr = ftrace_call_adjust(*p++);
|
||||
/* should not be called from interrupt context */
|
||||
spin_lock(&ftrace_lock);
|
||||
ftrace_record_ip(addr);
|
||||
spin_unlock(&ftrace_lock);
|
||||
ftrace_shutdown_replenish();
|
||||
}
|
||||
|
||||
/* p is ignored */
|
||||
/* disable interrupts to prevent kstop machine */
|
||||
local_irq_save(flags);
|
||||
__ftrace_update_code(p);
|
||||
ftrace_update_code();
|
||||
local_irq_restore(flags);
|
||||
mutex_unlock(&ftrace_start_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1658,130 +1337,26 @@ void __init ftrace_init(void)
|
||||
failed:
|
||||
ftrace_disabled = 1;
|
||||
}
|
||||
#else /* CONFIG_FTRACE_MCOUNT_RECORD */
|
||||
static int ftraced(void *ignore)
|
||||
{
|
||||
unsigned long usecs;
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
||||
/* check once a second */
|
||||
schedule_timeout(HZ);
|
||||
|
||||
if (unlikely(ftrace_disabled))
|
||||
continue;
|
||||
|
||||
mutex_lock(&ftrace_sysctl_lock);
|
||||
mutex_lock(&ftraced_lock);
|
||||
if (!ftraced_suspend && !ftraced_stop &&
|
||||
ftrace_update_code()) {
|
||||
usecs = nsecs_to_usecs(ftrace_update_time);
|
||||
if (ftrace_update_tot_cnt > 100000) {
|
||||
ftrace_update_tot_cnt = 0;
|
||||
pr_info("hm, dftrace overflow: %lu change%s"
|
||||
" (%lu total) in %lu usec%s\n",
|
||||
ftrace_update_cnt,
|
||||
ftrace_update_cnt != 1 ? "s" : "",
|
||||
ftrace_update_tot_cnt,
|
||||
usecs, usecs != 1 ? "s" : "");
|
||||
ftrace_disabled = 1;
|
||||
WARN_ON_ONCE(1);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&ftraced_lock);
|
||||
mutex_unlock(&ftrace_sysctl_lock);
|
||||
|
||||
ftrace_shutdown_replenish();
|
||||
}
|
||||
__set_current_state(TASK_RUNNING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init ftrace_dynamic_init(void)
|
||||
{
|
||||
struct task_struct *p;
|
||||
unsigned long addr;
|
||||
int ret;
|
||||
|
||||
addr = (unsigned long)ftrace_record_ip;
|
||||
|
||||
stop_machine(ftrace_dyn_arch_init, &addr, NULL);
|
||||
|
||||
/* ftrace_dyn_arch_init places the return code in addr */
|
||||
if (addr) {
|
||||
ret = (int)addr;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
ret = ftrace_dyn_table_alloc(NR_TO_INIT);
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
||||
p = kthread_run(ftraced, NULL, "ftraced");
|
||||
if (IS_ERR(p)) {
|
||||
ret = -1;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
last_ftrace_enabled = ftrace_enabled = 1;
|
||||
ftraced_task = p;
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
ftrace_disabled = 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
core_initcall(ftrace_dynamic_init);
|
||||
#endif /* CONFIG_FTRACE_MCOUNT_RECORD */
|
||||
|
||||
#else
|
||||
# define ftrace_startup() do { } while (0)
|
||||
# define ftrace_shutdown() do { } while (0)
|
||||
# define ftrace_startup_sysctl() do { } while (0)
|
||||
# define ftrace_shutdown_sysctl() do { } while (0)
|
||||
# define ftrace_force_shutdown() do { } while (0)
|
||||
#endif /* CONFIG_DYNAMIC_FTRACE */
|
||||
|
||||
/**
|
||||
* ftrace_kill_atomic - kill ftrace from critical sections
|
||||
* ftrace_kill - kill ftrace
|
||||
*
|
||||
* This function should be used by panic code. It stops ftrace
|
||||
* but in a not so nice way. If you need to simply kill ftrace
|
||||
* from a non-atomic section, use ftrace_kill.
|
||||
*/
|
||||
void ftrace_kill_atomic(void)
|
||||
{
|
||||
ftrace_disabled = 1;
|
||||
ftrace_enabled = 0;
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
ftraced_suspend = -1;
|
||||
#endif
|
||||
clear_ftrace_function();
|
||||
}
|
||||
|
||||
/**
|
||||
* ftrace_kill - totally shutdown ftrace
|
||||
*
|
||||
* This is a safety measure. If something was detected that seems
|
||||
* wrong, calling this function will keep ftrace from doing
|
||||
* any more modifications, and updates.
|
||||
* used when something went wrong.
|
||||
*/
|
||||
void ftrace_kill(void)
|
||||
{
|
||||
mutex_lock(&ftrace_sysctl_lock);
|
||||
ftrace_disabled = 1;
|
||||
ftrace_enabled = 0;
|
||||
|
||||
clear_ftrace_function();
|
||||
mutex_unlock(&ftrace_sysctl_lock);
|
||||
|
||||
/* Try to totally disable ftrace */
|
||||
ftrace_force_shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1870,3 +1445,4 @@ ftrace_enable_sysctl(struct ctl_table *table, int write,
|
||||
mutex_unlock(&ftrace_sysctl_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ struct buffer_page {
|
||||
static inline void free_buffer_page(struct buffer_page *bpage)
|
||||
{
|
||||
if (bpage->page)
|
||||
__free_page(bpage->page);
|
||||
free_page((unsigned long)bpage->page);
|
||||
kfree(bpage);
|
||||
}
|
||||
|
||||
@@ -966,7 +966,9 @@ rb_add_time_stamp(struct ring_buffer_per_cpu *cpu_buffer,
|
||||
if (unlikely(*delta > (1ULL << 59) && !once++)) {
|
||||
printk(KERN_WARNING "Delta way too big! %llu"
|
||||
" ts=%llu write stamp = %llu\n",
|
||||
*delta, *ts, cpu_buffer->write_stamp);
|
||||
(unsigned long long)*delta,
|
||||
(unsigned long long)*ts,
|
||||
(unsigned long long)cpu_buffer->write_stamp);
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#include <linux/stacktrace.h>
|
||||
#include <linux/ring_buffer.h>
|
||||
#include <linux/irqflags.h>
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
@@ -851,7 +852,7 @@ ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3)
|
||||
preempt_enable_notrace();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FTRACE
|
||||
#ifdef CONFIG_FUNCTION_TRACER
|
||||
static void
|
||||
function_trace_call(unsigned long ip, unsigned long parent_ip)
|
||||
{
|
||||
@@ -865,9 +866,6 @@ function_trace_call(unsigned long ip, unsigned long parent_ip)
|
||||
if (unlikely(!ftrace_function_enabled))
|
||||
return;
|
||||
|
||||
if (skip_trace(ip))
|
||||
return;
|
||||
|
||||
pc = preempt_count();
|
||||
resched = need_resched();
|
||||
preempt_disable_notrace();
|
||||
@@ -2379,9 +2377,10 @@ tracing_set_trace_write(struct file *filp, const char __user *ubuf,
|
||||
int i;
|
||||
size_t ret;
|
||||
|
||||
ret = cnt;
|
||||
|
||||
if (cnt > max_tracer_type_len)
|
||||
cnt = max_tracer_type_len;
|
||||
ret = cnt;
|
||||
|
||||
if (copy_from_user(&buf, ubuf, cnt))
|
||||
return -EFAULT;
|
||||
@@ -2414,8 +2413,8 @@ tracing_set_trace_write(struct file *filp, const char __user *ubuf,
|
||||
out:
|
||||
mutex_unlock(&trace_types_lock);
|
||||
|
||||
if (ret == cnt)
|
||||
filp->f_pos += cnt;
|
||||
if (ret > 0)
|
||||
filp->f_pos += ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -3097,7 +3096,7 @@ void ftrace_dump(void)
|
||||
dump_ran = 1;
|
||||
|
||||
/* No turning back! */
|
||||
ftrace_kill_atomic();
|
||||
ftrace_kill();
|
||||
|
||||
for_each_tracing_cpu(cpu) {
|
||||
atomic_inc(&global_trace.data[cpu]->disabled);
|
||||
|
||||
@@ -335,7 +335,7 @@ void update_max_tr_single(struct trace_array *tr,
|
||||
|
||||
extern cycle_t ftrace_now(int cpu);
|
||||
|
||||
#ifdef CONFIG_FTRACE
|
||||
#ifdef CONFIG_FUNCTION_TRACER
|
||||
void tracing_start_function_trace(void);
|
||||
void tracing_stop_function_trace(void);
|
||||
#else
|
||||
|
||||
@@ -64,7 +64,7 @@ static void function_trace_ctrl_update(struct trace_array *tr)
|
||||
|
||||
static struct tracer function_trace __read_mostly =
|
||||
{
|
||||
.name = "ftrace",
|
||||
.name = "function",
|
||||
.init = function_trace_init,
|
||||
.reset = function_trace_reset,
|
||||
.ctrl_update = function_trace_ctrl_update,
|
||||
|
||||
@@ -63,7 +63,7 @@ irq_trace(void)
|
||||
*/
|
||||
static __cacheline_aligned_in_smp unsigned long max_sequence;
|
||||
|
||||
#ifdef CONFIG_FTRACE
|
||||
#ifdef CONFIG_FUNCTION_TRACER
|
||||
/*
|
||||
* irqsoff uses its own tracer function to keep the overhead down:
|
||||
*/
|
||||
@@ -104,7 +104,7 @@ static struct ftrace_ops trace_ops __read_mostly =
|
||||
{
|
||||
.func = irqsoff_tracer_call,
|
||||
};
|
||||
#endif /* CONFIG_FTRACE */
|
||||
#endif /* CONFIG_FUNCTION_TRACER */
|
||||
|
||||
/*
|
||||
* Should this new latency be reported/recorded?
|
||||
|
||||
@@ -31,7 +31,7 @@ static raw_spinlock_t wakeup_lock =
|
||||
|
||||
static void __wakeup_reset(struct trace_array *tr);
|
||||
|
||||
#ifdef CONFIG_FTRACE
|
||||
#ifdef CONFIG_FUNCTION_TRACER
|
||||
/*
|
||||
* irqsoff uses its own tracer function to keep the overhead down:
|
||||
*/
|
||||
@@ -96,7 +96,7 @@ static struct ftrace_ops trace_ops __read_mostly =
|
||||
{
|
||||
.func = wakeup_tracer_call,
|
||||
};
|
||||
#endif /* CONFIG_FTRACE */
|
||||
#endif /* CONFIG_FUNCTION_TRACER */
|
||||
|
||||
/*
|
||||
* Should this new latency be reported/recorded?
|
||||
|
||||
@@ -70,7 +70,7 @@ static int trace_test_buffer(struct trace_array *tr, unsigned long *count)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FTRACE
|
||||
#ifdef CONFIG_FUNCTION_TRACER
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
|
||||
@@ -99,13 +99,6 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
|
||||
/* passed in by parameter to fool gcc from optimizing */
|
||||
func();
|
||||
|
||||
/* update the records */
|
||||
ret = ftrace_force_update();
|
||||
if (ret) {
|
||||
printk(KERN_CONT ".. ftraced failed .. ");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some archs *cough*PowerPC*cough* add charachters to the
|
||||
* start of the function names. We simply put a '*' to
|
||||
@@ -183,13 +176,6 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr)
|
||||
/* make sure msleep has been recorded */
|
||||
msleep(1);
|
||||
|
||||
/* force the recorded functions to be traced */
|
||||
ret = ftrace_force_update();
|
||||
if (ret) {
|
||||
printk(KERN_CONT ".. ftraced failed .. ");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* start the tracing */
|
||||
ftrace_enabled = 1;
|
||||
tracer_enabled = 1;
|
||||
@@ -226,7 +212,7 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr)
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_FTRACE */
|
||||
#endif /* CONFIG_FUNCTION_TRACER */
|
||||
|
||||
#ifdef CONFIG_IRQSOFF_TRACER
|
||||
int
|
||||
|
||||
@@ -44,6 +44,10 @@ static inline void check_stack(void)
|
||||
if (this_size <= max_stack_size)
|
||||
return;
|
||||
|
||||
/* we do not handle interrupt stacks yet */
|
||||
if (!object_is_on_stack(&this_size))
|
||||
return;
|
||||
|
||||
raw_local_irq_save(flags);
|
||||
__raw_spin_lock(&max_stack_lock);
|
||||
|
||||
|
||||
@@ -131,6 +131,9 @@ tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe)
|
||||
|
||||
old = entry->funcs;
|
||||
|
||||
if (!old)
|
||||
return NULL;
|
||||
|
||||
debug_print_probes(entry);
|
||||
/* (N -> M), (N > 1, M >= 0) probes */
|
||||
for (nr_probes = 0; old[nr_probes]; nr_probes++) {
|
||||
@@ -388,6 +391,11 @@ int tracepoint_probe_unregister(const char *name, void *probe)
|
||||
if (entry->rcu_pending)
|
||||
rcu_barrier_sched();
|
||||
old = tracepoint_entry_remove_probe(entry, probe);
|
||||
if (!old) {
|
||||
printk(KERN_WARNING "Warning: Trying to unregister a probe"
|
||||
"that doesn't exist\n");
|
||||
goto end;
|
||||
}
|
||||
mutex_unlock(&tracepoints_mutex);
|
||||
tracepoint_update_probes(); /* may update entry */
|
||||
mutex_lock(&tracepoints_mutex);
|
||||
|
||||
Reference in New Issue
Block a user