Commit e46b4e2b authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'trace-v4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace

Pull tracing updates from Steven Rostedt:
 "Nothing major this round.  Mostly small clean ups and fixes.

  Some visible changes:

   - A new flag was added to distinguish traces done in NMI context.

   - Preempt tracer now shows functions where preemption is disabled but
     interrupts are still enabled.

  Other notes:

   - Updates were done to function tracing to allow better performance
     with perf.

   - Infrastructure code has been added to allow for a new histogram
     feature for recording live trace event histograms that can be
     configured by simple user commands.  The feature itself was just
     finished, but needs a round in linux-next before being pulled.

     This only includes some infrastructure changes that will be needed"

* tag 'trace-v4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: (22 commits)
  tracing: Record and show NMI state
  tracing: Fix trace_printk() to print when not using bprintk()
  tracing: Remove redundant reset per-CPU buff in irqsoff tracer
  x86: ftrace: Fix the misleading comment for arch/x86/kernel/ftrace.c
  tracing: Fix crash from reading trace_pipe with sendfile
  tracing: Have preempt(irqs)off trace preempt disabled functions
  tracing: Fix return while holding a lock in register_tracer()
  ftrace: Use kasprintf() in ftrace_profile_tracefs()
  ftrace: Update dynamic ftrace calls only if necessary
  ftrace: Make ftrace_hash_rec_enable return update bool
  tracing: Fix typoes in code comment and printk in trace_nop.c
  tracing, writeback: Replace cgroup path to cgroup ino
  tracing: Use flags instead of bool in trigger structure
  tracing: Add an unreg_all() callback to trigger commands
  tracing: Add needs_rec flag to event triggers
  tracing: Add a per-event-trigger 'paused' field
  tracing: Add get_syscall_name()
  tracing: Add event record param to trigger_ops.func()
  tracing: Make event trigger functions available
  tracing: Make ftrace_event_field checking functions available
  ...
parents faea72dd 7e6867bf
/* /*
* Code for replacing ftrace calls with jumps. * Dynamic function tracing support.
* *
* Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com> * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
* *
......
...@@ -618,7 +618,7 @@ do { \ ...@@ -618,7 +618,7 @@ do { \
#define do_trace_printk(fmt, args...) \ #define do_trace_printk(fmt, args...) \
do { \ do { \
static const char *trace_printk_fmt \ static const char *trace_printk_fmt __used \
__attribute__((section("__trace_printk_fmt"))) = \ __attribute__((section("__trace_printk_fmt"))) = \
__builtin_constant_p(fmt) ? fmt : NULL; \ __builtin_constant_p(fmt) ? fmt : NULL; \
\ \
...@@ -662,7 +662,7 @@ int __trace_printk(unsigned long ip, const char *fmt, ...); ...@@ -662,7 +662,7 @@ int __trace_printk(unsigned long ip, const char *fmt, ...);
*/ */
#define trace_puts(str) ({ \ #define trace_puts(str) ({ \
static const char *trace_printk_fmt \ static const char *trace_printk_fmt __used \
__attribute__((section("__trace_printk_fmt"))) = \ __attribute__((section("__trace_printk_fmt"))) = \
__builtin_constant_p(str) ? str : NULL; \ __builtin_constant_p(str) ? str : NULL; \
\ \
...@@ -684,7 +684,7 @@ extern void trace_dump_stack(int skip); ...@@ -684,7 +684,7 @@ extern void trace_dump_stack(int skip);
#define ftrace_vprintk(fmt, vargs) \ #define ftrace_vprintk(fmt, vargs) \
do { \ do { \
if (__builtin_constant_p(fmt)) { \ if (__builtin_constant_p(fmt)) { \
static const char *trace_printk_fmt \ static const char *trace_printk_fmt __used \
__attribute__((section("__trace_printk_fmt"))) = \ __attribute__((section("__trace_printk_fmt"))) = \
__builtin_constant_p(fmt) ? fmt : NULL; \ __builtin_constant_p(fmt) ? fmt : NULL; \
\ \
......
...@@ -420,7 +420,8 @@ extern int call_filter_check_discard(struct trace_event_call *call, void *rec, ...@@ -420,7 +420,8 @@ extern int call_filter_check_discard(struct trace_event_call *call, void *rec,
extern enum event_trigger_type event_triggers_call(struct trace_event_file *file, extern enum event_trigger_type event_triggers_call(struct trace_event_file *file,
void *rec); void *rec);
extern void event_triggers_post_call(struct trace_event_file *file, extern void event_triggers_post_call(struct trace_event_file *file,
enum event_trigger_type tt); enum event_trigger_type tt,
void *rec);
bool trace_event_ignore_this_pid(struct trace_event_file *trace_file); bool trace_event_ignore_this_pid(struct trace_event_file *trace_file);
...@@ -507,7 +508,7 @@ event_trigger_unlock_commit(struct trace_event_file *file, ...@@ -507,7 +508,7 @@ event_trigger_unlock_commit(struct trace_event_file *file,
trace_buffer_unlock_commit(file->tr, buffer, event, irq_flags, pc); trace_buffer_unlock_commit(file->tr, buffer, event, irq_flags, pc);
if (tt) if (tt)
event_triggers_post_call(file, tt); event_triggers_post_call(file, tt, entry);
} }
/** /**
...@@ -540,7 +541,7 @@ event_trigger_unlock_commit_regs(struct trace_event_file *file, ...@@ -540,7 +541,7 @@ event_trigger_unlock_commit_regs(struct trace_event_file *file,
irq_flags, pc, regs); irq_flags, pc, regs);
if (tt) if (tt)
event_triggers_post_call(file, tt); event_triggers_post_call(file, tt, entry);
} }
#ifdef CONFIG_BPF_EVENTS #ifdef CONFIG_BPF_EVENTS
......
...@@ -140,42 +140,19 @@ DEFINE_EVENT(kmem_free, kfree, ...@@ -140,42 +140,19 @@ DEFINE_EVENT(kmem_free, kfree,
TP_ARGS(call_site, ptr) TP_ARGS(call_site, ptr)
); );
DEFINE_EVENT_CONDITION(kmem_free, kmem_cache_free, DEFINE_EVENT(kmem_free, kmem_cache_free,
TP_PROTO(unsigned long call_site, const void *ptr), TP_PROTO(unsigned long call_site, const void *ptr),
TP_ARGS(call_site, ptr), TP_ARGS(call_site, ptr)
/*
* This trace can be potentially called from an offlined cpu.
* Since trace points use RCU and RCU should not be used from
* offline cpus, filter such calls out.
* While this trace can be called from a preemptable section,
* it has no impact on the condition since tasks can migrate
* only from online cpus to other online cpus. Thus its safe
* to use raw_smp_processor_id.
*/
TP_CONDITION(cpu_online(raw_smp_processor_id()))
); );
TRACE_EVENT_CONDITION(mm_page_free, TRACE_EVENT(mm_page_free,
TP_PROTO(struct page *page, unsigned int order), TP_PROTO(struct page *page, unsigned int order),
TP_ARGS(page, order), TP_ARGS(page, order),
/*
* This trace can be potentially called from an offlined cpu.
* Since trace points use RCU and RCU should not be used from
* offline cpus, filter such calls out.
* While this trace can be called from a preemptable section,
* it has no impact on the condition since tasks can migrate
* only from online cpus to other online cpus. Thus its safe
* to use raw_smp_processor_id.
*/
TP_CONDITION(cpu_online(raw_smp_processor_id())),
TP_STRUCT__entry( TP_STRUCT__entry(
__field( unsigned long, pfn ) __field( unsigned long, pfn )
__field( unsigned int, order ) __field( unsigned int, order )
...@@ -276,23 +253,12 @@ DEFINE_EVENT(mm_page, mm_page_alloc_zone_locked, ...@@ -276,23 +253,12 @@ DEFINE_EVENT(mm_page, mm_page_alloc_zone_locked,
TP_ARGS(page, order, migratetype) TP_ARGS(page, order, migratetype)
); );
TRACE_EVENT_CONDITION(mm_page_pcpu_drain, TRACE_EVENT(mm_page_pcpu_drain,
TP_PROTO(struct page *page, unsigned int order, int migratetype), TP_PROTO(struct page *page, unsigned int order, int migratetype),
TP_ARGS(page, order, migratetype), TP_ARGS(page, order, migratetype),
/*
* This trace can be potentially called from an offlined cpu.
* Since trace points use RCU and RCU should not be used from
* offline cpus, filter such calls out.
* While this trace can be called from a preemptable section,
* it has no impact on the condition since tasks can migrate
* only from online cpus to other online cpus. Thus its safe
* to use raw_smp_processor_id.
*/
TP_CONDITION(cpu_online(raw_smp_processor_id())),
TP_STRUCT__entry( TP_STRUCT__entry(
__field( unsigned long, pfn ) __field( unsigned long, pfn )
__field( unsigned int, order ) __field( unsigned int, order )
......
...@@ -34,13 +34,11 @@ TLB_FLUSH_REASON ...@@ -34,13 +34,11 @@ TLB_FLUSH_REASON
#define EM(a,b) { a, b }, #define EM(a,b) { a, b },
#define EMe(a,b) { a, b } #define EMe(a,b) { a, b }
TRACE_EVENT_CONDITION(tlb_flush, TRACE_EVENT(tlb_flush,
TP_PROTO(int reason, unsigned long pages), TP_PROTO(int reason, unsigned long pages),
TP_ARGS(reason, pages), TP_ARGS(reason, pages),
TP_CONDITION(cpu_online(smp_processor_id())),
TP_STRUCT__entry( TP_STRUCT__entry(
__field( int, reason) __field( int, reason)
__field(unsigned long, pages) __field(unsigned long, pages)
......
This diff is collapsed.
...@@ -1030,8 +1030,7 @@ static __init void ftrace_profile_tracefs(struct dentry *d_tracer) ...@@ -1030,8 +1030,7 @@ static __init void ftrace_profile_tracefs(struct dentry *d_tracer)
for_each_possible_cpu(cpu) { for_each_possible_cpu(cpu) {
stat = &per_cpu(ftrace_profile_stats, cpu); stat = &per_cpu(ftrace_profile_stats, cpu);
/* allocate enough for function name + cpu number */ name = kasprintf(GFP_KERNEL, "function%d", cpu);
name = kmalloc(32, GFP_KERNEL);
if (!name) { if (!name) {
/* /*
* The files created are permanent, if something happens * The files created are permanent, if something happens
...@@ -1043,7 +1042,6 @@ static __init void ftrace_profile_tracefs(struct dentry *d_tracer) ...@@ -1043,7 +1042,6 @@ static __init void ftrace_profile_tracefs(struct dentry *d_tracer)
return; return;
} }
stat->stat = function_stats; stat->stat = function_stats;
snprintf(name, 32, "function%d", cpu);
stat->stat.name = name; stat->stat.name = name;
ret = register_stat_tracer(&stat->stat); ret = register_stat_tracer(&stat->stat);
if (ret) { if (ret) {
...@@ -1609,7 +1607,7 @@ static bool test_rec_ops_needs_regs(struct dyn_ftrace *rec) ...@@ -1609,7 +1607,7 @@ static bool test_rec_ops_needs_regs(struct dyn_ftrace *rec)
return keep_regs; return keep_regs;
} }
static void __ftrace_hash_rec_update(struct ftrace_ops *ops, static bool __ftrace_hash_rec_update(struct ftrace_ops *ops,
int filter_hash, int filter_hash,
bool inc) bool inc)
{ {
...@@ -1617,12 +1615,13 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, ...@@ -1617,12 +1615,13 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
struct ftrace_hash *other_hash; struct ftrace_hash *other_hash;
struct ftrace_page *pg; struct ftrace_page *pg;
struct dyn_ftrace *rec; struct dyn_ftrace *rec;
bool update = false;
int count = 0; int count = 0;
int all = 0; int all = 0;
/* Only update if the ops has been registered */ /* Only update if the ops has been registered */
if (!(ops->flags & FTRACE_OPS_FL_ENABLED)) if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
return; return false;
/* /*
* In the filter_hash case: * In the filter_hash case:
...@@ -1649,7 +1648,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, ...@@ -1649,7 +1648,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
* then there's nothing to do. * then there's nothing to do.
*/ */
if (ftrace_hash_empty(hash)) if (ftrace_hash_empty(hash))
return; return false;
} }
do_for_each_ftrace_rec(pg, rec) { do_for_each_ftrace_rec(pg, rec) {
...@@ -1693,7 +1692,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, ...@@ -1693,7 +1692,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
if (inc) { if (inc) {
rec->flags++; rec->flags++;
if (FTRACE_WARN_ON(ftrace_rec_count(rec) == FTRACE_REF_MAX)) if (FTRACE_WARN_ON(ftrace_rec_count(rec) == FTRACE_REF_MAX))
return; return false;
/* /*
* If there's only a single callback registered to a * If there's only a single callback registered to a
...@@ -1719,7 +1718,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, ...@@ -1719,7 +1718,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
rec->flags |= FTRACE_FL_REGS; rec->flags |= FTRACE_FL_REGS;
} else { } else {
if (FTRACE_WARN_ON(ftrace_rec_count(rec) == 0)) if (FTRACE_WARN_ON(ftrace_rec_count(rec) == 0))
return; return false;
rec->flags--; rec->flags--;
/* /*
...@@ -1752,22 +1751,28 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, ...@@ -1752,22 +1751,28 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
*/ */
} }
count++; count++;
/* Must match FTRACE_UPDATE_CALLS in ftrace_modify_all_code() */
update |= ftrace_test_record(rec, 1) != FTRACE_UPDATE_IGNORE;
/* Shortcut, if we handled all records, we are done. */ /* Shortcut, if we handled all records, we are done. */
if (!all && count == hash->count) if (!all && count == hash->count)
return; return update;
} while_for_each_ftrace_rec(); } while_for_each_ftrace_rec();
return update;
} }
static void ftrace_hash_rec_disable(struct ftrace_ops *ops, static bool ftrace_hash_rec_disable(struct ftrace_ops *ops,
int filter_hash) int filter_hash)
{ {
__ftrace_hash_rec_update(ops, filter_hash, 0); return __ftrace_hash_rec_update(ops, filter_hash, 0);
} }
static void ftrace_hash_rec_enable(struct ftrace_ops *ops, static bool ftrace_hash_rec_enable(struct ftrace_ops *ops,
int filter_hash) int filter_hash)
{ {
__ftrace_hash_rec_update(ops, filter_hash, 1); return __ftrace_hash_rec_update(ops, filter_hash, 1);
} }
static void ftrace_hash_rec_update_modify(struct ftrace_ops *ops, static void ftrace_hash_rec_update_modify(struct ftrace_ops *ops,
...@@ -2643,7 +2648,6 @@ static int ftrace_startup(struct ftrace_ops *ops, int command) ...@@ -2643,7 +2648,6 @@ static int ftrace_startup(struct ftrace_ops *ops, int command)
return ret; return ret;
ftrace_start_up++; ftrace_start_up++;
command |= FTRACE_UPDATE_CALLS;
/* /*
* Note that ftrace probes uses this to start up * Note that ftrace probes uses this to start up
...@@ -2664,7 +2668,8 @@ static int ftrace_startup(struct ftrace_ops *ops, int command) ...@@ -2664,7 +2668,8 @@ static int ftrace_startup(struct ftrace_ops *ops, int command)
return ret; return ret;
} }
ftrace_hash_rec_enable(ops, 1); if (ftrace_hash_rec_enable(ops, 1))
command |= FTRACE_UPDATE_CALLS;
ftrace_startup_enable(command); ftrace_startup_enable(command);
...@@ -2694,11 +2699,11 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int command) ...@@ -2694,11 +2699,11 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int command)
/* Disabling ipmodify never fails */ /* Disabling ipmodify never fails */
ftrace_hash_ipmodify_disable(ops); ftrace_hash_ipmodify_disable(ops);
ftrace_hash_rec_disable(ops, 1);
ops->flags &= ~FTRACE_OPS_FL_ENABLED; if (ftrace_hash_rec_disable(ops, 1))
command |= FTRACE_UPDATE_CALLS;
command |= FTRACE_UPDATE_CALLS; ops->flags &= ~FTRACE_OPS_FL_ENABLED;
if (saved_ftrace_func != ftrace_trace_function) { if (saved_ftrace_func != ftrace_trace_function) {
saved_ftrace_func = ftrace_trace_function; saved_ftrace_func = ftrace_trace_function;
......
...@@ -74,11 +74,6 @@ static struct tracer_opt dummy_tracer_opt[] = { ...@@ -74,11 +74,6 @@ static struct tracer_opt dummy_tracer_opt[] = {
{ } { }
}; };
static struct tracer_flags dummy_tracer_flags = {
.val = 0,
.opts = dummy_tracer_opt
};
static int static int
dummy_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set) dummy_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
{ {
...@@ -1258,12 +1253,22 @@ int __init register_tracer(struct tracer *type) ...@@ -1258,12 +1253,22 @@ int __init register_tracer(struct tracer *type)
if (!type->set_flag) if (!type->set_flag)
type->set_flag = &dummy_set_flag; type->set_flag = &dummy_set_flag;
if (!type->flags) if (!type->flags) {
type->flags = &dummy_tracer_flags; /*allocate a dummy tracer_flags*/
else type->flags = kmalloc(sizeof(*type->flags), GFP_KERNEL);
if (!type->flags) {
ret = -ENOMEM;
goto out;
}
type->flags->val = 0;
type->flags->opts = dummy_tracer_opt;
} else
if (!type->flags->opts) if (!type->flags->opts)
type->flags->opts = dummy_tracer_opt; type->flags->opts = dummy_tracer_opt;
/* store the tracer for __set_tracer_option */
type->flags->trace = type;
ret = run_tracer_selftest(type); ret = run_tracer_selftest(type);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -1659,6 +1664,7 @@ tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags, ...@@ -1659,6 +1664,7 @@ tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags,
#else #else
TRACE_FLAG_IRQS_NOSUPPORT | TRACE_FLAG_IRQS_NOSUPPORT |
#endif #endif
((pc & NMI_MASK ) ? TRACE_FLAG_NMI : 0) |
((pc & HARDIRQ_MASK) ? TRACE_FLAG_HARDIRQ : 0) | ((pc & HARDIRQ_MASK) ? TRACE_FLAG_HARDIRQ : 0) |
((pc & SOFTIRQ_MASK) ? TRACE_FLAG_SOFTIRQ : 0) | ((pc & SOFTIRQ_MASK) ? TRACE_FLAG_SOFTIRQ : 0) |
(tif_need_resched() ? TRACE_FLAG_NEED_RESCHED : 0) | (tif_need_resched() ? TRACE_FLAG_NEED_RESCHED : 0) |
...@@ -3505,7 +3511,7 @@ static int __set_tracer_option(struct trace_array *tr, ...@@ -3505,7 +3511,7 @@ static int __set_tracer_option(struct trace_array *tr,
struct tracer_flags *tracer_flags, struct tracer_flags *tracer_flags,
struct tracer_opt *opts, int neg) struct tracer_opt *opts, int neg)
{ {
struct tracer *trace = tr->current_trace; struct tracer *trace = tracer_flags->trace;
int ret; int ret;
ret = trace->set_flag(tr, tracer_flags->val, opts->bit, !neg); ret = trace->set_flag(tr, tracer_flags->val, opts->bit, !neg);
...@@ -4949,7 +4955,10 @@ static ssize_t tracing_splice_read_pipe(struct file *filp, ...@@ -4949,7 +4955,10 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
spd.nr_pages = i; spd.nr_pages = i;
ret = splice_to_pipe(pipe, &spd); if (i)
ret = splice_to_pipe(pipe, &spd);
else
ret = 0;
out: out:
splice_shrink_spd(&spd); splice_shrink_spd(&spd);
return ret; return ret;
...@@ -6391,11 +6400,8 @@ create_trace_option_files(struct trace_array *tr, struct tracer *tracer) ...@@ -6391,11 +6400,8 @@ create_trace_option_files(struct trace_array *tr, struct tracer *tracer)
return; return;
for (i = 0; i < tr->nr_topts; i++) { for (i = 0; i < tr->nr_topts; i++) {
/* /* Make sure there's no duplicate flags. */
* Check if these flags have already been added. if (WARN_ON_ONCE(tr->topts[i].tracer->flags == tracer->flags))
* Some tracers share flags.
*/
if (tr->topts[i].tracer->flags == tracer->flags)
return; return;
} }
......
...@@ -125,6 +125,7 @@ enum trace_flag_type { ...@@ -125,6 +125,7 @@ enum trace_flag_type {
TRACE_FLAG_HARDIRQ = 0x08, TRACE_FLAG_HARDIRQ = 0x08,
TRACE_FLAG_SOFTIRQ = 0x10, TRACE_FLAG_SOFTIRQ = 0x10,
TRACE_FLAG_PREEMPT_RESCHED = 0x20, TRACE_FLAG_PREEMPT_RESCHED = 0x20,
TRACE_FLAG_NMI = 0x40,
}; };
#define TRACE_BUF_SIZE 1024 #define TRACE_BUF_SIZE 1024
...@@ -345,6 +346,7 @@ struct tracer_opt { ...@@ -345,6 +346,7 @@ struct tracer_opt {
struct tracer_flags { struct tracer_flags {
u32 val; u32 val;
struct tracer_opt *opts; struct tracer_opt *opts;
struct tracer *trace;
}; };
/* Makes more easy to define a tracer opt */ /* Makes more easy to define a tracer opt */
...@@ -1111,6 +1113,18 @@ struct filter_pred { ...@@ -1111,6 +1113,18 @@ struct filter_pred {
unsigned short right; unsigned short right;
}; };
static inline bool is_string_field(struct ftrace_event_field *field)
{
return field->filter_type == FILTER_DYN_STRING ||
field->filter_type == FILTER_STATIC_STRING ||
field->filter_type == FILTER_PTR_STRING;
}
static inline bool is_function_field(struct ftrace_event_field *field)
{
return field->filter_type == FILTER_TRACE_FN;
}
extern enum regex_type extern enum regex_type
filter_parse_regex(char *buff, int len, char **search, int *not); filter_parse_regex(char *buff, int len, char **search, int *not);
extern void print_event_filter(struct trace_event_file *file, extern void print_event_filter(struct trace_event_file *file,
...@@ -1159,9 +1173,24 @@ struct event_trigger_data { ...@@ -1159,9 +1173,24 @@ struct event_trigger_data {
struct event_filter __rcu *filter; struct event_filter __rcu *filter;
char *filter_str; char *filter_str;
void *private_data; void *private_data;
bool paused;
struct list_head list; struct list_head list;
}; };
extern void trigger_data_free(struct event_trigger_data *data);
extern int event_trigger_init(struct event_trigger_ops *ops,
struct event_trigger_data *data);
extern int trace_event_trigger_enable_disable(struct trace_event_file *file,
int trigger_enable);
extern void update_cond_flag(struct trace_event_file *file);
extern void unregister_trigger(char *glob, struct event_trigger_ops *ops,
struct event_trigger_data *test,
struct trace_event_file *file);
extern int set_trigger_filter(char *filter_str,
struct event_trigger_data *trigger_data,
struct trace_event_file *file);
extern int register_event_command(struct event_command *cmd);
/** /**
* struct event_trigger_ops - callbacks for trace event triggers * struct event_trigger_ops - callbacks for trace event triggers
* *
...@@ -1174,7 +1203,8 @@ struct event_trigger_data { ...@@ -1174,7 +1203,8 @@ struct event_trigger_data {
* @func: The trigger 'probe' function called when the triggering * @func: The trigger 'probe' function called when the triggering
* event occurs. The data passed into this callback is the data * event occurs. The data passed into this callback is the data
* that was supplied to the event_command @reg() function that * that was supplied to the event_command @reg() function that
* registered the trigger (see struct event_command). * registered the trigger (see struct event_command) along with
* the trace record, rec.
* *
* @init: An optional initialization function called for the trigger * @init: An optional initialization function called for the trigger
* when the trigger is registered (via the event_command reg() * when the trigger is registered (via the event_command reg()
...@@ -1199,7 +1229,8 @@ struct event_trigger_data { ...@@ -1199,7 +1229,8 @@ struct event_trigger_data {
* (see trace_event_triggers.c). * (see trace_event_triggers.c).
*/ */
struct event_trigger_ops { struct event_trigger_ops {
void (*func)(struct event_trigger_data *data); void (*func)(struct event_trigger_data *data,
void *rec);
int (*init)(struct event_trigger_ops *ops, int (*init)(struct event_trigger_ops *ops,
struct event_trigger_data *data); struct event_trigger_data *data);
void (*free)(struct event_trigger_ops *ops, void (*free)(struct event_trigger_ops *ops,
...@@ -1243,27 +1274,10 @@ struct event_trigger_ops { ...@@ -1243,27 +1274,10 @@ struct event_trigger_ops {
* values are defined by adding new values to the trigger_type * values are defined by adding new values to the trigger_type
* enum in include/linux/trace_events.h. * enum in include/linux/trace_events.h.
* *
* @post_trigger: A flag that says whether or not this command needs * @flags: See the enum event_command_flags below.
* to have its action delayed until after the current event has
* been closed. Some triggers need to avoid being invoked while
* an event is currently in the process of being logged, since
* the trigger may itself log data into the trace buffer. Thus
* we make sure the current event is committed before invoking
* those triggers. To do that, the trigger invocation is split
* in two - the first part checks the filter using the current
* trace record; if a command has the @post_trigger flag set, it
* sets a bit for itself in the return value, otherwise it
* directly invokes the trigger. Once all commands have been
* either invoked or set their return flag, the current record is
* either committed or discarded. At that point, if any commands
* have deferred their triggers, those commands are finally
* invoked following the close of the current event. In other
* words, if the event_trigger_ops @func() probe implementation
* itself logs to the trace buffer, this flag should be set,
* otherwise it can be left unspecified.
* *
* All the methods below, except for @set_filter(), must be * All the methods below, except for @set_filter() and @unreg_all(),
* implemented. * must be implemented.
* *
* @func: The callback function responsible for parsing and * @func: The callback function responsible for parsing and
* registering the trigger written to the 'trigger' file by the * registering the trigger written to the 'trigger' file by the
...@@ -1288,6 +1302,10 @@ struct event_trigger_ops { ...@@ -1288,6 +1302,10 @@ struct event_trigger_ops {
* This is usually implemented by the generic utility function * This is usually implemented by the generic utility function
* @unregister_trigger() (see trace_event_triggers.c). * @unregister_trigger() (see trace_event_triggers.c).
* *
* @unreg_all: An optional function called to remove all the triggers
* from the list of triggers associated with the event. Called
* when a trigger file is opened in truncate mode.
*
* @set_filter: An optional function called to parse and set a filter * @set_filter: An optional function called to parse and set a filter
* for the trigger. If no @set_filter() method is set for the * for the trigger. If no @set_filter() method is set for the
* event command, filters set by the user for the command will be * event command, filters set by the user for the command will be
...@@ -1301,7 +1319,7 @@ struct event_command { ...@@ -1301,7 +1319,7 @@ struct event_command {
struct list_head list; struct list_head list;
char *name; char *name;
enum event_trigger_type trigger_type; enum event_trigger_type trigger_type;
bool post_trigger; int flags;
int (*func)(struct event_command *cmd_ops, int (*func)(struct event_command *cmd_ops,
struct trace_event_file *file, struct trace_event_file *file,
char *glob, char *cmd, char *params); char *glob, char *cmd, char *params);
...@@ -1313,12 +1331,56 @@ struct event_command { ...@@ -1313,12 +1331,56 @@ struct event_command {
struct event_trigger_ops *ops, struct event_trigger_ops *ops,
struct event_trigger_data *data, struct event_trigger_data *data,
struct trace_event_file *file); struct trace_event_file *file);
void (*unreg_all)(struct trace_event_file *file);
int (*set_filter)(char *filter_str, int (*set_filter)(char *filter_str,
struct event_trigger_data *data, struct event_trigger_data *data,
struct trace_event_file *file); struct trace_event_file *file);
struct event_trigger_ops *(*get_trigger_ops)(char *cmd, char *param); struct event_trigger_ops *(*get_trigger_ops)(char *cmd, char *param);
}; };
/**
* enum event_command_flags - flags for struct event_command
*
* @POST_TRIGGER: A flag that says whether or not this command needs
* to have its action delayed until after the current event has
* been closed. Some triggers need to avoid being invoked while
* an event is currently in the process of being logged, since
* the trigger may itself log data into the trace buffer. Thus
* we make sure the current event is committed before invoking
* those triggers. To do that, the trigger invocation is split
* in two - the first part checks the filter using the current
* trace record; if a command has the @post_trigger flag set, it
* sets a bit for itself in the return value, otherwise it
* directly invokes the trigger. Once all commands have been
* either invoked or set their return flag, the current record is
* either committed or discarded. At that point, if any commands
* have deferred their triggers, those commands are finally
* invoked following the close of the current event. In other
* words, if the event_trigger_ops @func() probe implementation
* itself logs to the trace buffer, this flag should be set,
* otherwise it can be left unspecified.
*
* @NEEDS_REC: A flag that says whether or not this command needs
* access to the trace record in order to perform its function,
* regardless of whether or not it has a filter associated with
* it (filters make a trigger require access to the trace record
* but are not always present).
*/
enum event_command_flags {
EVENT_CMD_FL_POST_TRIGGER = 1,
EVENT_CMD_FL_NEEDS_REC = 2,
};
static inline bool event_command_post_trigger(struct event_command *cmd_ops)
{
return cmd_ops->flags & EVENT_CMD_FL_POST_TRIGGER;
}
static inline bool event_command_needs_rec(struct event_command *cmd_ops)
{
return cmd_ops->flags & EVENT_CMD_FL_NEEDS_REC;
}
extern int trace_event_enable_disable(struct trace_event_file *file, extern int trace_event_enable_disable(struct trace_event_file *file,
int enable, int soft_disable); int enable, int soft_disable);
extern int tracing_alloc_snapshot(void); extern int tracing_alloc_snapshot(void);
...@@ -1365,8 +1427,13 @@ int perf_ftrace_event_register(struct trace_event_call *call, ...@@ -1365,8 +1427,13 @@ int perf_ftrace_event_register(struct trace_event_call *call,
#ifdef CONFIG_FTRACE_SYSCALLS #ifdef CONFIG_FTRACE_SYSCALLS
void init_ftrace_syscalls(void); void init_ftrace_syscalls(void);
const char *get_syscall_name(int syscall);
#else #else
static inline void init_ftrace_syscalls(void) { } static inline void init_ftrace_syscalls(void) { }
static inline const char *get_syscall_name(int syscall)
{
return NULL;
}
#endif #endif
#ifdef CONFIG_EVENT_TRACING #ifdef CONFIG_EVENT_TRACING
......
...@@ -961,18 +961,6 @@ int filter_assign_type(const char *type) ...@@ -961,18 +961,6 @@ int filter_assign_type(const char *type)
return FILTER_OTHER; return FILTER_OTHER;
} }
static bool is_function_field(struct ftrace_event_field *field)
{
return field->filter_type == FILTER_TRACE_FN;
}
static bool is_string_field(struct ftrace_event_field *field)
{
return field->filter_type == FILTER_DYN_STRING ||
field->filter_type == FILTER_STATIC_STRING ||
field->filter_type == FILTER_PTR_STRING;
}
static bool is_legal_op(struct ftrace_event_field *field, int op) static bool is_legal_op(struct ftrace_event_field *field, int op)
{ {
if (is_string_field(field) && if (is_string_field(field) &&
......
...@@ -28,8 +28,7 @@ ...@@ -28,8 +28,7 @@
static LIST_HEAD(trigger_commands); static LIST_HEAD(trigger_commands);
static DEFINE_MUTEX(trigger_cmd_mutex); static DEFINE_MUTEX(trigger_cmd_mutex);
static void void trigger_data_free(struct event_trigger_data *data)
trigger_data_free(struct event_trigger_data *data)
{ {
if (data->cmd_ops->set_filter) if (data->cmd_ops->set_filter)
data->cmd_ops->set_filter(NULL, data, NULL); data->cmd_ops->set_filter(NULL, data, NULL);
...@@ -73,18 +72,20 @@ event_triggers_call(struct trace_event_file *file, void *rec) ...@@ -73,18 +72,20 @@ event_triggers_call(struct trace_event_file *file, void *rec)
return tt; return tt;
list_for_each_entry_rcu(data, &file->triggers, list) { list_for_each_entry_rcu(data, &file->triggers, list) {
if (data->paused)
continue;
if (!rec) { if (!rec) {
data->ops->func(data); data->ops->func(data, rec);
continue; continue;
} }
filter = rcu_dereference_sched(data->filter); filter = rcu_dereference_sched(data->filter);
if (filter && !filter_match_preds(filter, rec)) if (filter && !filter_match_preds(filter, rec))
continue; continue;
if (data->cmd_ops->post_trigger) { if (event_command_post_trigger(data->cmd_ops)) {
tt |= data->cmd_ops->trigger_type; tt |= data->cmd_ops->trigger_type;
continue; continue;
} }
data->ops->func(data); data->ops->func(data, rec);
} }
return tt; return tt;
} }
...@@ -94,6 +95,7 @@ EXPORT_SYMBOL_GPL(event_triggers_call); ...@@ -94,6 +95,7 @@ EXPORT_SYMBOL_GPL(event_triggers_call);
* event_triggers_post_call - Call 'post_triggers' for a trace event * event_triggers_post_call - Call 'post_triggers' for a trace event
* @file: The trace_event_file associated with the event * @file: The trace_event_file associated with the event
* @tt: enum event_trigger_type containing a set bit for each trigger to invoke * @tt: enum event_trigger_type containing a set bit for each trigger to invoke
* @rec: The trace entry for the event
* *
* For each trigger associated with an event, invoke the trigger * For each trigger associated with an event, invoke the trigger
* function registered with the associated trigger command, if the * function registered with the associated trigger command, if the
...@@ -104,13 +106,16 @@ EXPORT_SYMBOL_GPL(event_triggers_call); ...@@ -104,13 +106,16 @@ EXPORT_SYMBOL_GPL(event_triggers_call);
*/ */
void void
event_triggers_post_call(struct trace_event_file *file, event_triggers_post_call(struct trace_event_file *file,
enum event_trigger_type tt) enum event_trigger_type tt,
void *rec)
{ {
struct event_trigger_data *data; struct event_trigger_data *data;
list_for_each_entry_rcu(data, &file->triggers, list) { list_for_each_entry_rcu(data, &file->triggers, list) {
if (data->paused)
continue;
if (data->cmd_ops->trigger_type & tt) if (data->cmd_ops->trigger_type & tt)
data->ops->func(data); data->ops->func(data, rec);
} }
} }
EXPORT_SYMBOL_GPL(event_triggers_post_call); EXPORT_SYMBOL_GPL(event_triggers_post_call);
...@@ -188,6 +193,19 @@ static int event_trigger_regex_open(struct inode *inode, struct file *file) ...@@ -188,6 +193,19 @@ static int event_trigger_regex_open(struct inode *inode, struct file *file)
return -ENODEV; return -ENODEV;
} }
if ((file->f_mode & FMODE_WRITE) &&
(file->f_flags & O_TRUNC)) {
struct trace_event_file *event_file;
struct event_command *p;
event_file = event_file_data(file);
list_for_each_entry(p, &trigger_commands, list) {
if (p->unreg_all)
p->unreg_all(event_file);
}
}
if (file->f_mode & FMODE_READ) { if (file->f_mode & FMODE_READ) {
ret = seq_open(file, &event_triggers_seq_ops); ret = seq_open(file, &event_triggers_seq_ops);
if (!ret) { if (!ret) {
...@@ -306,7 +324,7 @@ const struct file_operations event_trigger_fops = { ...@@ -306,7 +324,7 @@ const struct file_operations event_trigger_fops = {
* Currently we only register event commands from __init, so mark this * Currently we only register event commands from __init, so mark this
* __init too. * __init too.
*/ */
static __init int register_event_command(struct event_command *cmd) __init int register_event_command(struct event_command *cmd)
{ {
struct event_command *p; struct event_command *p;
int ret = 0; int ret = 0;
...@@ -395,9 +413,8 @@ event_trigger_print(const char *name, struct seq_file *m, ...@@ -395,9 +413,8 @@ event_trigger_print(const char *name, struct seq_file *m,
* *
* Return: 0 on success, errno otherwise * Return: 0 on success, errno otherwise
*/ */
static int int event_trigger_init(struct event_trigger_ops *ops,
event_trigger_init(struct event_trigger_ops *ops, struct event_trigger_data *data)
struct event_trigger_data *data)
{ {
data->ref++; data->ref++;
return 0; return 0;
...@@ -425,8 +442,8 @@ event_trigger_free(struct event_trigger_ops *ops, ...@@ -425,8 +442,8 @@ event_trigger_free(struct event_trigger_ops *ops,
trigger_data_free(data); trigger_data_free(data);
} }
static int trace_event_trigger_enable_disable(struct trace_event_file *file, int trace_event_trigger_enable_disable(struct trace_event_file *file,
int trigger_enable) int trigger_enable)
{ {
int ret = 0; int ret = 0;
...@@ -483,13 +500,14 @@ clear_event_triggers(struct trace_array *tr) ...@@ -483,13 +500,14 @@ clear_event_triggers(struct trace_array *tr)
* its TRIGGER_COND bit set, otherwise the TRIGGER_COND bit should be * its TRIGGER_COND bit set, otherwise the TRIGGER_COND bit should be
* cleared. * cleared.
*/ */
static void update_cond_flag(struct trace_event_file *file) void update_cond_flag(struct trace_event_file *file)
{ {
struct event_trigger_data *data; struct event_trigger_data *data;
bool set_cond = false; bool set_cond = false;
list_for_each_entry_rcu(data, &file->triggers, list) { list_for_each_entry_rcu(data, &file->triggers, list) {
if (data->filter || data->cmd_ops->post_trigger) { if (data->filter || event_command_post_trigger(data->cmd_ops) ||
event_command_needs_rec(data->cmd_ops)) {
set_cond = true; set_cond = true;
break; break;
} }
...@@ -560,9 +578,9 @@ static int register_trigger(char *glob, struct event_trigger_ops *ops, ...@@ -560,9 +578,9 @@ static int register_trigger(char *glob, struct event_trigger_ops *ops,
* Usually used directly as the @unreg method in event command * Usually used directly as the @unreg method in event command
* implementations. * implementations.
*/ */
static void unregister_trigger(char *glob, struct event_trigger_ops *ops, void unregister_trigger(char *glob, struct event_trigger_ops *ops,
struct event_trigger_data *test, struct event_trigger_data *test,
struct trace_event_file *file) struct trace_event_file *file)
{ {
struct event_trigger_data *data; struct event_trigger_data *data;
bool unregistered = false; bool unregistered = false;
...@@ -696,9 +714,9 @@ event_trigger_callback(struct event_command *cmd_ops, ...@@ -696,9 +714,9 @@ event_trigger_callback(struct event_command *cmd_ops,
* *
* Return: 0 on success, errno otherwise * Return: 0 on success, errno otherwise
*/ */
static int set_trigger_filter(char *filter_str, int set_trigger_filter(char *filter_str,
struct event_trigger_data *trigger_data, struct event_trigger_data *trigger_data,
struct trace_event_file *file) struct trace_event_file *file)
{ {
struct event_trigger_data *data = trigger_data; struct event_trigger_data *data = trigger_data;
struct event_filter *filter = NULL, *tmp; struct event_filter *filter = NULL, *tmp;
...@@ -747,7 +765,7 @@ static int set_trigger_filter(char *filter_str, ...@@ -747,7 +765,7 @@ static int set_trigger_filter(char *filter_str,
} }
static void static void
traceon_trigger(struct event_trigger_data *data) traceon_trigger(struct event_trigger_data *data, void *rec)
{ {
if (tracing_is_on()) if (tracing_is_on())
return; return;
...@@ -756,7 +774,7 @@ traceon_trigger(struct event_trigger_data *data) ...@@ -756,7 +774,7 @@ traceon_trigger(struct event_trigger_data *data)
} }
static void static void
traceon_count_trigger(struct event_trigger_data *data) traceon_count_trigger(struct event_trigger_data *data, void *rec)
{ {
if (tracing_is_on()) if (tracing_is_on())
return; return;
...@@ -771,7 +789,7 @@ traceon_count_trigger(struct event_trigger_data *data) ...@@ -771,7 +789,7 @@ traceon_count_trigger(struct event_trigger_data *data)
} }
static void static void
traceoff_trigger(struct event_trigger_data *data) traceoff_trigger(struct event_trigger_data *data, void *rec)
{ {
if (!tracing_is_on()) if (!tracing_is_on())
return; return;
...@@ -780,7 +798,7 @@ traceoff_trigger(struct event_trigger_data *data) ...@@ -780,7 +798,7 @@ traceoff_trigger(struct event_trigger_data *data)
} }
static void static void
traceoff_count_trigger(struct event_trigger_data *data) traceoff_count_trigger(struct event_trigger_data *data, void *rec)
{ {
if (!tracing_is_on()) if (!tracing_is_on())
return; return;
...@@ -876,13 +894,13 @@ static struct event_command trigger_traceoff_cmd = { ...@@ -876,13 +894,13 @@ static struct event_command trigger_traceoff_cmd = {
#ifdef CONFIG_TRACER_SNAPSHOT #ifdef CONFIG_TRACER_SNAPSHOT
static void static void
snapshot_trigger(struct event_trigger_data *data) snapshot_trigger(struct event_trigger_data *data, void *rec)
{ {
tracing_snapshot(); tracing_snapshot();
} }
static void static void
snapshot_count_trigger(struct event_trigger_data *data) snapshot_count_trigger(struct event_trigger_data *data, void *rec)
{ {
if (!data->count) if (!data->count)
return; return;
...@@ -890,7 +908,7 @@ snapshot_count_trigger(struct event_trigger_data *data) ...@@ -890,7 +908,7 @@ snapshot_count_trigger(struct event_trigger_data *data)
if (data->count != -1) if (data->count != -1)
(data->count)--; (data->count)--;
snapshot_trigger(data); snapshot_trigger(data, rec);
} }
static int static int
...@@ -969,13 +987,13 @@ static __init int register_trigger_snapshot_cmd(void) { return 0; } ...@@ -969,13 +987,13 @@ static __init int register_trigger_snapshot_cmd(void) { return 0; }
#define STACK_SKIP 3 #define STACK_SKIP 3
static void static void
stacktrace_trigger(struct event_trigger_data *data) stacktrace_trigger(struct event_trigger_data *data, void *rec)
{ {
trace_dump_stack(STACK_SKIP); trace_dump_stack(STACK_SKIP);
} }
static void static void
stacktrace_count_trigger(struct event_trigger_data *data) stacktrace_count_trigger(struct event_trigger_data *data, void *rec)
{ {
if (!data->count) if (!data->count)
return; return;
...@@ -983,7 +1001,7 @@ stacktrace_count_trigger(struct event_trigger_data *data) ...@@ -983,7 +1001,7 @@ stacktrace_count_trigger(struct event_trigger_data *data)
if (data->count != -1) if (data->count != -1)
(data->count)--; (data->count)--;
stacktrace_trigger(data); stacktrace_trigger(data, rec);
} }
static int static int
...@@ -1017,7 +1035,7 @@ stacktrace_get_trigger_ops(char *cmd, char *param) ...@@ -1017,7 +1035,7 @@ stacktrace_get_trigger_ops(char *cmd, char *param)
static struct event_command trigger_stacktrace_cmd = { static struct event_command trigger_stacktrace_cmd = {
.name = "stacktrace", .name = "stacktrace",
.trigger_type = ETT_STACKTRACE, .trigger_type = ETT_STACKTRACE,
.post_trigger = true, .flags = EVENT_CMD_FL_POST_TRIGGER,
.func = event_trigger_callback, .func = event_trigger_callback,
.reg = register_trigger, .reg = register_trigger,
.unreg = unregister_trigger, .unreg = unregister_trigger,
...@@ -1054,7 +1072,7 @@ struct enable_trigger_data { ...@@ -1054,7 +1072,7 @@ struct enable_trigger_data {
}; };
static void static void
event_enable_trigger(struct event_trigger_data *data) event_enable_trigger(struct event_trigger_data *data, void *rec)
{ {
struct enable_trigger_data *enable_data = data->private_data; struct enable_trigger_data *enable_data = data->private_data;
...@@ -1065,7 +1083,7 @@ event_enable_trigger(struct event_trigger_data *data) ...@@ -1065,7 +1083,7 @@ event_enable_trigger(struct event_trigger_data *data)
} }
static void static void
event_enable_count_trigger(struct event_trigger_data *data) event_enable_count_trigger(struct event_trigger_data *data, void *rec)
{ {
struct enable_trigger_data *enable_data = data->private_data; struct enable_trigger_data *enable_data = data->private_data;
...@@ -1079,7 +1097,7 @@ event_enable_count_trigger(struct event_trigger_data *data) ...@@ -1079,7 +1097,7 @@ event_enable_count_trigger(struct event_trigger_data *data)
if (data->count != -1) if (data->count != -1)
(data->count)--; (data->count)--;
event_enable_trigger(data); event_enable_trigger(data, rec);
} }
static int static int
......
...@@ -219,6 +219,8 @@ static void tracing_stop_function_trace(struct trace_array *tr) ...@@ -219,6 +219,8 @@ static void tracing_stop_function_trace(struct trace_array *tr)
unregister_ftrace_function(tr->ops); unregister_ftrace_function(tr->ops);
} }
static struct tracer function_trace;
static int static int
func_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set) func_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
{ {
...@@ -228,6 +230,10 @@ func_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set) ...@@ -228,6 +230,10 @@ func_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
if (!!set == !!(func_flags.val & TRACE_FUNC_OPT_STACK)) if (!!set == !!(func_flags.val & TRACE_FUNC_OPT_STACK))
break; break;
/* We can change this flag when not running. */
if (tr->current_trace != &function_trace)
break;
unregister_ftrace_function(tr->ops); unregister_ftrace_function(tr->ops);
if (set) { if (set) {
......
...@@ -109,8 +109,12 @@ static int func_prolog_dec(struct trace_array *tr, ...@@ -109,8 +109,12 @@ static int func_prolog_dec(struct trace_array *tr,
return 0; return 0;
local_save_flags(*flags); local_save_flags(*flags);
/* slight chance to get a false positive on tracing_cpu */ /*
if (!irqs_disabled_flags(*flags)) * Slight chance to get a false positive on tracing_cpu,
* although I'm starting to think there isn't a chance.
* Leave this for now just to be paranoid.
*/
if (!irqs_disabled_flags(*flags) && !preempt_count())
return 0; return 0;
*data = per_cpu_ptr(tr->trace_buffer.data, cpu); *data = per_cpu_ptr(tr->trace_buffer.data, cpu);
...@@ -622,7 +626,6 @@ static int __irqsoff_tracer_init(struct trace_array *tr) ...@@ -622,7 +626,6 @@ static int __irqsoff_tracer_init(struct trace_array *tr)
irqsoff_trace = tr; irqsoff_trace = tr;
/* make sure that the tracer is visible */ /* make sure that the tracer is visible */
smp_wmb(); smp_wmb();
tracing_reset_online_cpus(&tr->trace_buffer);
ftrace_init_array_ops(tr, irqsoff_tracer_call); ftrace_init_array_ops(tr, irqsoff_tracer_call);
......
...@@ -56,7 +56,7 @@ static void nop_trace_reset(struct trace_array *tr) ...@@ -56,7 +56,7 @@ static void nop_trace_reset(struct trace_array *tr)
} }
/* It only serves as a signal handler and a callback to /* It only serves as a signal handler and a callback to
* accept or refuse tthe setting of a flag. * accept or refuse the setting of a flag.
* If you don't implement it, then the flag setting will be * If you don't implement it, then the flag setting will be
* automatically accepted. * automatically accepted.
*/ */
...@@ -75,7 +75,7 @@ static int nop_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set) ...@@ -75,7 +75,7 @@ static int nop_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
if (bit == TRACE_NOP_OPT_REFUSE) { if (bit == TRACE_NOP_OPT_REFUSE) {
printk(KERN_DEBUG "nop_test_refuse flag set to %d: we refuse." printk(KERN_DEBUG "nop_test_refuse flag set to %d: we refuse."
"Now cat trace_options to see the result\n", " Now cat trace_options to see the result\n",
set); set);
return -EINVAL; return -EINVAL;
} }
......
...@@ -389,7 +389,9 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry) ...@@ -389,7 +389,9 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry)
char irqs_off; char irqs_off;
int hardirq; int hardirq;
int softirq; int softirq;
int nmi;
nmi = entry->flags & TRACE_FLAG_NMI;
hardirq = entry->flags & TRACE_FLAG_HARDIRQ; hardirq = entry->flags & TRACE_FLAG_HARDIRQ;
softirq = entry->flags & TRACE_FLAG_SOFTIRQ; softirq = entry->flags & TRACE_FLAG_SOFTIRQ;
...@@ -415,10 +417,12 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry) ...@@ -415,10 +417,12 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry)
} }
hardsoft_irq = hardsoft_irq =
(nmi && hardirq) ? 'Z' :
nmi ? 'z' :
(hardirq && softirq) ? 'H' : (hardirq && softirq) ? 'H' :
hardirq ? 'h' : hardirq ? 'h' :
softirq ? 's' : softirq ? 's' :
'.'; '.' ;
trace_seq_printf(s, "%c%c%c", trace_seq_printf(s, "%c%c%c",
irqs_off, need_resched, hardsoft_irq); irqs_off, need_resched, hardsoft_irq);
......
...@@ -296,6 +296,9 @@ static int t_show(struct seq_file *m, void *v) ...@@ -296,6 +296,9 @@ static int t_show(struct seq_file *m, void *v)
const char *str = *fmt; const char *str = *fmt;
int i; int i;
if (!*fmt)
return 0;
seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt); seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt);
/* /*
......
...@@ -106,6 +106,17 @@ static struct syscall_metadata *syscall_nr_to_meta(int nr) ...@@ -106,6 +106,17 @@ static struct syscall_metadata *syscall_nr_to_meta(int nr)
return syscalls_metadata[nr]; return syscalls_metadata[nr];
} }
const char *get_syscall_name(int syscall)
{
struct syscall_metadata *entry;
entry = syscall_nr_to_meta(syscall);
if (!entry)
return NULL;
return entry->name;
}
static enum print_line_t static enum print_line_t
print_syscall_enter(struct trace_iterator *iter, int flags, print_syscall_enter(struct trace_iterator *iter, int flags,
struct trace_event *event) struct trace_event *event)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment