tracing: Replace trace_event struct array with pointer array
Currently the trace_event structures are placed in the _ftrace_events section, and at link time, the linker makes one large array of all the trace_event structures. On boot up, this array is read (much like the initcall sections) and the events are processed. The problem is that there is no guarantee that gcc will place complex structures nicely together in an array format. Two structures in the same file may be placed awkwardly, because gcc has no clue that they are suppose to be in an array. A hack was used previous to force the alignment to 4, to pack the structures together. But this caused alignment issues with other architectures (sparc). Instead of packing the structures into an array, the structures' addresses are now put into the _ftrace_event section. As pointers are always the natural alignment, gcc should always pack them tightly together (otherwise initcall, extable, etc would also fail). By having the pointers to the structures in the section, we can still iterate the trace_events without causing unnecessary alignment problems with other architectures, or depending on the current behaviour of gcc that will likely change in the future just to tick us kernel developers off a little more. The _ftrace_event section is also moved into the .init.data section as it is now only needed at boot up. Suggested-by: David Miller <davem@davemloft.net> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Acked-by: David S. Miller <davem@davemloft.net> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
This commit is contained in:
Родитель
9ffdc6c37d
Коммит
e4a9ea5ee7
|
@ -124,7 +124,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_EVENT_TRACING
|
#ifdef CONFIG_EVENT_TRACING
|
||||||
#define FTRACE_EVENTS() VMLINUX_SYMBOL(__start_ftrace_events) = .; \
|
#define FTRACE_EVENTS() . = ALIGN(8); \
|
||||||
|
VMLINUX_SYMBOL(__start_ftrace_events) = .; \
|
||||||
*(_ftrace_events) \
|
*(_ftrace_events) \
|
||||||
VMLINUX_SYMBOL(__stop_ftrace_events) = .;
|
VMLINUX_SYMBOL(__stop_ftrace_events) = .;
|
||||||
#else
|
#else
|
||||||
|
@ -179,9 +180,6 @@
|
||||||
TRACE_PRINTKS() \
|
TRACE_PRINTKS() \
|
||||||
\
|
\
|
||||||
STRUCT_ALIGN(); \
|
STRUCT_ALIGN(); \
|
||||||
FTRACE_EVENTS() \
|
|
||||||
\
|
|
||||||
STRUCT_ALIGN(); \
|
|
||||||
TRACE_SYSCALLS()
|
TRACE_SYSCALLS()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -482,6 +480,7 @@
|
||||||
KERNEL_CTORS() \
|
KERNEL_CTORS() \
|
||||||
*(.init.rodata) \
|
*(.init.rodata) \
|
||||||
MCOUNT_REC() \
|
MCOUNT_REC() \
|
||||||
|
FTRACE_EVENTS() \
|
||||||
DEV_DISCARD(init.rodata) \
|
DEV_DISCARD(init.rodata) \
|
||||||
CPU_DISCARD(init.rodata) \
|
CPU_DISCARD(init.rodata) \
|
||||||
MEM_DISCARD(init.rodata) \
|
MEM_DISCARD(init.rodata) \
|
||||||
|
|
|
@ -389,7 +389,7 @@ struct module
|
||||||
unsigned int num_trace_bprintk_fmt;
|
unsigned int num_trace_bprintk_fmt;
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_EVENT_TRACING
|
#ifdef CONFIG_EVENT_TRACING
|
||||||
struct ftrace_event_call *trace_events;
|
struct ftrace_event_call **trace_events;
|
||||||
unsigned int num_trace_events;
|
unsigned int num_trace_events;
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_FTRACE_MCOUNT_RECORD
|
#ifdef CONFIG_FTRACE_MCOUNT_RECORD
|
||||||
|
|
|
@ -128,28 +128,30 @@ extern struct trace_event_functions exit_syscall_print_funcs;
|
||||||
static struct syscall_metadata \
|
static struct syscall_metadata \
|
||||||
__attribute__((__aligned__(4))) __syscall_meta_##sname; \
|
__attribute__((__aligned__(4))) __syscall_meta_##sname; \
|
||||||
static struct ftrace_event_call __used \
|
static struct ftrace_event_call __used \
|
||||||
__attribute__((__aligned__(4))) \
|
|
||||||
__attribute__((section("_ftrace_events"))) \
|
|
||||||
event_enter_##sname = { \
|
event_enter_##sname = { \
|
||||||
.name = "sys_enter"#sname, \
|
.name = "sys_enter"#sname, \
|
||||||
.class = &event_class_syscall_enter, \
|
.class = &event_class_syscall_enter, \
|
||||||
.event.funcs = &enter_syscall_print_funcs, \
|
.event.funcs = &enter_syscall_print_funcs, \
|
||||||
.data = (void *)&__syscall_meta_##sname,\
|
.data = (void *)&__syscall_meta_##sname,\
|
||||||
}; \
|
}; \
|
||||||
|
static struct ftrace_event_call __used \
|
||||||
|
__attribute__((section("_ftrace_events"))) \
|
||||||
|
*__event_enter_##sname = &event_enter_##sname; \
|
||||||
__TRACE_EVENT_FLAGS(enter_##sname, TRACE_EVENT_FL_CAP_ANY)
|
__TRACE_EVENT_FLAGS(enter_##sname, TRACE_EVENT_FL_CAP_ANY)
|
||||||
|
|
||||||
#define SYSCALL_TRACE_EXIT_EVENT(sname) \
|
#define SYSCALL_TRACE_EXIT_EVENT(sname) \
|
||||||
static struct syscall_metadata \
|
static struct syscall_metadata \
|
||||||
__attribute__((__aligned__(4))) __syscall_meta_##sname; \
|
__attribute__((__aligned__(4))) __syscall_meta_##sname; \
|
||||||
static struct ftrace_event_call __used \
|
static struct ftrace_event_call __used \
|
||||||
__attribute__((__aligned__(4))) \
|
|
||||||
__attribute__((section("_ftrace_events"))) \
|
|
||||||
event_exit_##sname = { \
|
event_exit_##sname = { \
|
||||||
.name = "sys_exit"#sname, \
|
.name = "sys_exit"#sname, \
|
||||||
.class = &event_class_syscall_exit, \
|
.class = &event_class_syscall_exit, \
|
||||||
.event.funcs = &exit_syscall_print_funcs, \
|
.event.funcs = &exit_syscall_print_funcs, \
|
||||||
.data = (void *)&__syscall_meta_##sname,\
|
.data = (void *)&__syscall_meta_##sname,\
|
||||||
}; \
|
}; \
|
||||||
|
static struct ftrace_event_call __used \
|
||||||
|
__attribute__((section("_ftrace_events"))) \
|
||||||
|
*__event_exit_##sname = &event_exit_##sname; \
|
||||||
__TRACE_EVENT_FLAGS(exit_##sname, TRACE_EVENT_FL_CAP_ANY)
|
__TRACE_EVENT_FLAGS(exit_##sname, TRACE_EVENT_FL_CAP_ANY)
|
||||||
|
|
||||||
#define SYSCALL_METADATA(sname, nb) \
|
#define SYSCALL_METADATA(sname, nb) \
|
||||||
|
|
|
@ -446,14 +446,16 @@ static inline notrace int ftrace_get_offsets_##call( \
|
||||||
* .reg = ftrace_event_reg,
|
* .reg = ftrace_event_reg,
|
||||||
* };
|
* };
|
||||||
*
|
*
|
||||||
* static struct ftrace_event_call __used
|
* static struct ftrace_event_call event_<call> = {
|
||||||
* __attribute__((__aligned__(4)))
|
|
||||||
* __attribute__((section("_ftrace_events"))) event_<call> = {
|
|
||||||
* .name = "<call>",
|
* .name = "<call>",
|
||||||
* .class = event_class_<template>,
|
* .class = event_class_<template>,
|
||||||
* .event = &ftrace_event_type_<call>,
|
* .event = &ftrace_event_type_<call>,
|
||||||
* .print_fmt = print_fmt_<call>,
|
* .print_fmt = print_fmt_<call>,
|
||||||
* };
|
* };
|
||||||
|
* // its only safe to use pointers when doing linker tricks to
|
||||||
|
* // create an array.
|
||||||
|
* static struct ftrace_event_call __used
|
||||||
|
* __attribute__((section("_ftrace_events"))) *__event_<call> = &event_<call>;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -579,28 +581,28 @@ static struct ftrace_event_class __used event_class_##call = { \
|
||||||
#undef DEFINE_EVENT
|
#undef DEFINE_EVENT
|
||||||
#define DEFINE_EVENT(template, call, proto, args) \
|
#define DEFINE_EVENT(template, call, proto, args) \
|
||||||
\
|
\
|
||||||
static struct ftrace_event_call __used \
|
static struct ftrace_event_call __used event_##call = { \
|
||||||
__attribute__((__aligned__(4))) \
|
|
||||||
__attribute__((section("_ftrace_events"))) event_##call = { \
|
|
||||||
.name = #call, \
|
.name = #call, \
|
||||||
.class = &event_class_##template, \
|
.class = &event_class_##template, \
|
||||||
.event.funcs = &ftrace_event_type_funcs_##template, \
|
.event.funcs = &ftrace_event_type_funcs_##template, \
|
||||||
.print_fmt = print_fmt_##template, \
|
.print_fmt = print_fmt_##template, \
|
||||||
};
|
}; \
|
||||||
|
static struct ftrace_event_call __used \
|
||||||
|
__attribute__((section("_ftrace_events"))) *__event_##call = &event_##call
|
||||||
|
|
||||||
#undef DEFINE_EVENT_PRINT
|
#undef DEFINE_EVENT_PRINT
|
||||||
#define DEFINE_EVENT_PRINT(template, call, proto, args, print) \
|
#define DEFINE_EVENT_PRINT(template, call, proto, args, print) \
|
||||||
\
|
\
|
||||||
static const char print_fmt_##call[] = print; \
|
static const char print_fmt_##call[] = print; \
|
||||||
\
|
\
|
||||||
static struct ftrace_event_call __used \
|
static struct ftrace_event_call __used event_##call = { \
|
||||||
__attribute__((__aligned__(4))) \
|
|
||||||
__attribute__((section("_ftrace_events"))) event_##call = { \
|
|
||||||
.name = #call, \
|
.name = #call, \
|
||||||
.class = &event_class_##template, \
|
.class = &event_class_##template, \
|
||||||
.event.funcs = &ftrace_event_type_funcs_##call, \
|
.event.funcs = &ftrace_event_type_funcs_##call, \
|
||||||
.print_fmt = print_fmt_##call, \
|
.print_fmt = print_fmt_##call, \
|
||||||
}
|
}; \
|
||||||
|
static struct ftrace_event_call __used \
|
||||||
|
__attribute__((section("_ftrace_events"))) *__event_##call = &event_##call
|
||||||
|
|
||||||
#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
|
#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
|
||||||
|
|
||||||
|
|
|
@ -1284,7 +1284,7 @@ trace_create_file_ops(struct module *mod)
|
||||||
static void trace_module_add_events(struct module *mod)
|
static void trace_module_add_events(struct module *mod)
|
||||||
{
|
{
|
||||||
struct ftrace_module_file_ops *file_ops = NULL;
|
struct ftrace_module_file_ops *file_ops = NULL;
|
||||||
struct ftrace_event_call *call, *start, *end;
|
struct ftrace_event_call **call, **start, **end;
|
||||||
|
|
||||||
start = mod->trace_events;
|
start = mod->trace_events;
|
||||||
end = mod->trace_events + mod->num_trace_events;
|
end = mod->trace_events + mod->num_trace_events;
|
||||||
|
@ -1297,7 +1297,7 @@ static void trace_module_add_events(struct module *mod)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for_each_event(call, start, end) {
|
for_each_event(call, start, end) {
|
||||||
__trace_add_event_call(call, mod,
|
__trace_add_event_call(*call, mod,
|
||||||
&file_ops->id, &file_ops->enable,
|
&file_ops->id, &file_ops->enable,
|
||||||
&file_ops->filter, &file_ops->format);
|
&file_ops->filter, &file_ops->format);
|
||||||
}
|
}
|
||||||
|
@ -1367,8 +1367,8 @@ static struct notifier_block trace_module_nb = {
|
||||||
.priority = 0,
|
.priority = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct ftrace_event_call __start_ftrace_events[];
|
extern struct ftrace_event_call *__start_ftrace_events[];
|
||||||
extern struct ftrace_event_call __stop_ftrace_events[];
|
extern struct ftrace_event_call *__stop_ftrace_events[];
|
||||||
|
|
||||||
static char bootup_event_buf[COMMAND_LINE_SIZE] __initdata;
|
static char bootup_event_buf[COMMAND_LINE_SIZE] __initdata;
|
||||||
|
|
||||||
|
@ -1384,7 +1384,7 @@ __setup("trace_event=", setup_trace_event);
|
||||||
|
|
||||||
static __init int event_trace_init(void)
|
static __init int event_trace_init(void)
|
||||||
{
|
{
|
||||||
struct ftrace_event_call *call;
|
struct ftrace_event_call **call;
|
||||||
struct dentry *d_tracer;
|
struct dentry *d_tracer;
|
||||||
struct dentry *entry;
|
struct dentry *entry;
|
||||||
struct dentry *d_events;
|
struct dentry *d_events;
|
||||||
|
@ -1430,7 +1430,7 @@ static __init int event_trace_init(void)
|
||||||
pr_warning("tracing: Failed to allocate common fields");
|
pr_warning("tracing: Failed to allocate common fields");
|
||||||
|
|
||||||
for_each_event(call, __start_ftrace_events, __stop_ftrace_events) {
|
for_each_event(call, __start_ftrace_events, __stop_ftrace_events) {
|
||||||
__trace_add_event_call(call, NULL, &ftrace_event_id_fops,
|
__trace_add_event_call(*call, NULL, &ftrace_event_id_fops,
|
||||||
&ftrace_enable_fops,
|
&ftrace_enable_fops,
|
||||||
&ftrace_event_filter_fops,
|
&ftrace_event_filter_fops,
|
||||||
&ftrace_event_format_fops);
|
&ftrace_event_format_fops);
|
||||||
|
|
|
@ -161,13 +161,13 @@ struct ftrace_event_class event_class_ftrace_##call = { \
|
||||||
.fields = LIST_HEAD_INIT(event_class_ftrace_##call.fields),\
|
.fields = LIST_HEAD_INIT(event_class_ftrace_##call.fields),\
|
||||||
}; \
|
}; \
|
||||||
\
|
\
|
||||||
struct ftrace_event_call __used \
|
struct ftrace_event_call __used event_##call = { \
|
||||||
__attribute__((__aligned__(4))) \
|
|
||||||
__attribute__((section("_ftrace_events"))) event_##call = { \
|
|
||||||
.name = #call, \
|
.name = #call, \
|
||||||
.event.type = etype, \
|
.event.type = etype, \
|
||||||
.class = &event_class_ftrace_##call, \
|
.class = &event_class_ftrace_##call, \
|
||||||
.print_fmt = print, \
|
.print_fmt = print, \
|
||||||
}; \
|
}; \
|
||||||
|
struct ftrace_event_call __used \
|
||||||
|
__attribute__((section("_ftrace_events"))) *__event_##call = &event_##call;
|
||||||
|
|
||||||
#include "trace_entries.h"
|
#include "trace_entries.h"
|
||||||
|
|
Загрузка…
Ссылка в новой задаче