Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
910e94dd
Commit
910e94dd
authored
Oct 12, 2011
by
Ingo Molnar
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'tip/perf/core' of
git://github.com/rostedt/linux
into perf/core
parents
177e2163
d696b58c
Changes
17
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
928 additions
and
479 deletions
+928
-479
arch/x86/kernel/jump_label.c
arch/x86/kernel/jump_label.c
+1
-1
include/linux/module.h
include/linux/module.h
+0
-12
include/linux/ring_buffer.h
include/linux/ring_buffer.h
+2
-0
include/linux/trace_clock.h
include/linux/trace_clock.h
+1
-0
include/linux/tracepoint.h
include/linux/tracepoint.h
+11
-14
kernel/module.c
kernel/module.c
+0
-47
kernel/trace/Makefile
kernel/trace/Makefile
+2
-0
kernel/trace/ftrace.c
kernel/trace/ftrace.c
+8
-0
kernel/trace/ring_buffer.c
kernel/trace/ring_buffer.c
+69
-1
kernel/trace/trace.c
kernel/trace/trace.c
+145
-28
kernel/trace/trace.h
kernel/trace/trace.h
+6
-10
kernel/trace/trace_clock.c
kernel/trace/trace_clock.c
+12
-0
kernel/trace/trace_events_filter.c
kernel/trace/trace_events_filter.c
+462
-333
kernel/trace/trace_events_filter_test.h
kernel/trace/trace_events_filter_test.h
+50
-0
kernel/trace/trace_irqsoff.c
kernel/trace/trace_irqsoff.c
+2
-2
kernel/trace/trace_printk.c
kernel/trace/trace_printk.c
+10
-9
kernel/tracepoint.c
kernel/tracepoint.c
+147
-22
No files found.
arch/x86/kernel/jump_label.c
View file @
910e94dd
...
@@ -42,7 +42,7 @@ void arch_jump_label_transform(struct jump_entry *entry,
...
@@ -42,7 +42,7 @@ void arch_jump_label_transform(struct jump_entry *entry,
put_online_cpus
();
put_online_cpus
();
}
}
void
arch_jump_label_text_poke_early
(
jump_label_t
addr
)
void
__init_or_module
arch_jump_label_text_poke_early
(
jump_label_t
addr
)
{
{
text_poke_early
((
void
*
)
addr
,
ideal_nops
[
NOP_ATOMIC5
],
text_poke_early
((
void
*
)
addr
,
ideal_nops
[
NOP_ATOMIC5
],
JUMP_LABEL_NOP_SIZE
);
JUMP_LABEL_NOP_SIZE
);
...
...
include/linux/module.h
View file @
910e94dd
...
@@ -580,9 +580,6 @@ int unregister_module_notifier(struct notifier_block * nb);
...
@@ -580,9 +580,6 @@ int unregister_module_notifier(struct notifier_block * nb);
extern
void
print_modules
(
void
);
extern
void
print_modules
(
void
);
extern
void
module_update_tracepoints
(
void
);
extern
int
module_get_iter_tracepoints
(
struct
tracepoint_iter
*
iter
);
#else
/* !CONFIG_MODULES... */
#else
/* !CONFIG_MODULES... */
#define EXPORT_SYMBOL(sym)
#define EXPORT_SYMBOL(sym)
#define EXPORT_SYMBOL_GPL(sym)
#define EXPORT_SYMBOL_GPL(sym)
...
@@ -698,15 +695,6 @@ static inline int unregister_module_notifier(struct notifier_block * nb)
...
@@ -698,15 +695,6 @@ static inline int unregister_module_notifier(struct notifier_block * nb)
static
inline
void
print_modules
(
void
)
static
inline
void
print_modules
(
void
)
{
{
}
}
static
inline
void
module_update_tracepoints
(
void
)
{
}
static
inline
int
module_get_iter_tracepoints
(
struct
tracepoint_iter
*
iter
)
{
return
0
;
}
#endif
/* CONFIG_MODULES */
#endif
/* CONFIG_MODULES */
#ifdef CONFIG_SYSFS
#ifdef CONFIG_SYSFS
...
...
include/linux/ring_buffer.h
View file @
910e94dd
...
@@ -154,6 +154,8 @@ void ring_buffer_record_enable(struct ring_buffer *buffer);
...
@@ -154,6 +154,8 @@ void ring_buffer_record_enable(struct ring_buffer *buffer);
void
ring_buffer_record_disable_cpu
(
struct
ring_buffer
*
buffer
,
int
cpu
);
void
ring_buffer_record_disable_cpu
(
struct
ring_buffer
*
buffer
,
int
cpu
);
void
ring_buffer_record_enable_cpu
(
struct
ring_buffer
*
buffer
,
int
cpu
);
void
ring_buffer_record_enable_cpu
(
struct
ring_buffer
*
buffer
,
int
cpu
);
unsigned
long
ring_buffer_oldest_event_ts
(
struct
ring_buffer
*
buffer
,
int
cpu
);
unsigned
long
ring_buffer_bytes_cpu
(
struct
ring_buffer
*
buffer
,
int
cpu
);
unsigned
long
ring_buffer_entries
(
struct
ring_buffer
*
buffer
);
unsigned
long
ring_buffer_entries
(
struct
ring_buffer
*
buffer
);
unsigned
long
ring_buffer_overruns
(
struct
ring_buffer
*
buffer
);
unsigned
long
ring_buffer_overruns
(
struct
ring_buffer
*
buffer
);
unsigned
long
ring_buffer_entries_cpu
(
struct
ring_buffer
*
buffer
,
int
cpu
);
unsigned
long
ring_buffer_entries_cpu
(
struct
ring_buffer
*
buffer
,
int
cpu
);
...
...
include/linux/trace_clock.h
View file @
910e94dd
...
@@ -15,5 +15,6 @@
...
@@ -15,5 +15,6 @@
extern
u64
notrace
trace_clock_local
(
void
);
extern
u64
notrace
trace_clock_local
(
void
);
extern
u64
notrace
trace_clock
(
void
);
extern
u64
notrace
trace_clock
(
void
);
extern
u64
notrace
trace_clock_global
(
void
);
extern
u64
notrace
trace_clock_global
(
void
);
extern
u64
notrace
trace_clock_counter
(
void
);
#endif
/* _LINUX_TRACE_CLOCK_H */
#endif
/* _LINUX_TRACE_CLOCK_H */
include/linux/tracepoint.h
View file @
910e94dd
...
@@ -54,8 +54,18 @@ extern int tracepoint_probe_unregister_noupdate(const char *name, void *probe,
...
@@ -54,8 +54,18 @@ extern int tracepoint_probe_unregister_noupdate(const char *name, void *probe,
void
*
data
);
void
*
data
);
extern
void
tracepoint_probe_update_all
(
void
);
extern
void
tracepoint_probe_update_all
(
void
);
#ifdef CONFIG_MODULES
struct
tp_module
{
struct
list_head
list
;
unsigned
int
num_tracepoints
;
struct
tracepoint
*
const
*
tracepoints_ptrs
;
};
#endif
/* CONFIG_MODULES */
struct
tracepoint_iter
{
struct
tracepoint_iter
{
struct
module
*
module
;
#ifdef CONFIG_MODULES
struct
tp_module
*
module
;
#endif
/* CONFIG_MODULES */
struct
tracepoint
*
const
*
tracepoint
;
struct
tracepoint
*
const
*
tracepoint
;
};
};
...
@@ -63,8 +73,6 @@ extern void tracepoint_iter_start(struct tracepoint_iter *iter);
...
@@ -63,8 +73,6 @@ extern void tracepoint_iter_start(struct tracepoint_iter *iter);
extern
void
tracepoint_iter_next
(
struct
tracepoint_iter
*
iter
);
extern
void
tracepoint_iter_next
(
struct
tracepoint_iter
*
iter
);
extern
void
tracepoint_iter_stop
(
struct
tracepoint_iter
*
iter
);
extern
void
tracepoint_iter_stop
(
struct
tracepoint_iter
*
iter
);
extern
void
tracepoint_iter_reset
(
struct
tracepoint_iter
*
iter
);
extern
void
tracepoint_iter_reset
(
struct
tracepoint_iter
*
iter
);
extern
int
tracepoint_get_iter_range
(
struct
tracepoint
*
const
**
tracepoint
,
struct
tracepoint
*
const
*
begin
,
struct
tracepoint
*
const
*
end
);
/*
/*
* tracepoint_synchronize_unregister must be called between the last tracepoint
* tracepoint_synchronize_unregister must be called between the last tracepoint
...
@@ -78,17 +86,6 @@ static inline void tracepoint_synchronize_unregister(void)
...
@@ -78,17 +86,6 @@ static inline void tracepoint_synchronize_unregister(void)
#define PARAMS(args...) args
#define PARAMS(args...) args
#ifdef CONFIG_TRACEPOINTS
extern
void
tracepoint_update_probe_range
(
struct
tracepoint
*
const
*
begin
,
struct
tracepoint
*
const
*
end
);
#else
static
inline
void
tracepoint_update_probe_range
(
struct
tracepoint
*
const
*
begin
,
struct
tracepoint
*
const
*
end
)
{
}
#endif
/* CONFIG_TRACEPOINTS */
#endif
/* _LINUX_TRACEPOINT_H */
#endif
/* _LINUX_TRACEPOINT_H */
/*
/*
...
...
kernel/module.c
View file @
910e94dd
...
@@ -3487,50 +3487,3 @@ void module_layout(struct module *mod,
...
@@ -3487,50 +3487,3 @@ void module_layout(struct module *mod,
}
}
EXPORT_SYMBOL
(
module_layout
);
EXPORT_SYMBOL
(
module_layout
);
#endif
#endif
#ifdef CONFIG_TRACEPOINTS
void
module_update_tracepoints
(
void
)
{
struct
module
*
mod
;
mutex_lock
(
&
module_mutex
);
list_for_each_entry
(
mod
,
&
modules
,
list
)
if
(
!
mod
->
taints
)
tracepoint_update_probe_range
(
mod
->
tracepoints_ptrs
,
mod
->
tracepoints_ptrs
+
mod
->
num_tracepoints
);
mutex_unlock
(
&
module_mutex
);
}
/*
* Returns 0 if current not found.
* Returns 1 if current found.
*/
int
module_get_iter_tracepoints
(
struct
tracepoint_iter
*
iter
)
{
struct
module
*
iter_mod
;
int
found
=
0
;
mutex_lock
(
&
module_mutex
);
list_for_each_entry
(
iter_mod
,
&
modules
,
list
)
{
if
(
!
iter_mod
->
taints
)
{
/*
* Sorted module list
*/
if
(
iter_mod
<
iter
->
module
)
continue
;
else
if
(
iter_mod
>
iter
->
module
)
iter
->
tracepoint
=
NULL
;
found
=
tracepoint_get_iter_range
(
&
iter
->
tracepoint
,
iter_mod
->
tracepoints_ptrs
,
iter_mod
->
tracepoints_ptrs
+
iter_mod
->
num_tracepoints
);
if
(
found
)
{
iter
->
module
=
iter_mod
;
break
;
}
}
}
mutex_unlock
(
&
module_mutex
);
return
found
;
}
#endif
kernel/trace/Makefile
View file @
910e94dd
...
@@ -15,6 +15,8 @@ ifdef CONFIG_TRACING_BRANCHES
...
@@ -15,6 +15,8 @@ ifdef CONFIG_TRACING_BRANCHES
KBUILD_CFLAGS
+=
-DDISABLE_BRANCH_PROFILING
KBUILD_CFLAGS
+=
-DDISABLE_BRANCH_PROFILING
endif
endif
CFLAGS_trace_events_filter.o
:=
-I
$(src)
#
#
# Make the trace clocks available generally: it's infrastructure
# Make the trace clocks available generally: it's infrastructure
# relied on by ptrace for example:
# relied on by ptrace for example:
...
...
kernel/trace/ftrace.c
View file @
910e94dd
...
@@ -3862,6 +3862,14 @@ void ftrace_kill(void)
...
@@ -3862,6 +3862,14 @@ void ftrace_kill(void)
clear_ftrace_function
();
clear_ftrace_function
();
}
}
/**
* Test if ftrace is dead or not.
*/
int
ftrace_is_dead
(
void
)
{
return
ftrace_disabled
;
}
/**
/**
* register_ftrace_function - register a function for profiling
* register_ftrace_function - register a function for profiling
* @ops - ops structure that holds the function for profiling.
* @ops - ops structure that holds the function for profiling.
...
...
kernel/trace/ring_buffer.c
View file @
910e94dd
...
@@ -488,12 +488,14 @@ struct ring_buffer_per_cpu {
...
@@ -488,12 +488,14 @@ struct ring_buffer_per_cpu {
struct
buffer_page
*
reader_page
;
struct
buffer_page
*
reader_page
;
unsigned
long
lost_events
;
unsigned
long
lost_events
;
unsigned
long
last_overrun
;
unsigned
long
last_overrun
;
local_t
entries_bytes
;
local_t
commit_overrun
;
local_t
commit_overrun
;
local_t
overrun
;
local_t
overrun
;
local_t
entries
;
local_t
entries
;
local_t
committing
;
local_t
committing
;
local_t
commits
;
local_t
commits
;
unsigned
long
read
;
unsigned
long
read
;
unsigned
long
read_bytes
;
u64
write_stamp
;
u64
write_stamp
;
u64
read_stamp
;
u64
read_stamp
;
};
};
...
@@ -1708,6 +1710,7 @@ rb_handle_head_page(struct ring_buffer_per_cpu *cpu_buffer,
...
@@ -1708,6 +1710,7 @@ rb_handle_head_page(struct ring_buffer_per_cpu *cpu_buffer,
* the counters.
* the counters.
*/
*/
local_add
(
entries
,
&
cpu_buffer
->
overrun
);
local_add
(
entries
,
&
cpu_buffer
->
overrun
);
local_sub
(
BUF_PAGE_SIZE
,
&
cpu_buffer
->
entries_bytes
);
/*
/*
* The entries will be zeroed out when we move the
* The entries will be zeroed out when we move the
...
@@ -1863,6 +1866,9 @@ rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer,
...
@@ -1863,6 +1866,9 @@ rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer,
event
=
__rb_page_index
(
tail_page
,
tail
);
event
=
__rb_page_index
(
tail_page
,
tail
);
kmemcheck_annotate_bitfield
(
event
,
bitfield
);
kmemcheck_annotate_bitfield
(
event
,
bitfield
);
/* account for padding bytes */
local_add
(
BUF_PAGE_SIZE
-
tail
,
&
cpu_buffer
->
entries_bytes
);
/*
/*
* Save the original length to the meta data.
* Save the original length to the meta data.
* This will be used by the reader to add lost event
* This will be used by the reader to add lost event
...
@@ -2054,6 +2060,9 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
...
@@ -2054,6 +2060,9 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
if
(
!
tail
)
if
(
!
tail
)
tail_page
->
page
->
time_stamp
=
ts
;
tail_page
->
page
->
time_stamp
=
ts
;
/* account for these added bytes */
local_add
(
length
,
&
cpu_buffer
->
entries_bytes
);
return
event
;
return
event
;
}
}
...
@@ -2076,6 +2085,7 @@ rb_try_to_discard(struct ring_buffer_per_cpu *cpu_buffer,
...
@@ -2076,6 +2085,7 @@ rb_try_to_discard(struct ring_buffer_per_cpu *cpu_buffer,
if
(
bpage
->
page
==
(
void
*
)
addr
&&
rb_page_write
(
bpage
)
==
old_index
)
{
if
(
bpage
->
page
==
(
void
*
)
addr
&&
rb_page_write
(
bpage
)
==
old_index
)
{
unsigned
long
write_mask
=
unsigned
long
write_mask
=
local_read
(
&
bpage
->
write
)
&
~
RB_WRITE_MASK
;
local_read
(
&
bpage
->
write
)
&
~
RB_WRITE_MASK
;
unsigned
long
event_length
=
rb_event_length
(
event
);
/*
/*
* This is on the tail page. It is possible that
* This is on the tail page. It is possible that
* a write could come in and move the tail page
* a write could come in and move the tail page
...
@@ -2085,8 +2095,11 @@ rb_try_to_discard(struct ring_buffer_per_cpu *cpu_buffer,
...
@@ -2085,8 +2095,11 @@ rb_try_to_discard(struct ring_buffer_per_cpu *cpu_buffer,
old_index
+=
write_mask
;
old_index
+=
write_mask
;
new_index
+=
write_mask
;
new_index
+=
write_mask
;
index
=
local_cmpxchg
(
&
bpage
->
write
,
old_index
,
new_index
);
index
=
local_cmpxchg
(
&
bpage
->
write
,
old_index
,
new_index
);
if
(
index
==
old_index
)
if
(
index
==
old_index
)
{
/* update counters */
local_sub
(
event_length
,
&
cpu_buffer
->
entries_bytes
);
return
1
;
return
1
;
}
}
}
/* could not discard */
/* could not discard */
...
@@ -2660,6 +2673,58 @@ rb_num_of_entries(struct ring_buffer_per_cpu *cpu_buffer)
...
@@ -2660,6 +2673,58 @@ rb_num_of_entries(struct ring_buffer_per_cpu *cpu_buffer)
(
local_read
(
&
cpu_buffer
->
overrun
)
+
cpu_buffer
->
read
);
(
local_read
(
&
cpu_buffer
->
overrun
)
+
cpu_buffer
->
read
);
}
}
/**
* ring_buffer_oldest_event_ts - get the oldest event timestamp from the buffer
* @buffer: The ring buffer
* @cpu: The per CPU buffer to read from.
*/
unsigned
long
ring_buffer_oldest_event_ts
(
struct
ring_buffer
*
buffer
,
int
cpu
)
{
unsigned
long
flags
;
struct
ring_buffer_per_cpu
*
cpu_buffer
;
struct
buffer_page
*
bpage
;
unsigned
long
ret
;
if
(
!
cpumask_test_cpu
(
cpu
,
buffer
->
cpumask
))
return
0
;
cpu_buffer
=
buffer
->
buffers
[
cpu
];
spin_lock_irqsave
(
&
cpu_buffer
->
reader_lock
,
flags
);
/*
* if the tail is on reader_page, oldest time stamp is on the reader
* page
*/
if
(
cpu_buffer
->
tail_page
==
cpu_buffer
->
reader_page
)
bpage
=
cpu_buffer
->
reader_page
;
else
bpage
=
rb_set_head_page
(
cpu_buffer
);
ret
=
bpage
->
page
->
time_stamp
;
spin_unlock_irqrestore
(
&
cpu_buffer
->
reader_lock
,
flags
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
ring_buffer_oldest_event_ts
);
/**
* ring_buffer_bytes_cpu - get the number of bytes consumed in a cpu buffer
* @buffer: The ring buffer
* @cpu: The per CPU buffer to read from.
*/
unsigned
long
ring_buffer_bytes_cpu
(
struct
ring_buffer
*
buffer
,
int
cpu
)
{
struct
ring_buffer_per_cpu
*
cpu_buffer
;
unsigned
long
ret
;
if
(
!
cpumask_test_cpu
(
cpu
,
buffer
->
cpumask
))
return
0
;
cpu_buffer
=
buffer
->
buffers
[
cpu
];
ret
=
local_read
(
&
cpu_buffer
->
entries_bytes
)
-
cpu_buffer
->
read_bytes
;
return
ret
;
}
EXPORT_SYMBOL_GPL
(
ring_buffer_bytes_cpu
);
/**
/**
* ring_buffer_entries_cpu - get the number of entries in a cpu buffer
* ring_buffer_entries_cpu - get the number of entries in a cpu buffer
* @buffer: The ring buffer
* @buffer: The ring buffer
...
@@ -3527,11 +3592,13 @@ rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer)
...
@@ -3527,11 +3592,13 @@ rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer)
cpu_buffer
->
reader_page
->
read
=
0
;
cpu_buffer
->
reader_page
->
read
=
0
;
local_set
(
&
cpu_buffer
->
commit_overrun
,
0
);
local_set
(
&
cpu_buffer
->
commit_overrun
,
0
);
local_set
(
&
cpu_buffer
->
entries_bytes
,
0
);
local_set
(
&
cpu_buffer
->
overrun
,
0
);
local_set
(
&
cpu_buffer
->
overrun
,
0
);
local_set
(
&
cpu_buffer
->
entries
,
0
);
local_set
(
&
cpu_buffer
->
entries
,
0
);
local_set
(
&
cpu_buffer
->
committing
,
0
);
local_set
(
&
cpu_buffer
->
committing
,
0
);
local_set
(
&
cpu_buffer
->
commits
,
0
);
local_set
(
&
cpu_buffer
->
commits
,
0
);
cpu_buffer
->
read
=
0
;
cpu_buffer
->
read
=
0
;
cpu_buffer
->
read_bytes
=
0
;
cpu_buffer
->
write_stamp
=
0
;
cpu_buffer
->
write_stamp
=
0
;
cpu_buffer
->
read_stamp
=
0
;
cpu_buffer
->
read_stamp
=
0
;
...
@@ -3918,6 +3985,7 @@ int ring_buffer_read_page(struct ring_buffer *buffer,
...
@@ -3918,6 +3985,7 @@ int ring_buffer_read_page(struct ring_buffer *buffer,
}
else
{
}
else
{
/* update the entry counter */
/* update the entry counter */
cpu_buffer
->
read
+=
rb_page_entries
(
reader
);
cpu_buffer
->
read
+=
rb_page_entries
(
reader
);
cpu_buffer
->
read_bytes
+=
BUF_PAGE_SIZE
;
/* swap the pages */
/* swap the pages */
rb_init_page
(
bpage
);
rb_init_page
(
bpage
);
...
...
kernel/trace/trace.c
View file @
910e94dd
...
@@ -435,6 +435,7 @@ static struct {
...
@@ -435,6 +435,7 @@ static struct {
}
trace_clocks
[]
=
{
}
trace_clocks
[]
=
{
{
trace_clock_local
,
"local"
},
{
trace_clock_local
,
"local"
},
{
trace_clock_global
,
"global"
},
{
trace_clock_global
,
"global"
},
{
trace_clock_counter
,
"counter"
},
};
};
int
trace_clock_id
;
int
trace_clock_id
;
...
@@ -2159,6 +2160,14 @@ void trace_default_header(struct seq_file *m)
...
@@ -2159,6 +2160,14 @@ void trace_default_header(struct seq_file *m)
}
}
}
}
static
void
test_ftrace_alive
(
struct
seq_file
*
m
)
{
if
(
!
ftrace_is_dead
())
return
;
seq_printf
(
m
,
"# WARNING: FUNCTION TRACING IS CORRUPTED
\n
"
);
seq_printf
(
m
,
"# MAY BE MISSING FUNCTION EVENTS
\n
"
);
}
static
int
s_show
(
struct
seq_file
*
m
,
void
*
v
)
static
int
s_show
(
struct
seq_file
*
m
,
void
*
v
)
{
{
struct
trace_iterator
*
iter
=
v
;
struct
trace_iterator
*
iter
=
v
;
...
@@ -2168,6 +2177,7 @@ static int s_show(struct seq_file *m, void *v)
...
@@ -2168,6 +2177,7 @@ static int s_show(struct seq_file *m, void *v)
if
(
iter
->
tr
)
{
if
(
iter
->
tr
)
{
seq_printf
(
m
,
"# tracer: %s
\n
"
,
iter
->
trace
->
name
);
seq_printf
(
m
,
"# tracer: %s
\n
"
,
iter
->
trace
->
name
);
seq_puts
(
m
,
"#
\n
"
);
seq_puts
(
m
,
"#
\n
"
);
test_ftrace_alive
(
m
);
}
}
if
(
iter
->
trace
&&
iter
->
trace
->
print_header
)
if
(
iter
->
trace
&&
iter
->
trace
->
print_header
)
iter
->
trace
->
print_header
(
m
);
iter
->
trace
->
print_header
(
m
);
...
@@ -3568,6 +3578,30 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
...
@@ -3568,6 +3578,30 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
return
cnt
;
return
cnt
;
}
}
static
ssize_t
tracing_total_entries_read
(
struct
file
*
filp
,
char
__user
*
ubuf
,
size_t
cnt
,
loff_t
*
ppos
)
{
struct
trace_array
*
tr
=
filp
->
private_data
;
char
buf
[
64
];
int
r
,
cpu
;
unsigned
long
size
=
0
,
expanded_size
=
0
;
mutex_lock
(
&
trace_types_lock
);
for_each_tracing_cpu
(
cpu
)
{
size
+=
tr
->
entries
>>
10
;
if
(
!
ring_buffer_expanded
)
expanded_size
+=
trace_buf_size
>>
10
;
}
if
(
ring_buffer_expanded
)
r
=
sprintf
(
buf
,
"%lu
\n
"
,
size
);
else
r
=
sprintf
(
buf
,
"%lu (expanded: %lu)
\n
"
,
size
,
expanded_size
);
mutex_unlock
(
&
trace_types_lock
);
return
simple_read_from_buffer
(
ubuf
,
cnt
,
ppos
,
buf
,
r
);
}
static
ssize_t
static
ssize_t
tracing_free_buffer_write
(
struct
file
*
filp
,
const
char
__user
*
ubuf
,
tracing_free_buffer_write
(
struct
file
*
filp
,
const
char
__user
*
ubuf
,
size_t
cnt
,
loff_t
*
ppos
)
size_t
cnt
,
loff_t
*
ppos
)
...
@@ -3594,22 +3628,24 @@ tracing_free_buffer_release(struct inode *inode, struct file *filp)
...
@@ -3594,22 +3628,24 @@ tracing_free_buffer_release(struct inode *inode, struct file *filp)
return
0
;
return
0
;
}
}
static
int
mark_printk
(
const
char
*
fmt
,
...)
{
int
ret
;
va_list
args
;
va_start
(
args
,
fmt
);
ret
=
trace_vprintk
(
0
,
fmt
,
args
);
va_end
(
args
);
return
ret
;
}
static
ssize_t
static
ssize_t
tracing_mark_write
(
struct
file
*
filp
,
const
char
__user
*
ubuf
,
tracing_mark_write
(
struct
file
*
filp
,
const
char
__user
*
ubuf
,
size_t
cnt
,
loff_t
*
fpos
)
size_t
cnt
,
loff_t
*
fpos
)
{
{
char
*
buf
;
unsigned
long
addr
=
(
unsigned
long
)
ubuf
;
size_t
written
;
struct
ring_buffer_event
*
event
;
struct
ring_buffer
*
buffer
;
struct
print_entry
*
entry
;
unsigned
long
irq_flags
;
struct
page
*
pages
[
2
];
int
nr_pages
=
1
;
ssize_t
written
;
void
*
page1
;
void
*
page2
;
int
offset
;
int
size
;
int
len
;
int
ret
;
if
(
tracing_disabled
)
if
(
tracing_disabled
)
return
-
EINVAL
;
return
-
EINVAL
;
...
@@ -3617,28 +3653,81 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
...
@@ -3617,28 +3653,81 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
if
(
cnt
>
TRACE_BUF_SIZE
)
if
(
cnt
>
TRACE_BUF_SIZE
)
cnt
=
TRACE_BUF_SIZE
;
cnt
=
TRACE_BUF_SIZE
;
buf
=
kmalloc
(
cnt
+
2
,
GFP_KERNEL
);
/*
if
(
buf
==
NULL
)
* Userspace is injecting traces into the kernel trace buffer.
return
-
ENOMEM
;
* We want to be as non intrusive as possible.
* To do so, we do not want to allocate any special buffers
* or take any locks, but instead write the userspace data
* straight into the ring buffer.
*
* First we need to pin the userspace buffer into memory,
* which, most likely it is, because it just referenced it.
* But there's no guarantee that it is. By using get_user_pages_fast()
* and kmap_atomic/kunmap_atomic() we can get access to the
* pages directly. We then write the data directly into the
* ring buffer.
*/
BUILD_BUG_ON
(
TRACE_BUF_SIZE
>=
PAGE_SIZE
);
if
(
copy_from_user
(
buf
,
ubuf
,
cnt
))
{
/* check if we cross pages */
kfree
(
buf
);
if
((
addr
&
PAGE_MASK
)
!=
((
addr
+
cnt
)
&
PAGE_MASK
))
return
-
EFAULT
;
nr_pages
=
2
;
offset
=
addr
&
(
PAGE_SIZE
-
1
);
addr
&=
PAGE_MASK
;
ret
=
get_user_pages_fast
(
addr
,
nr_pages
,
0
,
pages
);
if
(
ret
<
nr_pages
)
{
while
(
--
ret
>=
0
)
put_page
(
pages
[
ret
]);
written
=
-
EFAULT
;
goto
out
;
}
}
if
(
buf
[
cnt
-
1
]
!=
'\n'
)
{
buf
[
cnt
]
=
'\n'
;
page1
=
kmap_atomic
(
pages
[
0
]);
buf
[
cnt
+
1
]
=
'\0'
;
if
(
nr_pages
==
2
)
page2
=
kmap_atomic
(
pages
[
1
]);
local_save_flags
(
irq_flags
);
size
=
sizeof
(
*
entry
)
+
cnt
+
2
;
/* possible \n added */
buffer
=
global_trace
.
buffer
;
event
=
trace_buffer_lock_reserve
(
buffer
,
TRACE_PRINT
,
size
,
irq_flags
,
preempt_count
());
if
(
!
event
)
{
/* Ring buffer disabled, return as if not open for write */
written
=
-
EBADF
;
goto
out_unlock
;
}
entry
=
ring_buffer_event_data
(
event
);
entry
->
ip
=
_THIS_IP_
;
if
(
nr_pages
==
2
)
{
len
=
PAGE_SIZE
-
offset
;
memcpy
(
&
entry
->
buf
,
page1
+
offset
,
len
);
memcpy
(
&
entry
->
buf
[
len
],
page2
,
cnt
-
len
);
}
else
}
else
buf
[
cnt
]
=
'\0'
;
memcpy
(
&
entry
->
buf
,
page1
+
offset
,
cnt
)
;
written
=
mark_printk
(
"%s"
,
buf
);
if
(
entry
->
buf
[
cnt
-
1
]
!=
'\n'
)
{
kfree
(
buf
);
entry
->
buf
[
cnt
]
=
'\n'
;
*
fpos
+=
written
;
entry
->
buf
[
cnt
+
1
]
=
'\0'
;
}
else
entry
->
buf
[
cnt
]
=
'\0'
;
/* don't tell userspace we wrote more - it might confuse them */
ring_buffer_unlock_commit
(
buffer
,
event
);
if
(
written
>
cnt
)
written
=
cnt
;
written
=
cnt
;
*
fpos
+=
written
;
out_unlock:
if
(
nr_pages
==
2
)
kunmap_atomic
(
page2
);
kunmap_atomic
(
page1
);
while
(
nr_pages
>
0
)
put_page
(
pages
[
--
nr_pages
]);
out:
return
written
;
return
written
;
}
}
...
@@ -3739,6 +3828,12 @@ static const struct file_operations tracing_entries_fops = {
...
@@ -3739,6 +3828,12 @@ static const struct file_operations tracing_entries_fops = {
.
llseek
=
generic_file_llseek
,
.
llseek
=
generic_file_llseek
,
};
};
static
const
struct
file_operations
tracing_total_entries_fops
=
{
.
open
=
tracing_open_generic
,
.
read
=
tracing_total_entries_read
,
.
llseek
=
generic_file_llseek
,
};
static
const
struct
file_operations
tracing_free_buffer_fops
=
{
static
const
struct
file_operations
tracing_free_buffer_fops
=
{
.
write
=
tracing_free_buffer_write
,
.
write
=
tracing_free_buffer_write
,
.
release
=
tracing_free_buffer_release
,
.
release
=
tracing_free_buffer_release
,
...
@@ -4026,6 +4121,8 @@ tracing_stats_read(struct file *filp, char __user *ubuf,
...
@@ -4026,6 +4121,8 @@ tracing_stats_read(struct file *filp, char __user *ubuf,
struct
trace_array
*
tr
=
&
global_trace
;
struct
trace_array
*
tr
=
&
global_trace
;
struct
trace_seq
*
s
;
struct
trace_seq
*
s
;
unsigned
long
cnt
;
unsigned
long
cnt
;
unsigned
long
long
t
;
unsigned
long
usec_rem
;
s
=
kmalloc
(
sizeof
(
*
s
),
GFP_KERNEL
);
s
=
kmalloc
(
sizeof
(
*
s
),
GFP_KERNEL
);
if
(
!
s
)
if
(
!
s
)
...
@@ -4042,6 +4139,17 @@ tracing_stats_read(struct file *filp, char __user *ubuf,
...
@@ -4042,6 +4139,17 @@ tracing_stats_read(struct file *filp, char __user *ubuf,
cnt
=
ring_buffer_commit_overrun_cpu
(
tr
->
buffer
,
cpu
);
cnt
=
ring_buffer_commit_overrun_cpu
(
tr
->
buffer
,
cpu
);
trace_seq_printf
(
s
,
"commit overrun: %ld
\n
"
,
cnt
);
trace_seq_printf
(
s
,
"commit overrun: %ld
\n
"
,
cnt
);
cnt
=
ring_buffer_bytes_cpu
(
tr
->
buffer
,
cpu
);
trace_seq_printf
(
s
,
"bytes: %ld
\n
"
,
cnt
);
t
=
ns2usecs
(
ring_buffer_oldest_event_ts
(
tr
->
buffer
,
cpu
));
usec_rem
=
do_div
(
t
,
USEC_PER_SEC
);
trace_seq_printf
(
s
,
"oldest event ts: %5llu.%06lu
\n
"
,
t
,
usec_rem
);
t
=
ns2usecs
(
ring_buffer_time_stamp
(
tr
->
buffer
,
cpu
));
usec_rem
=
do_div
(
t
,
USEC_PER_SEC
);
trace_seq_printf
(
s
,
"now ts: %5llu.%06lu
\n
"
,
t
,
usec_rem
);
count
=
simple_read_from_buffer
(
ubuf
,
count
,
ppos
,
s
->
buffer
,
s
->
len
);
count
=
simple_read_from_buffer
(
ubuf
,
count
,
ppos
,
s
->
buffer
,
s
->
len
);
kfree
(
s
);
kfree
(
s
);
...
@@ -4450,6 +4558,9 @@ static __init int tracer_init_debugfs(void)
...
@@ -4450,6 +4558,9 @@ static __init int tracer_init_debugfs(void)
trace_create_file
(
"buffer_size_kb"
,
0644
,
d_tracer
,
trace_create_file
(
"buffer_size_kb"
,
0644
,
d_tracer
,
&
global_trace
,
&
tracing_entries_fops
);
&
global_trace
,
&
tracing_entries_fops
);
trace_create_file
(
"buffer_total_size_kb"
,
0444
,
d_tracer
,
&
global_trace
,
&
tracing_total_entries_fops
);
trace_create_file
(
"free_buffer"
,
0644
,
d_tracer
,
trace_create_file
(
"free_buffer"
,
0644
,
d_tracer
,
&
global_trace
,
&
tracing_free_buffer_fops
);
&
global_trace
,
&
tracing_free_buffer_fops
);
...
@@ -4566,6 +4677,12 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
...
@@ -4566,6 +4677,12 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
tracing_off
();
tracing_off
();
/* Did function tracer already get disabled? */
if
(
ftrace_is_dead
())
{
printk
(
"# WARNING: FUNCTION TRACING IS CORRUPTED
\n
"
);
printk
(
"# MAY BE MISSING FUNCTION EVENTS
\n
"
);
}
if
(
disable_tracing
)
if
(
disable_tracing
)
ftrace_kill
();
ftrace_kill
();
...
...
kernel/trace/trace.h
View file @
910e94dd
...
@@ -579,11 +579,13 @@ static inline int ftrace_trace_task(struct task_struct *task)
...
@@ -579,11 +579,13 @@ static inline int ftrace_trace_task(struct task_struct *task)
return
test_tsk_trace_trace
(
task
);
return
test_tsk_trace_trace
(
task
);
}
}
extern
int
ftrace_is_dead
(
void
);
#else
#else
static
inline
int
ftrace_trace_task
(
struct
task_struct
*
task
)
static
inline
int
ftrace_trace_task
(
struct
task_struct
*
task
)
{
{
return
1
;
return
1
;
}
}
static
inline
int
ftrace_is_dead
(
void
)
{
return
0
;
}
#endif
#endif
/*
/*
...
@@ -761,16 +763,10 @@ struct filter_pred {
...
@@ -761,16 +763,10 @@ struct filter_pred {
filter_pred_fn_t
fn
;
filter_pred_fn_t
fn
;
u64
val
;
u64
val
;
struct
regex
regex
;
struct
regex
regex
;
/*
unsigned
short
*
ops
;
* Leaf nodes use field_name, ops is used by AND and OR
#ifdef CONFIG_FTRACE_STARTUP_TEST
* nodes. The field_name is always freed when freeing a pred.
struct
ftrace_event_field
*
field
;
* We can overload field_name for ops and have it freed
#endif
* as well.
*/
union
{
char
*
field_name
;
unsigned
short
*
ops
;
};
int
offset
;
int
offset
;
int
not
;
int
not
;
int
op
;
int
op
;
...
...
kernel/trace/trace_clock.c
View file @
910e94dd
...
@@ -113,3 +113,15 @@ u64 notrace trace_clock_global(void)
...
@@ -113,3 +113,15 @@ u64 notrace trace_clock_global(void)
return
now
;
return
now
;
}
}
static
atomic64_t
trace_counter
;
/*
* trace_clock_counter(): simply an atomic counter.
* Use the trace_counter "counter" for cases where you do not care
* about timings, but are interested in strict ordering.
*/
u64
notrace
trace_clock_counter
(
void
)
{
return
atomic64_add_return
(
1
,
&
trace_counter
);
}
kernel/trace/trace_events_filter.c
View file @
910e94dd
...
@@ -381,6 +381,63 @@ get_pred_parent(struct filter_pred *pred, struct filter_pred *preds,
...
@@ -381,6 +381,63 @@ get_pred_parent(struct filter_pred *pred, struct filter_pred *preds,
return
pred
;
return
pred
;
}
}
enum
walk_return
{
WALK_PRED_ABORT
,
WALK_PRED_PARENT
,
WALK_PRED_DEFAULT
,
};
typedef
int
(
*
filter_pred_walkcb_t
)
(
enum
move_type
move
,
struct
filter_pred
*
pred
,
int
*
err
,
void
*
data
);
static
int
walk_pred_tree
(
struct
filter_pred
*
preds
,
struct
filter_pred
*
root
,
filter_pred_walkcb_t
cb
,
void
*
data
)
{
struct
filter_pred
*
pred
=
root
;
enum
move_type
move
=
MOVE_DOWN
;
int
done
=
0
;
if
(
!
preds
)
return
-
EINVAL
;
do
{
int
err
=
0
,
ret
;
ret
=
cb
(
move
,
pred
,
&
err
,
data
);
if
(
ret
==
WALK_PRED_ABORT
)
return
err
;
if
(
ret
==
WALK_PRED_PARENT
)
goto
get_parent
;
switch
(
move
)
{
case
MOVE_DOWN
:
if
(
pred
->
left
!=
FILTER_PRED_INVALID
)
{
pred
=
&
preds
[
pred
->
left
];
continue
;
}
goto
get_parent
;
case
MOVE_UP_FROM_LEFT
:
pred
=
&
preds
[
pred
->
right
];
move
=
MOVE_DOWN
;
continue
;
case
MOVE_UP_FROM_RIGHT
:
get_parent:
if
(
pred
==
root
)
break
;
pred
=
get_pred_parent
(
pred
,
preds
,
pred
->
parent
,
&
move
);
continue
;
}
done
=
1
;
}
while
(
!
done
);
/* We are fine. */
return
0
;
}
/*
/*
* A series of AND or ORs where found together. Instead of
* A series of AND or ORs where found together. Instead of
* climbing up and down the tree branches, an array of the
* climbing up and down the tree branches, an array of the
...
@@ -410,99 +467,91 @@ static int process_ops(struct filter_pred *preds,
...
@@ -410,99 +467,91 @@ static int process_ops(struct filter_pred *preds,
for
(
i
=
0
;
i
<
op
->
val
;
i
++
)
{
for
(
i
=
0
;
i
<
op
->
val
;
i
++
)
{
pred
=
&
preds
[
op
->
ops
[
i
]];
pred
=
&
preds
[
op
->
ops
[
i
]];
match
=
pred
->
fn
(
pred
,
rec
);
if
(
!
WARN_ON_ONCE
(
!
pred
->
fn
))
match
=
pred
->
fn
(
pred
,
rec
);
if
(
!!
match
==
type
)
if
(
!!
match
==
type
)
return
match
;
return
match
;
}
}
return
match
;
return
match
;
}
}
struct
filter_match_preds_data
{
struct
filter_pred
*
preds
;
int
match
;
void
*
rec
;
};
static
int
filter_match_preds_cb
(
enum
move_type
move
,
struct
filter_pred
*
pred
,
int
*
err
,
void
*
data
)
{
struct
filter_match_preds_data
*
d
=
data
;
*
err
=
0
;
switch
(
move
)
{
case
MOVE_DOWN
:
/* only AND and OR have children */
if
(
pred
->
left
!=
FILTER_PRED_INVALID
)
{
/* If ops is set, then it was folded. */
if
(
!
pred
->
ops
)
return
WALK_PRED_DEFAULT
;
/* We can treat folded ops as a leaf node */
d
->
match
=
process_ops
(
d
->
preds
,
pred
,
d
->
rec
);
}
else
{
if
(
!
WARN_ON_ONCE
(
!
pred
->
fn
))
d
->
match
=
pred
->
fn
(
pred
,
d
->
rec
);
}
return
WALK_PRED_PARENT
;
case
MOVE_UP_FROM_LEFT
:
/*
* Check for short circuits.
*
* Optimization: !!match == (pred->op == OP_OR)
* is the same as:
* if ((match && pred->op == OP_OR) ||
* (!match && pred->op == OP_AND))
*/
if
(
!!
d
->
match
==
(
pred
->
op
==
OP_OR
))
return
WALK_PRED_PARENT
;
break
;
case
MOVE_UP_FROM_RIGHT
:
break
;
}
return
WALK_PRED_DEFAULT
;
}
/* return 1 if event matches, 0 otherwise (discard) */
/* return 1 if event matches, 0 otherwise (discard) */
int
filter_match_preds
(
struct
event_filter
*
filter
,
void
*
rec
)
int
filter_match_preds
(
struct
event_filter
*
filter
,
void
*
rec
)
{
{
int
match
=
-
1
;
enum
move_type
move
=
MOVE_DOWN
;
struct
filter_pred
*
preds
;
struct
filter_pred
*
preds
;
struct
filter_pred
*
pred
;
struct
filter_pred
*
root
;
struct
filter_pred
*
root
;
int
n_preds
;
struct
filter_match_preds_data
data
=
{
int
done
=
0
;
/* match is currently meaningless */
.
match
=
-
1
,
.
rec
=
rec
,
};
int
n_preds
,
ret
;
/* no filter is considered a match */
/* no filter is considered a match */
if
(
!
filter
)
if
(
!
filter
)
return
1
;
return
1
;
n_preds
=
filter
->
n_preds
;
n_preds
=
filter
->
n_preds
;
if
(
!
n_preds
)
if
(
!
n_preds
)
return
1
;
return
1
;
/*
/*
* n_preds, root and filter->preds are protect with preemption disabled.
* n_preds, root and filter->preds are protect with preemption disabled.
*/
*/
preds
=
rcu_dereference_sched
(
filter
->
preds
);
root
=
rcu_dereference_sched
(
filter
->
root
);
root
=
rcu_dereference_sched
(
filter
->
root
);
if
(
!
root
)
if
(
!
root
)
return
1
;
return
1
;
pred
=
root
;
data
.
preds
=
preds
=
rcu_dereference_sched
(
filter
->
preds
);
ret
=
walk_pred_tree
(
preds
,
root
,
filter_match_preds_cb
,
&
data
);
/* match is currently meaningless */
WARN_ON
(
ret
);
match
=
-
1
;
return
data
.
match
;
do
{
switch
(
move
)
{
case
MOVE_DOWN
:
/* only AND and OR have children */
if
(
pred
->
left
!=
FILTER_PRED_INVALID
)
{
/* If ops is set, then it was folded. */
if
(
!
pred
->
ops
)
{
/* keep going to down the left side */
pred
=
&
preds
[
pred
->
left
];
continue
;
}
/* We can treat folded ops as a leaf node */
match
=
process_ops
(
preds
,
pred
,
rec
);
}
else
match
=
pred
->
fn
(
pred
,
rec
);
/* If this pred is the only pred */
if
(
pred
==
root
)
break
;
pred
=
get_pred_parent
(
pred
,
preds
,
pred
->
parent
,
&
move
);
continue
;
case
MOVE_UP_FROM_LEFT
:
/*
* Check for short circuits.
*
* Optimization: !!match == (pred->op == OP_OR)
* is the same as:
* if ((match && pred->op == OP_OR) ||
* (!match && pred->op == OP_AND))
*/
if
(
!!
match
==
(
pred
->
op
==
OP_OR
))
{
if
(
pred
==
root
)
break
;
pred
=
get_pred_parent
(
pred
,
preds
,
pred
->
parent
,
&
move
);
continue
;
}
/* now go down the right side of the tree. */
pred
=
&
preds
[
pred
->
right
];
move
=
MOVE_DOWN
;
continue
;
case
MOVE_UP_FROM_RIGHT
:
/* We finished this equation. */
if
(
pred
==
root
)
break
;
pred
=
get_pred_parent
(
pred
,
preds
,
pred
->
parent
,
&
move
);
continue
;
}
done
=
1
;
}
while
(
!
done
);
return
match
;
}
}
EXPORT_SYMBOL_GPL
(
filter_match_preds
);
EXPORT_SYMBOL_GPL
(
filter_match_preds
);
...
@@ -628,22 +677,6 @@ find_event_field(struct ftrace_event_call *call, char *name)
...
@@ -628,22 +677,6 @@ find_event_field(struct ftrace_event_call *call, char *name)
return
__find_event_field
(
head
,
name
);
return
__find_event_field
(
head
,
name
);
}
}
static
void
filter_free_pred
(
struct
filter_pred
*
pred
)
{
if
(
!
pred
)
return
;
kfree
(
pred
->
field_name
);
kfree
(
pred
);
}
static
void
filter_clear_pred
(
struct
filter_pred
*
pred
)
{
kfree
(
pred
->
field_name
);
pred
->
field_name
=
NULL
;
pred
->
regex
.
len
=
0
;
}
static
int
__alloc_pred_stack
(
struct
pred_stack
*
stack
,
int
n_preds
)
static
int
__alloc_pred_stack
(
struct
pred_stack
*
stack
,
int
n_preds
)
{
{
stack
->
preds
=
kzalloc
(
sizeof
(
*
stack
->
preds
)
*
(
n_preds
+
1
),
GFP_KERNEL
);
stack
->
preds
=
kzalloc
(
sizeof
(
*
stack
->
preds
)
*
(
n_preds
+
1
),
GFP_KERNEL
);
...
@@ -689,20 +722,13 @@ __pop_pred_stack(struct pred_stack *stack)
...
@@ -689,20 +722,13 @@ __pop_pred_stack(struct pred_stack *stack)
static
int
filter_set_pred
(
struct
event_filter
*
filter
,
static
int
filter_set_pred
(
struct
event_filter
*
filter
,
int
idx
,
int
idx
,
struct
pred_stack
*
stack
,
struct
pred_stack
*
stack
,
struct
filter_pred
*
src
,
struct
filter_pred
*
src
)
filter_pred_fn_t
fn
)
{
{
struct
filter_pred
*
dest
=
&
filter
->
preds
[
idx
];
struct
filter_pred
*
dest
=
&
filter
->
preds
[
idx
];
struct
filter_pred
*
left
;
struct
filter_pred
*
left
;
struct
filter_pred
*
right
;
struct
filter_pred
*
right
;
*
dest
=
*
src
;
*
dest
=
*
src
;
if
(
src
->
field_name
)
{
dest
->
field_name
=
kstrdup
(
src
->
field_name
,
GFP_KERNEL
);
if
(
!
dest
->
field_name
)
return
-
ENOMEM
;
}
dest
->
fn
=
fn
;
dest
->
index
=
idx
;
dest
->
index
=
idx
;
if
(
dest
->
op
==
OP_OR
||
dest
->
op
==
OP_AND
)
{
if
(
dest
->
op
==
OP_OR
||
dest
->
op
==
OP_AND
)
{
...
@@ -743,11 +769,7 @@ static int filter_set_pred(struct event_filter *filter,
...
@@ -743,11 +769,7 @@ static int filter_set_pred(struct event_filter *filter,
static
void
__free_preds
(
struct
event_filter
*
filter
)
static
void
__free_preds
(
struct
event_filter
*
filter
)
{
{
int
i
;
if
(
filter
->
preds
)
{
if
(
filter
->
preds
)
{
for
(
i
=
0
;
i
<
filter
->
a_preds
;
i
++
)
kfree
(
filter
->
preds
[
i
].
field_name
);
kfree
(
filter
->
preds
);
kfree
(
filter
->
preds
);
filter
->
preds
=
NULL
;
filter
->
preds
=
NULL
;
}
}
...
@@ -840,23 +862,19 @@ static void filter_free_subsystem_filters(struct event_subsystem *system)
...
@@ -840,23 +862,19 @@ static void filter_free_subsystem_filters(struct event_subsystem *system)
}
}
}
}
static
int
filter_add_pred_fn
(
struct
filter_parse_state
*
ps
,
static
int
filter_add_pred
(
struct
filter_parse_state
*
ps
,
struct
ftrace_event_call
*
call
,
struct
event_filter
*
filter
,
struct
event_filter
*
filter
,
struct
filter_pred
*
pred
,
struct
filter_pred
*
pred
,
struct
pred_stack
*
stack
)
struct
pred_stack
*
stack
,
filter_pred_fn_t
fn
)
{
{
int
idx
,
err
;
int
err
;
if
(
WARN_ON
(
filter
->
n_preds
==
filter
->
a_preds
))
{
if
(
WARN_ON
(
filter
->
n_preds
==
filter
->
a_preds
))
{
parse_error
(
ps
,
FILT_ERR_TOO_MANY_PREDS
,
0
);
parse_error
(
ps
,
FILT_ERR_TOO_MANY_PREDS
,
0
);
return
-
ENOSPC
;
return
-
ENOSPC
;
}
}
idx
=
filter
->
n_preds
;
err
=
filter_set_pred
(
filter
,
filter
->
n_preds
,
stack
,
pred
);
filter_clear_pred
(
&
filter
->
preds
[
idx
]);
err
=
filter_set_pred
(
filter
,
idx
,
stack
,
pred
,
fn
);
if
(
err
)
if
(
err
)
return
err
;
return
err
;
...
@@ -937,31 +955,15 @@ static filter_pred_fn_t select_comparison_fn(int op, int field_size,
...
@@ -937,31 +955,15 @@ static filter_pred_fn_t select_comparison_fn(int op, int field_size,
return
fn
;
return
fn
;
}
}
static
int
filter_add_pred
(
struct
filter_parse_state
*
ps
,
static
int
init_pred
(
struct
filter_parse_state
*
ps
,
struct
ftrace_event_call
*
call
,
struct
ftrace_event_field
*
field
,
struct
event_filter
*
filter
,
struct
filter_pred
*
pred
)
struct
filter_pred
*
pred
,
struct
pred_stack
*
stack
,
bool
dry_run
)
{
{
struct
ftrace_event_field
*
field
;
filter_pred_fn_t
fn
=
filter_pred_none
;
filter_pred_fn_t
fn
;
unsigned
long
long
val
;
unsigned
long
long
val
;
int
ret
;
int
ret
;
fn
=
pred
->
fn
=
filter_pred_none
;
if
(
pred
->
op
==
OP_AND
)
goto
add_pred_fn
;
else
if
(
pred
->
op
==
OP_OR
)
goto
add_pred_fn
;
field
=
find_event_field
(
call
,
pred
->
field_name
);
if
(
!
field
)
{
parse_error
(
ps
,
FILT_ERR_FIELD_NOT_FOUND
,
0
);
return
-
EINVAL
;
}
pred
->
offset
=
field
->
offset
;
pred
->
offset
=
field
->
offset
;
if
(
!
is_legal_op
(
field
,
pred
->
op
))
{
if
(
!
is_legal_op
(
field
,
pred
->
op
))
{
...
@@ -1001,9 +1003,7 @@ static int filter_add_pred(struct filter_parse_state *ps,
...
@@ -1001,9 +1003,7 @@ static int filter_add_pred(struct filter_parse_state *ps,
if
(
pred
->
op
==
OP_NE
)
if
(
pred
->
op
==
OP_NE
)
pred
->
not
=
1
;
pred
->
not
=
1
;
add_pred_fn:
pred
->
fn
=
fn
;
if
(
!
dry_run
)
return
filter_add_pred_fn
(
ps
,
call
,
filter
,
pred
,
stack
,
fn
);
return
0
;
return
0
;
}
}
...
@@ -1302,39 +1302,37 @@ static int filter_parse(struct filter_parse_state *ps)
...
@@ -1302,39 +1302,37 @@ static int filter_parse(struct filter_parse_state *ps)
return
0
;
return
0
;
}
}
static
struct
filter_pred
*
create_pred
(
int
op
,
char
*
operand1
,
char
*
operand2
)
static
struct
filter_pred
*
create_pred
(
struct
filter_parse_state
*
ps
,
struct
ftrace_event_call
*
call
,
int
op
,
char
*
operand1
,
char
*
operand2
)
{
{
struct
filter_pred
*
pred
;
struct
ftrace_event_field
*
field
;
static
struct
filter_pred
pred
;
pred
=
kzalloc
(
sizeof
(
*
pred
),
GFP_KERNEL
);
memset
(
&
pred
,
0
,
sizeof
(
pred
));
if
(
!
pred
)
pred
.
op
=
op
;
return
NULL
;
pred
->
field_name
=
kstrdup
(
operand1
,
GFP_KERNEL
);
if
(
op
==
OP_AND
||
op
==
OP_OR
)
if
(
!
pred
->
field_name
)
{
return
&
pred
;
kfree
(
pred
);
if
(
!
operand1
||
!
operand2
)
{
parse_error
(
ps
,
FILT_ERR_MISSING_FIELD
,
0
);
return
NULL
;
return
NULL
;
}
}
strcpy
(
pred
->
regex
.
pattern
,
operand2
);
field
=
find_event_field
(
call
,
operand1
);
pred
->
regex
.
len
=
strlen
(
pred
->
regex
.
pattern
);
if
(
!
field
)
{
parse_error
(
ps
,
FILT_ERR_FIELD_NOT_FOUND
,
0
);
pred
->
op
=
op
;
return
pred
;
}
static
struct
filter_pred
*
create_logical_pred
(
int
op
)
{
struct
filter_pred
*
pred
;
pred
=
kzalloc
(
sizeof
(
*
pred
),
GFP_KERNEL
);
if
(
!
pred
)
return
NULL
;
return
NULL
;
}
pred
->
op
=
op
;
strcpy
(
pred
.
regex
.
pattern
,
operand2
);
pred
.
regex
.
len
=
strlen
(
pred
.
regex
.
pattern
);
return
pred
;
#ifdef CONFIG_FTRACE_STARTUP_TEST
pred
.
field
=
field
;
#endif
return
init_pred
(
ps
,
field
,
&
pred
)
?
NULL
:
&
pred
;
}
}
static
int
check_preds
(
struct
filter_parse_state
*
ps
)
static
int
check_preds
(
struct
filter_parse_state
*
ps
)
...
@@ -1375,6 +1373,23 @@ static int count_preds(struct filter_parse_state *ps)
...
@@ -1375,6 +1373,23 @@ static int count_preds(struct filter_parse_state *ps)
return
n_preds
;
return
n_preds
;
}
}
struct
check_pred_data
{
int
count
;
int
max
;
};
static
int
check_pred_tree_cb
(
enum
move_type
move
,
struct
filter_pred
*
pred
,
int
*
err
,
void
*
data
)
{
struct
check_pred_data
*
d
=
data
;
if
(
WARN_ON
(
d
->
count
++
>
d
->
max
))
{
*
err
=
-
EINVAL
;
return
WALK_PRED_ABORT
;
}
return
WALK_PRED_DEFAULT
;
}
/*
/*
* The tree is walked at filtering of an event. If the tree is not correctly
* The tree is walked at filtering of an event. If the tree is not correctly
* built, it may cause an infinite loop. Check here that the tree does
* built, it may cause an infinite loop. Check here that the tree does
...
@@ -1383,107 +1398,76 @@ static int count_preds(struct filter_parse_state *ps)
...
@@ -1383,107 +1398,76 @@ static int count_preds(struct filter_parse_state *ps)
static
int
check_pred_tree
(
struct
event_filter
*
filter
,
static
int
check_pred_tree
(
struct
event_filter
*
filter
,
struct
filter_pred
*
root
)
struct
filter_pred
*
root
)
{
{
struct
filter_pred
*
preds
;
struct
check_pred_data
data
=
{
struct
filter_pred
*
pred
;
/*
enum
move_type
move
=
MOVE_DOWN
;
* The max that we can hit a node is three times.
int
count
=
0
;
* Once going down, once coming up from left, and
int
done
=
0
;
* once coming up from right. This is more than enough
int
max
;
* since leafs are only hit a single time.
*/
/*
.
max
=
3
*
filter
->
n_preds
,
* The max that we can hit a node is three times.
.
count
=
0
,
* Once going down, once coming up from left, and
};
* once coming up from right. This is more than enough
* since leafs are only hit a single time.
*/
max
=
3
*
filter
->
n_preds
;
preds
=
filter
->
preds
;
return
walk_pred_tree
(
filter
->
preds
,
root
,
if
(
!
preds
)
check_pred_tree_cb
,
&
data
);
return
-
EINVAL
;
}
pred
=
root
;
do
{
static
int
count_leafs_cb
(
enum
move_type
move
,
struct
filter_pred
*
pred
,
if
(
WARN_ON
(
count
++
>
max
))
int
*
err
,
void
*
data
)
return
-
EINVAL
;
{
int
*
count
=
data
;
switch
(
move
)
{
if
((
move
==
MOVE_DOWN
)
&&
case
MOVE_DOWN
:
(
pred
->
left
==
FILTER_PRED_INVALID
))
if
(
pred
->
left
!=
FILTER_PRED_INVALID
)
{
(
*
count
)
++
;
pred
=
&
preds
[
pred
->
left
];
continue
;
}
/* A leaf at the root is just a leaf in the tree */
if
(
pred
==
root
)
break
;
pred
=
get_pred_parent
(
pred
,
preds
,
pred
->
parent
,
&
move
);
continue
;
case
MOVE_UP_FROM_LEFT
:
pred
=
&
preds
[
pred
->
right
];
move
=
MOVE_DOWN
;
continue
;
case
MOVE_UP_FROM_RIGHT
:
if
(
pred
==
root
)
break
;
pred
=
get_pred_parent
(
pred
,
preds
,
pred
->
parent
,
&
move
);
continue
;
}
done
=
1
;
}
while
(
!
done
);
/* We are fine. */
return
WALK_PRED_DEFAULT
;
return
0
;
}
}
static
int
count_leafs
(
struct
filter_pred
*
preds
,
struct
filter_pred
*
root
)
static
int
count_leafs
(
struct
filter_pred
*
preds
,
struct
filter_pred
*
root
)
{
{
struct
filter_pred
*
pred
;
int
count
=
0
,
ret
;
enum
move_type
move
=
MOVE_DOWN
;
int
count
=
0
;
int
done
=
0
;
pred
=
root
;
ret
=
walk_pred_tree
(
preds
,
root
,
count_leafs_cb
,
&
count
);
WARN_ON
(
ret
);
return
count
;
}
do
{
struct
fold_pred_data
{
switch
(
move
)
{
struct
filter_pred
*
root
;
case
MOVE_DOWN
:
int
count
;
if
(
pred
->
left
!=
FILTER_PRED_INVALID
)
{
int
children
;
pred
=
&
preds
[
pred
->
left
];
};
continue
;
}
/* A leaf at the root is just a leaf in the tree */
if
(
pred
==
root
)
return
1
;
count
++
;
pred
=
get_pred_parent
(
pred
,
preds
,
pred
->
parent
,
&
move
);
continue
;
case
MOVE_UP_FROM_LEFT
:
pred
=
&
preds
[
pred
->
right
];
move
=
MOVE_DOWN
;
continue
;
case
MOVE_UP_FROM_RIGHT
:
if
(
pred
==
root
)
break
;
pred
=
get_pred_parent
(
pred
,
preds
,
pred
->
parent
,
&
move
);
continue
;
}
done
=
1
;
}
while
(
!
done
);
return
count
;
static
int
fold_pred_cb
(
enum
move_type
move
,
struct
filter_pred
*
pred
,
int
*
err
,
void
*
data
)
{
struct
fold_pred_data
*
d
=
data
;
struct
filter_pred
*
root
=
d
->
root
;
if
(
move
!=
MOVE_DOWN
)
return
WALK_PRED_DEFAULT
;
if
(
pred
->
left
!=
FILTER_PRED_INVALID
)
return
WALK_PRED_DEFAULT
;
if
(
WARN_ON
(
d
->
count
==
d
->
children
))
{
*
err
=
-
EINVAL
;
return
WALK_PRED_ABORT
;
}
pred
->
index
&=
~
FILTER_PRED_FOLD
;
root
->
ops
[
d
->
count
++
]
=
pred
->
index
;
return
WALK_PRED_DEFAULT
;
}
}
static
int
fold_pred
(
struct
filter_pred
*
preds
,
struct
filter_pred
*
root
)
static
int
fold_pred
(
struct
filter_pred
*
preds
,
struct
filter_pred
*
root
)
{
{
struct
filter_pred
*
pred
;
struct
fold_pred_data
data
=
{
enum
move_type
move
=
MOVE_DOWN
;
.
root
=
root
,
int
count
=
0
;
.
count
=
0
,
};
int
children
;
int
children
;
int
done
=
0
;
/* No need to keep the fold flag */
/* No need to keep the fold flag */
root
->
index
&=
~
FILTER_PRED_FOLD
;
root
->
index
&=
~
FILTER_PRED_FOLD
;
...
@@ -1501,37 +1485,26 @@ static int fold_pred(struct filter_pred *preds, struct filter_pred *root)
...
@@ -1501,37 +1485,26 @@ static int fold_pred(struct filter_pred *preds, struct filter_pred *root)
return
-
ENOMEM
;
return
-
ENOMEM
;
root
->
val
=
children
;
root
->
val
=
children
;
data
.
children
=
children
;
return
walk_pred_tree
(
preds
,
root
,
fold_pred_cb
,
&
data
);
}
pred
=
root
;
static
int
fold_pred_tree_cb
(
enum
move_type
move
,
struct
filter_pred
*
pred
,
do
{
int
*
err
,
void
*
data
)
switch
(
move
)
{
{
case
MOVE_DOWN
:
struct
filter_pred
*
preds
=
data
;
if
(
pred
->
left
!=
FILTER_PRED_INVALID
)
{
pred
=
&
preds
[
pred
->
left
];
continue
;
}
if
(
WARN_ON
(
count
==
children
))
return
-
EINVAL
;
pred
->
index
&=
~
FILTER_PRED_FOLD
;
root
->
ops
[
count
++
]
=
pred
->
index
;
pred
=
get_pred_parent
(
pred
,
preds
,
pred
->
parent
,
&
move
);
continue
;
case
MOVE_UP_FROM_LEFT
:
pred
=
&
preds
[
pred
->
right
];
move
=
MOVE_DOWN
;
continue
;
case
MOVE_UP_FROM_RIGHT
:
if
(
pred
==
root
)
break
;
pred
=
get_pred_parent
(
pred
,
preds
,
pred
->
parent
,
&
move
);
continue
;
}
done
=
1
;
}
while
(
!
done
);
return
0
;
if
(
move
!=
MOVE_DOWN
)
return
WALK_PRED_DEFAULT
;
if
(
!
(
pred
->
index
&
FILTER_PRED_FOLD
))
return
WALK_PRED_DEFAULT
;
*
err
=
fold_pred
(
preds
,
pred
);
if
(
*
err
)
return
WALK_PRED_ABORT
;
/* eveyrhing below is folded, continue with parent */
return
WALK_PRED_PARENT
;
}
}
/*
/*
...
@@ -1542,51 +1515,8 @@ static int fold_pred(struct filter_pred *preds, struct filter_pred *root)
...
@@ -1542,51 +1515,8 @@ static int fold_pred(struct filter_pred *preds, struct filter_pred *root)
static
int
fold_pred_tree
(
struct
event_filter
*
filter
,
static
int
fold_pred_tree
(
struct
event_filter
*
filter
,
struct
filter_pred
*
root
)
struct
filter_pred
*
root
)
{
{
struct
filter_pred
*
preds
;
return
walk_pred_tree
(
filter
->
preds
,
root
,
fold_pred_tree_cb
,
struct
filter_pred
*
pred
;
filter
->
preds
);
enum
move_type
move
=
MOVE_DOWN
;
int
done
=
0
;
int
err
;
preds
=
filter
->
preds
;
if
(
!
preds
)
return
-
EINVAL
;
pred
=
root
;
do
{
switch
(
move
)
{
case
MOVE_DOWN
:
if
(
pred
->
index
&
FILTER_PRED_FOLD
)
{
err
=
fold_pred
(
preds
,
pred
);
if
(
err
)
return
err
;
/* Folded nodes are like leafs */
}
else
if
(
pred
->
left
!=
FILTER_PRED_INVALID
)
{
pred
=
&
preds
[
pred
->
left
];
continue
;
}
/* A leaf at the root is just a leaf in the tree */
if
(
pred
==
root
)
break
;
pred
=
get_pred_parent
(
pred
,
preds
,
pred
->
parent
,
&
move
);
continue
;
case
MOVE_UP_FROM_LEFT
:
pred
=
&
preds
[
pred
->
right
];
move
=
MOVE_DOWN
;
continue
;
case
MOVE_UP_FROM_RIGHT
:
if
(
pred
==
root
)
break
;
pred
=
get_pred_parent
(
pred
,
preds
,
pred
->
parent
,
&
move
);
continue
;
}
done
=
1
;
}
while
(
!
done
);
return
0
;
}
}
static
int
replace_preds
(
struct
ftrace_event_call
*
call
,
static
int
replace_preds
(
struct
ftrace_event_call
*
call
,
...
@@ -1643,27 +1573,17 @@ static int replace_preds(struct ftrace_event_call *call,
...
@@ -1643,27 +1573,17 @@ static int replace_preds(struct ftrace_event_call *call,
goto
fail
;
goto
fail
;
}
}
if
(
elt
->
op
==
OP_AND
||
elt
->
op
==
OP_OR
)
{
pred
=
create_pred
(
ps
,
call
,
elt
->
op
,
operand1
,
operand2
);
pred
=
create_logical_pred
(
elt
->
op
);
if
(
!
pred
)
{
goto
add_pred
;
}
if
(
!
operand1
||
!
operand2
)
{
parse_error
(
ps
,
FILT_ERR_MISSING_FIELD
,
0
);
err
=
-
EINVAL
;
err
=
-
EINVAL
;
goto
fail
;
goto
fail
;
}
}
pred
=
create_pred
(
elt
->
op
,
operand1
,
operand2
);
if
(
!
dry_run
)
{
add_pred:
err
=
filter_add_pred
(
ps
,
filter
,
pred
,
&
stack
);
if
(
!
pred
)
{
if
(
err
)
err
=
-
ENOMEM
;
goto
fail
;
goto
fail
;
}
}
err
=
filter_add_pred
(
ps
,
call
,
filter
,
pred
,
&
stack
,
dry_run
);
filter_free_pred
(
pred
);
if
(
err
)
goto
fail
;
operand1
=
operand2
=
NULL
;
operand1
=
operand2
=
NULL
;
}
}
...
@@ -1958,17 +1878,14 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id,
...
@@ -1958,17 +1878,14 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id,
int
err
;
int
err
;
struct
event_filter
*
filter
;
struct
event_filter
*
filter
;
struct
filter_parse_state
*
ps
;
struct
filter_parse_state
*
ps
;
struct
ftrace_event_call
*
call
=
NULL
;
struct
ftrace_event_call
*
call
;
mutex_lock
(
&
event_mutex
);
mutex_lock
(
&
event_mutex
);
list_for_each_entry
(
call
,
&
ftrace_events
,
list
)
{
call
=
event
->
tp_event
;
if
(
call
->
event
.
type
==
event_id
)
break
;
}
err
=
-
EINVAL
;
err
=
-
EINVAL
;
if
(
&
call
->
list
==
&
ftrace_events
)
if
(
!
call
)
goto
out_unlock
;
goto
out_unlock
;
err
=
-
EEXIST
;
err
=
-
EEXIST
;
...
@@ -2012,3 +1929,215 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id,
...
@@ -2012,3 +1929,215 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id,
#endif
/* CONFIG_PERF_EVENTS */
#endif
/* CONFIG_PERF_EVENTS */
#ifdef CONFIG_FTRACE_STARTUP_TEST
#include <linux/types.h>
#include <linux/tracepoint.h>
#define CREATE_TRACE_POINTS
#include "trace_events_filter_test.h"
static
int
test_get_filter
(
char
*
filter_str
,
struct
ftrace_event_call
*
call
,
struct
event_filter
**
pfilter
)
{
struct
event_filter
*
filter
;
struct
filter_parse_state
*
ps
;
int
err
=
-
ENOMEM
;
filter
=
__alloc_filter
();
if
(
!
filter
)
goto
out
;
ps
=
kzalloc
(
sizeof
(
*
ps
),
GFP_KERNEL
);
if
(
!
ps
)
goto
free_filter
;
parse_init
(
ps
,
filter_ops
,
filter_str
);
err
=
filter_parse
(
ps
);
if
(
err
)
goto
free_ps
;
err
=
replace_preds
(
call
,
filter
,
ps
,
filter_str
,
false
);
if
(
!
err
)
*
pfilter
=
filter
;
free_ps:
filter_opstack_clear
(
ps
);
postfix_clear
(
ps
);
kfree
(
ps
);
free_filter:
if
(
err
)
__free_filter
(
filter
);
out:
return
err
;
}
#define DATA_REC(m, va, vb, vc, vd, ve, vf, vg, vh, nvisit) \
{ \
.filter = FILTER, \
.rec = { .a = va, .b = vb, .c = vc, .d = vd, \
.e = ve, .f = vf, .g = vg, .h = vh }, \
.match = m, \
.not_visited = nvisit, \
}
#define YES 1
#define NO 0
static
struct
test_filter_data_t
{
char
*
filter
;
struct
ftrace_raw_ftrace_test_filter
rec
;
int
match
;
char
*
not_visited
;
}
test_filter_data
[]
=
{
#define FILTER "a == 1 && b == 1 && c == 1 && d == 1 && " \
"e == 1 && f == 1 && g == 1 && h == 1"
DATA_REC
(
YES
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
""
),
DATA_REC
(
NO
,
0
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
"bcdefgh"
),
DATA_REC
(
NO
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
0
,
""
),
#undef FILTER
#define FILTER "a == 1 || b == 1 || c == 1 || d == 1 || " \
"e == 1 || f == 1 || g == 1 || h == 1"
DATA_REC
(
NO
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
""
),
DATA_REC
(
YES
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
1
,
""
),
DATA_REC
(
YES
,
1
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
"bcdefgh"
),
#undef FILTER
#define FILTER "(a == 1 || b == 1) && (c == 1 || d == 1) && " \
"(e == 1 || f == 1) && (g == 1 || h == 1)"
DATA_REC
(
NO
,
0
,
0
,
1
,
1
,
1
,
1
,
1
,
1
,
"dfh"
),
DATA_REC
(
YES
,
0
,
1
,
0
,
1
,
0
,
1
,
0
,
1
,
""
),
DATA_REC
(
YES
,
1
,
0
,
1
,
0
,
0
,
1
,
0
,
1
,
"bd"
),
DATA_REC
(
NO
,
1
,
0
,
1
,
0
,
0
,
1
,
0
,
0
,
"bd"
),
#undef FILTER
#define FILTER "(a == 1 && b == 1) || (c == 1 && d == 1) || " \
"(e == 1 && f == 1) || (g == 1 && h == 1)"
DATA_REC
(
YES
,
1
,
0
,
1
,
1
,
1
,
1
,
1
,
1
,
"efgh"
),
DATA_REC
(
YES
,
0
,
0
,
0
,
0
,
0
,
0
,
1
,
1
,
""
),
DATA_REC
(
NO
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
1
,
""
),
#undef FILTER
#define FILTER "(a == 1 && b == 1) && (c == 1 && d == 1) && " \
"(e == 1 && f == 1) || (g == 1 && h == 1)"
DATA_REC
(
YES
,
1
,
1
,
1
,
1
,
1
,
1
,
0
,
0
,
"gh"
),
DATA_REC
(
NO
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
1
,
""
),
DATA_REC
(
YES
,
1
,
1
,
1
,
1
,
1
,
0
,
1
,
1
,
""
),
#undef FILTER
#define FILTER "((a == 1 || b == 1) || (c == 1 || d == 1) || " \
"(e == 1 || f == 1)) && (g == 1 || h == 1)"
DATA_REC
(
YES
,
1
,
1
,
1
,
1
,
1
,
1
,
0
,
1
,
"bcdef"
),
DATA_REC
(
NO
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
""
),
DATA_REC
(
YES
,
1
,
1
,
1
,
1
,
1
,
0
,
1
,
1
,
"h"
),
#undef FILTER
#define FILTER "((((((((a == 1) && (b == 1)) || (c == 1)) && (d == 1)) || " \
"(e == 1)) && (f == 1)) || (g == 1)) && (h == 1))"
DATA_REC
(
YES
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
"ceg"
),
DATA_REC
(
NO
,
0
,
1
,
0
,
1
,
0
,
1
,
0
,
1
,
""
),
DATA_REC
(
NO
,
1
,
0
,
1
,
0
,
1
,
0
,
1
,
0
,
""
),
#undef FILTER
#define FILTER "((((((((a == 1) || (b == 1)) && (c == 1)) || (d == 1)) && " \
"(e == 1)) || (f == 1)) && (g == 1)) || (h == 1))"
DATA_REC
(
YES
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
"bdfh"
),
DATA_REC
(
YES
,
0
,
1
,
0
,
1
,
0
,
1
,
0
,
1
,
""
),
DATA_REC
(
YES
,
1
,
0
,
1
,
0
,
1
,
0
,
1
,
0
,
"bdfh"
),
};
#undef DATA_REC
#undef FILTER
#undef YES
#undef NO
#define DATA_CNT (sizeof(test_filter_data)/sizeof(struct test_filter_data_t))
static
int
test_pred_visited
;
static
int
test_pred_visited_fn
(
struct
filter_pred
*
pred
,
void
*
event
)
{
struct
ftrace_event_field
*
field
=
pred
->
field
;
test_pred_visited
=
1
;
printk
(
KERN_INFO
"
\n
pred visited %s
\n
"
,
field
->
name
);
return
1
;
}
static
int
test_walk_pred_cb
(
enum
move_type
move
,
struct
filter_pred
*
pred
,
int
*
err
,
void
*
data
)
{
char
*
fields
=
data
;
if
((
move
==
MOVE_DOWN
)
&&
(
pred
->
left
==
FILTER_PRED_INVALID
))
{
struct
ftrace_event_field
*
field
=
pred
->
field
;
if
(
!
field
)
{
WARN
(
1
,
"all leafs should have field defined"
);
return
WALK_PRED_DEFAULT
;
}
if
(
!
strchr
(
fields
,
*
field
->
name
))
return
WALK_PRED_DEFAULT
;
WARN_ON
(
!
pred
->
fn
);
pred
->
fn
=
test_pred_visited_fn
;
}
return
WALK_PRED_DEFAULT
;
}
static
__init
int
ftrace_test_event_filter
(
void
)
{
int
i
;
printk
(
KERN_INFO
"Testing ftrace filter: "
);
for
(
i
=
0
;
i
<
DATA_CNT
;
i
++
)
{
struct
event_filter
*
filter
=
NULL
;
struct
test_filter_data_t
*
d
=
&
test_filter_data
[
i
];
int
err
;
err
=
test_get_filter
(
d
->
filter
,
&
event_ftrace_test_filter
,
&
filter
);
if
(
err
)
{
printk
(
KERN_INFO
"Failed to get filter for '%s', err %d
\n
"
,
d
->
filter
,
err
);
break
;
}
/*
* The preemption disabling is not really needed for self
* tests, but the rcu dereference will complain without it.
*/
preempt_disable
();
if
(
*
d
->
not_visited
)
walk_pred_tree
(
filter
->
preds
,
filter
->
root
,
test_walk_pred_cb
,
d
->
not_visited
);
test_pred_visited
=
0
;
err
=
filter_match_preds
(
filter
,
&
d
->
rec
);
preempt_enable
();
__free_filter
(
filter
);
if
(
test_pred_visited
)
{
printk
(
KERN_INFO
"Failed, unwanted pred visited for filter %s
\n
"
,
d
->
filter
);
break
;
}
if
(
err
!=
d
->
match
)
{
printk
(
KERN_INFO
"Failed to match filter '%s', expected %d
\n
"
,
d
->
filter
,
d
->
match
);
break
;
}
}
if
(
i
==
DATA_CNT
)
printk
(
KERN_CONT
"OK
\n
"
);
return
0
;
}
late_initcall
(
ftrace_test_event_filter
);
#endif
/* CONFIG_FTRACE_STARTUP_TEST */
kernel/trace/trace_events_filter_test.h
0 → 100644
View file @
910e94dd
#undef TRACE_SYSTEM
#define TRACE_SYSTEM test
#if !defined(_TRACE_TEST_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_TEST_H
#include <linux/tracepoint.h>
TRACE_EVENT
(
ftrace_test_filter
,
TP_PROTO
(
int
a
,
int
b
,
int
c
,
int
d
,
int
e
,
int
f
,
int
g
,
int
h
),
TP_ARGS
(
a
,
b
,
c
,
d
,
e
,
f
,
g
,
h
),
TP_STRUCT__entry
(
__field
(
int
,
a
)
__field
(
int
,
b
)
__field
(
int
,
c
)
__field
(
int
,
d
)
__field
(
int
,
e
)
__field
(
int
,
f
)
__field
(
int
,
g
)
__field
(
int
,
h
)
),
TP_fast_assign
(
__entry
->
a
=
a
;
__entry
->
b
=
b
;
__entry
->
c
=
c
;
__entry
->
d
=
d
;
__entry
->
e
=
e
;
__entry
->
f
=
f
;
__entry
->
g
=
g
;
__entry
->
h
=
h
;
),
TP_printk
(
"a %d, b %d, c %d, d %d, e %d, f %d, g %d, h %d"
,
__entry
->
a
,
__entry
->
b
,
__entry
->
c
,
__entry
->
d
,
__entry
->
e
,
__entry
->
f
,
__entry
->
g
,
__entry
->
h
)
);
#endif
/* _TRACE_TEST_H || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_PATH .
#define TRACE_INCLUDE_FILE trace_events_filter_test
/* This part must be outside protection */
#include <trace/define_trace.h>
kernel/trace/trace_irqsoff.c
View file @
910e94dd
...
@@ -505,13 +505,13 @@ EXPORT_SYMBOL(trace_hardirqs_off_caller);
...
@@ -505,13 +505,13 @@ EXPORT_SYMBOL(trace_hardirqs_off_caller);
#ifdef CONFIG_PREEMPT_TRACER
#ifdef CONFIG_PREEMPT_TRACER
void
trace_preempt_on
(
unsigned
long
a0
,
unsigned
long
a1
)
void
trace_preempt_on
(
unsigned
long
a0
,
unsigned
long
a1
)
{
{
if
(
preempt_trace
())
if
(
preempt_trace
()
&&
!
irq_trace
()
)
stop_critical_timing
(
a0
,
a1
);
stop_critical_timing
(
a0
,
a1
);
}
}
void
trace_preempt_off
(
unsigned
long
a0
,
unsigned
long
a1
)
void
trace_preempt_off
(
unsigned
long
a0
,
unsigned
long
a1
)
{
{
if
(
preempt_trace
())
if
(
preempt_trace
()
&&
!
irq_trace
()
)
start_critical_timing
(
a0
,
a1
);
start_critical_timing
(
a0
,
a1
);
}
}
#endif
/* CONFIG_PREEMPT_TRACER */
#endif
/* CONFIG_PREEMPT_TRACER */
...
...
kernel/trace/trace_printk.c
View file @
910e94dd
...
@@ -59,18 +59,19 @@ void hold_module_trace_bprintk_format(const char **start, const char **end)
...
@@ -59,18 +59,19 @@ void hold_module_trace_bprintk_format(const char **start, const char **end)
continue
;
continue
;
}
}
fmt
=
NULL
;
tb_fmt
=
kmalloc
(
sizeof
(
*
tb_fmt
),
GFP_KERNEL
);
tb_fmt
=
kmalloc
(
sizeof
(
*
tb_fmt
),
GFP_KERNEL
);
if
(
tb_fmt
)
if
(
tb_fmt
)
{
fmt
=
kmalloc
(
strlen
(
*
iter
)
+
1
,
GFP_KERNEL
);
fmt
=
kmalloc
(
strlen
(
*
iter
)
+
1
,
GFP_KERNEL
);
if
(
tb_fmt
&&
fmt
)
{
if
(
fmt
)
{
list_add_tail
(
&
tb_fmt
->
list
,
&
trace_bprintk_fmt_list
);
list_add_tail
(
&
tb_fmt
->
list
,
&
trace_bprintk_fmt_list
);
strcpy
(
fmt
,
*
iter
);
strcpy
(
fmt
,
*
iter
);
tb_fmt
->
fmt
=
fmt
;
tb_fmt
->
fmt
=
fmt
;
*
iter
=
tb_fmt
->
fmt
;
}
else
}
else
{
kfree
(
tb_fmt
);
kfree
(
tb_fmt
);
*
iter
=
NULL
;
}
}
*
iter
=
fmt
;
}
}
mutex_unlock
(
&
btrace_mutex
);
mutex_unlock
(
&
btrace_mutex
);
}
}
...
...
kernel/tracepoint.c
View file @
910e94dd
...
@@ -34,11 +34,16 @@ extern struct tracepoint * const __stop___tracepoints_ptrs[];
...
@@ -34,11 +34,16 @@ extern struct tracepoint * const __stop___tracepoints_ptrs[];
static
const
int
tracepoint_debug
;
static
const
int
tracepoint_debug
;
/*
/*
*
tracepoints_mutex nests inside module_mutex. Tracepoints mutex protects the
*
Tracepoints mutex protects the builtin and module tracepoints and the hash
*
builtin and module tracepoints and the hash table
.
*
table, as well as the local module list
.
*/
*/
static
DEFINE_MUTEX
(
tracepoints_mutex
);
static
DEFINE_MUTEX
(
tracepoints_mutex
);
#ifdef CONFIG_MODULES
/* Local list of struct module */
static
LIST_HEAD
(
tracepoint_module_list
);
#endif
/* CONFIG_MODULES */
/*
/*
* Tracepoint hash table, containing the active tracepoints.
* Tracepoint hash table, containing the active tracepoints.
* Protected by tracepoints_mutex.
* Protected by tracepoints_mutex.
...
@@ -292,9 +297,10 @@ static void disable_tracepoint(struct tracepoint *elem)
...
@@ -292,9 +297,10 @@ static void disable_tracepoint(struct tracepoint *elem)
* @end: end of the range
* @end: end of the range
*
*
* Updates the probe callback corresponding to a range of tracepoints.
* Updates the probe callback corresponding to a range of tracepoints.
* Called with tracepoints_mutex held.
*/
*/
void
tracepoint_update_probe_range
(
struct
tracepoint
*
const
*
begin
,
static
void
tracepoint_update_probe_range
(
struct
tracepoint
*
const
*
begin
,
struct
tracepoint
*
const
*
end
)
struct
tracepoint
*
const
*
end
)
{
{
struct
tracepoint
*
const
*
iter
;
struct
tracepoint
*
const
*
iter
;
struct
tracepoint_entry
*
mark_entry
;
struct
tracepoint_entry
*
mark_entry
;
...
@@ -302,7 +308,6 @@ void tracepoint_update_probe_range(struct tracepoint * const *begin,
...
@@ -302,7 +308,6 @@ void tracepoint_update_probe_range(struct tracepoint * const *begin,
if
(
!
begin
)
if
(
!
begin
)
return
;
return
;
mutex_lock
(
&
tracepoints_mutex
);
for
(
iter
=
begin
;
iter
<
end
;
iter
++
)
{
for
(
iter
=
begin
;
iter
<
end
;
iter
++
)
{
mark_entry
=
get_tracepoint
((
*
iter
)
->
name
);
mark_entry
=
get_tracepoint
((
*
iter
)
->
name
);
if
(
mark_entry
)
{
if
(
mark_entry
)
{
...
@@ -312,11 +317,27 @@ void tracepoint_update_probe_range(struct tracepoint * const *begin,
...
@@ -312,11 +317,27 @@ void tracepoint_update_probe_range(struct tracepoint * const *begin,
disable_tracepoint
(
*
iter
);
disable_tracepoint
(
*
iter
);
}
}
}
}
mutex_unlock
(
&
tracepoints_mutex
);
}
}
#ifdef CONFIG_MODULES
void
module_update_tracepoints
(
void
)
{
struct
tp_module
*
tp_mod
;
list_for_each_entry
(
tp_mod
,
&
tracepoint_module_list
,
list
)
tracepoint_update_probe_range
(
tp_mod
->
tracepoints_ptrs
,
tp_mod
->
tracepoints_ptrs
+
tp_mod
->
num_tracepoints
);
}
#else
/* CONFIG_MODULES */
void
module_update_tracepoints
(
void
)
{
}
#endif
/* CONFIG_MODULES */
/*
/*
* Update probes, removing the faulty probes.
* Update probes, removing the faulty probes.
* Called with tracepoints_mutex held.
*/
*/
static
void
tracepoint_update_probes
(
void
)
static
void
tracepoint_update_probes
(
void
)
{
{
...
@@ -359,11 +380,12 @@ int tracepoint_probe_register(const char *name, void *probe, void *data)
...
@@ -359,11 +380,12 @@ int tracepoint_probe_register(const char *name, void *probe, void *data)
mutex_lock
(
&
tracepoints_mutex
);
mutex_lock
(
&
tracepoints_mutex
);
old
=
tracepoint_add_probe
(
name
,
probe
,
data
);
old
=
tracepoint_add_probe
(
name
,
probe
,
data
);
mutex_unlock
(
&
tracepoints_mutex
);
if
(
IS_ERR
(
old
))
{
if
(
IS_ERR
(
old
))
mutex_unlock
(
&
tracepoints_mutex
);
return
PTR_ERR
(
old
);
return
PTR_ERR
(
old
);
}
tracepoint_update_probes
();
/* may update entry */
tracepoint_update_probes
();
/* may update entry */
mutex_unlock
(
&
tracepoints_mutex
);
release_probes
(
old
);
release_probes
(
old
);
return
0
;
return
0
;
}
}
...
@@ -402,11 +424,12 @@ int tracepoint_probe_unregister(const char *name, void *probe, void *data)
...
@@ -402,11 +424,12 @@ int tracepoint_probe_unregister(const char *name, void *probe, void *data)
mutex_lock
(
&
tracepoints_mutex
);
mutex_lock
(
&
tracepoints_mutex
);
old
=
tracepoint_remove_probe
(
name
,
probe
,
data
);
old
=
tracepoint_remove_probe
(
name
,
probe
,
data
);
mutex_unlock
(
&
tracepoints_mutex
);
if
(
IS_ERR
(
old
))
{
if
(
IS_ERR
(
old
))
mutex_unlock
(
&
tracepoints_mutex
);
return
PTR_ERR
(
old
);
return
PTR_ERR
(
old
);
}
tracepoint_update_probes
();
/* may update entry */
tracepoint_update_probes
();
/* may update entry */
mutex_unlock
(
&
tracepoints_mutex
);
release_probes
(
old
);
release_probes
(
old
);
return
0
;
return
0
;
}
}
...
@@ -489,9 +512,8 @@ void tracepoint_probe_update_all(void)
...
@@ -489,9 +512,8 @@ void tracepoint_probe_update_all(void)
if
(
!
list_empty
(
&
old_probes
))
if
(
!
list_empty
(
&
old_probes
))
list_replace_init
(
&
old_probes
,
&
release_probes
);
list_replace_init
(
&
old_probes
,
&
release_probes
);
need_update
=
0
;
need_update
=
0
;
mutex_unlock
(
&
tracepoints_mutex
);
tracepoint_update_probes
();
tracepoint_update_probes
();
mutex_unlock
(
&
tracepoints_mutex
);
list_for_each_entry_safe
(
pos
,
next
,
&
release_probes
,
u
.
list
)
{
list_for_each_entry_safe
(
pos
,
next
,
&
release_probes
,
u
.
list
)
{
list_del
(
&
pos
->
u
.
list
);
list_del
(
&
pos
->
u
.
list
);
call_rcu_sched
(
&
pos
->
u
.
rcu
,
rcu_free_old_probes
);
call_rcu_sched
(
&
pos
->
u
.
rcu
,
rcu_free_old_probes
);
...
@@ -509,7 +531,7 @@ EXPORT_SYMBOL_GPL(tracepoint_probe_update_all);
...
@@ -509,7 +531,7 @@ EXPORT_SYMBOL_GPL(tracepoint_probe_update_all);
* Will return the first tracepoint in the range if the input tracepoint is
* Will return the first tracepoint in the range if the input tracepoint is
* NULL.
* NULL.
*/
*/
int
tracepoint_get_iter_range
(
struct
tracepoint
*
const
**
tracepoint
,
static
int
tracepoint_get_iter_range
(
struct
tracepoint
*
const
**
tracepoint
,
struct
tracepoint
*
const
*
begin
,
struct
tracepoint
*
const
*
end
)
struct
tracepoint
*
const
*
begin
,
struct
tracepoint
*
const
*
end
)
{
{
if
(
!*
tracepoint
&&
begin
!=
end
)
{
if
(
!*
tracepoint
&&
begin
!=
end
)
{
...
@@ -520,11 +542,12 @@ int tracepoint_get_iter_range(struct tracepoint * const **tracepoint,
...
@@ -520,11 +542,12 @@ int tracepoint_get_iter_range(struct tracepoint * const **tracepoint,
return
1
;
return
1
;
return
0
;
return
0
;
}
}
EXPORT_SYMBOL_GPL
(
tracepoint_get_iter_range
);
#ifdef CONFIG_MODULES
static
void
tracepoint_get_iter
(
struct
tracepoint_iter
*
iter
)
static
void
tracepoint_get_iter
(
struct
tracepoint_iter
*
iter
)
{
{
int
found
=
0
;
int
found
=
0
;
struct
tp_module
*
iter_mod
;
/* Core kernel tracepoints */
/* Core kernel tracepoints */
if
(
!
iter
->
module
)
{
if
(
!
iter
->
module
)
{
...
@@ -534,12 +557,43 @@ static void tracepoint_get_iter(struct tracepoint_iter *iter)
...
@@ -534,12 +557,43 @@ static void tracepoint_get_iter(struct tracepoint_iter *iter)
if
(
found
)
if
(
found
)
goto
end
;
goto
end
;
}
}
/* tracepoints in modules. */
/* Tracepoints in modules */
found
=
module_get_iter_tracepoints
(
iter
);
mutex_lock
(
&
tracepoints_mutex
);
list_for_each_entry
(
iter_mod
,
&
tracepoint_module_list
,
list
)
{
/*
* Sorted module list
*/
if
(
iter_mod
<
iter
->
module
)
continue
;
else
if
(
iter_mod
>
iter
->
module
)
iter
->
tracepoint
=
NULL
;
found
=
tracepoint_get_iter_range
(
&
iter
->
tracepoint
,
iter_mod
->
tracepoints_ptrs
,
iter_mod
->
tracepoints_ptrs
+
iter_mod
->
num_tracepoints
);
if
(
found
)
{
iter
->
module
=
iter_mod
;
break
;
}
}
mutex_unlock
(
&
tracepoints_mutex
);
end:
end:
if
(
!
found
)
if
(
!
found
)
tracepoint_iter_reset
(
iter
);
tracepoint_iter_reset
(
iter
);
}
}
#else
/* CONFIG_MODULES */
static
void
tracepoint_get_iter
(
struct
tracepoint_iter
*
iter
)
{
int
found
=
0
;
/* Core kernel tracepoints */
found
=
tracepoint_get_iter_range
(
&
iter
->
tracepoint
,
__start___tracepoints_ptrs
,
__stop___tracepoints_ptrs
);
if
(
!
found
)
tracepoint_iter_reset
(
iter
);
}
#endif
/* CONFIG_MODULES */
void
tracepoint_iter_start
(
struct
tracepoint_iter
*
iter
)
void
tracepoint_iter_start
(
struct
tracepoint_iter
*
iter
)
{
{
...
@@ -566,26 +620,98 @@ EXPORT_SYMBOL_GPL(tracepoint_iter_stop);
...
@@ -566,26 +620,98 @@ EXPORT_SYMBOL_GPL(tracepoint_iter_stop);
void
tracepoint_iter_reset
(
struct
tracepoint_iter
*
iter
)
void
tracepoint_iter_reset
(
struct
tracepoint_iter
*
iter
)
{
{
#ifdef CONFIG_MODULES
iter
->
module
=
NULL
;
iter
->
module
=
NULL
;
#endif
/* CONFIG_MODULES */
iter
->
tracepoint
=
NULL
;
iter
->
tracepoint
=
NULL
;
}
}
EXPORT_SYMBOL_GPL
(
tracepoint_iter_reset
);
EXPORT_SYMBOL_GPL
(
tracepoint_iter_reset
);
#ifdef CONFIG_MODULES
#ifdef CONFIG_MODULES
static
int
tracepoint_module_coming
(
struct
module
*
mod
)
{
struct
tp_module
*
tp_mod
,
*
iter
;
int
ret
=
0
;
/*
* We skip modules that tain the kernel, especially those with different
* module header (for forced load), to make sure we don't cause a crash.
*/
if
(
mod
->
taints
)
return
0
;
mutex_lock
(
&
tracepoints_mutex
);
tp_mod
=
kmalloc
(
sizeof
(
struct
tp_module
),
GFP_KERNEL
);
if
(
!
tp_mod
)
{
ret
=
-
ENOMEM
;
goto
end
;
}
tp_mod
->
num_tracepoints
=
mod
->
num_tracepoints
;
tp_mod
->
tracepoints_ptrs
=
mod
->
tracepoints_ptrs
;
/*
* tracepoint_module_list is kept sorted by struct module pointer
* address for iteration on tracepoints from a seq_file that can release
* the mutex between calls.
*/
list_for_each_entry_reverse
(
iter
,
&
tracepoint_module_list
,
list
)
{
BUG_ON
(
iter
==
tp_mod
);
/* Should never be in the list twice */
if
(
iter
<
tp_mod
)
{
/* We belong to the location right after iter. */
list_add
(
&
tp_mod
->
list
,
&
iter
->
list
);
goto
module_added
;
}
}
/* We belong to the beginning of the list */
list_add
(
&
tp_mod
->
list
,
&
tracepoint_module_list
);
module_added:
tracepoint_update_probe_range
(
mod
->
tracepoints_ptrs
,
mod
->
tracepoints_ptrs
+
mod
->
num_tracepoints
);
end:
mutex_unlock
(
&
tracepoints_mutex
);
return
ret
;
}
static
int
tracepoint_module_going
(
struct
module
*
mod
)
{
struct
tp_module
*
pos
;
mutex_lock
(
&
tracepoints_mutex
);
tracepoint_update_probe_range
(
mod
->
tracepoints_ptrs
,
mod
->
tracepoints_ptrs
+
mod
->
num_tracepoints
);
list_for_each_entry
(
pos
,
&
tracepoint_module_list
,
list
)
{
if
(
pos
->
tracepoints_ptrs
==
mod
->
tracepoints_ptrs
)
{
list_del
(
&
pos
->
list
);
kfree
(
pos
);
break
;
}
}
/*
* In the case of modules that were tainted at "coming", we'll simply
* walk through the list without finding it. We cannot use the "tainted"
* flag on "going", in case a module taints the kernel only after being
* loaded.
*/
mutex_unlock
(
&
tracepoints_mutex
);
return
0
;
}
int
tracepoint_module_notify
(
struct
notifier_block
*
self
,
int
tracepoint_module_notify
(
struct
notifier_block
*
self
,
unsigned
long
val
,
void
*
data
)
unsigned
long
val
,
void
*
data
)
{
{
struct
module
*
mod
=
data
;
struct
module
*
mod
=
data
;
int
ret
=
0
;
switch
(
val
)
{
switch
(
val
)
{
case
MODULE_STATE_COMING
:
case
MODULE_STATE_COMING
:
ret
=
tracepoint_module_coming
(
mod
);
break
;
case
MODULE_STATE_LIVE
:
break
;
case
MODULE_STATE_GOING
:
case
MODULE_STATE_GOING
:
tracepoint_update_probe_range
(
mod
->
tracepoints_ptrs
,
ret
=
tracepoint_module_going
(
mod
);
mod
->
tracepoints_ptrs
+
mod
->
num_tracepoints
);
break
;
break
;
}
}
return
0
;
return
ret
;
}
}
struct
notifier_block
tracepoint_module_nb
=
{
struct
notifier_block
tracepoint_module_nb
=
{
...
@@ -598,7 +724,6 @@ static int init_tracepoints(void)
...
@@ -598,7 +724,6 @@ static int init_tracepoints(void)
return
register_module_notifier
(
&
tracepoint_module_nb
);
return
register_module_notifier
(
&
tracepoint_module_nb
);
}
}
__initcall
(
init_tracepoints
);
__initcall
(
init_tracepoints
);
#endif
/* CONFIG_MODULES */
#endif
/* CONFIG_MODULES */
#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment