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
b29144c3
Commit
b29144c3
authored
Dec 04, 2008
by
Ingo Molnar
Browse files
Options
Browse Files
Download
Plain Diff
Merge branches 'tracing/ftrace' and 'tracing/function-graph-tracer' into tracing/core
parents
b8307db2
e8e1abe9
764f3b95
Changes
21
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
884 additions
and
726 deletions
+884
-726
arch/x86/kernel/Makefile
arch/x86/kernel/Makefile
+1
-1
arch/x86/kernel/dumpstack.c
arch/x86/kernel/dumpstack.c
+351
-0
arch/x86/kernel/dumpstack.h
arch/x86/kernel/dumpstack.h
+39
-0
arch/x86/kernel/dumpstack_32.c
arch/x86/kernel/dumpstack_32.c
+6
-301
arch/x86/kernel/dumpstack_64.c
arch/x86/kernel/dumpstack_64.c
+6
-283
arch/x86/kernel/entry_32.S
arch/x86/kernel/entry_32.S
+4
-0
arch/x86/kernel/entry_64.S
arch/x86/kernel/entry_64.S
+4
-0
arch/x86/kernel/ftrace.c
arch/x86/kernel/ftrace.c
+33
-21
arch/x86/mm/fault.c
arch/x86/mm/fault.c
+7
-4
include/linux/ftrace.h
include/linux/ftrace.h
+3
-1
include/linux/ring_buffer.h
include/linux/ring_buffer.h
+5
-0
kernel/fork.c
kernel/fork.c
+6
-3
kernel/lockdep.c
kernel/lockdep.c
+1
-0
kernel/trace/Kconfig
kernel/trace/Kconfig
+1
-0
kernel/trace/ftrace.c
kernel/trace/ftrace.c
+12
-3
kernel/trace/ring_buffer.c
kernel/trace/ring_buffer.c
+243
-68
kernel/trace/trace.c
kernel/trace/trace.c
+9
-7
kernel/trace/trace.h
kernel/trace/trace.h
+1
-1
kernel/trace/trace_branch.c
kernel/trace/trace_branch.c
+2
-2
kernel/trace/trace_functions_graph.c
kernel/trace/trace_functions_graph.c
+142
-26
kernel/trace/trace_stack.c
kernel/trace/trace_stack.c
+8
-5
No files found.
arch/x86/kernel/Makefile
View file @
b29144c3
...
...
@@ -31,7 +31,7 @@ CFLAGS_tsc.o := $(nostackp)
obj-y
:=
process_
$(BITS)
.o signal_
$(BITS)
.o entry_
$(BITS)
.o
obj-y
+=
traps.o irq.o irq_
$(BITS)
.o dumpstack_
$(BITS)
.o
obj-y
+=
time_
$(BITS)
.o ioport.o ldt.o
obj-y
+=
time_
$(BITS)
.o ioport.o ldt.o
dumpstack.o
obj-y
+=
setup.o i8259.o irqinit_
$(BITS)
.o setup_percpu.o
obj-$(CONFIG_X86_VISWS)
+=
visws_quirks.o
obj-$(CONFIG_X86_32)
+=
probe_roms_32.o
...
...
arch/x86/kernel/dumpstack.c
0 → 100644
View file @
b29144c3
/*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
*/
#include <linux/kallsyms.h>
#include <linux/kprobes.h>
#include <linux/uaccess.h>
#include <linux/utsname.h>
#include <linux/hardirq.h>
#include <linux/kdebug.h>
#include <linux/module.h>
#include <linux/ptrace.h>
#include <linux/kexec.h>
#include <linux/bug.h>
#include <linux/nmi.h>
#include <linux/sysfs.h>
#include <asm/stacktrace.h>
#include "dumpstack.h"
int
panic_on_unrecovered_nmi
;
unsigned
int
code_bytes
=
64
;
int
kstack_depth_to_print
=
3
*
STACKSLOTS_PER_LINE
;
static
int
die_counter
;
void
printk_address
(
unsigned
long
address
,
int
reliable
)
{
printk
(
" [<%p>] %s%pS
\n
"
,
(
void
*
)
address
,
reliable
?
""
:
"? "
,
(
void
*
)
address
);
}
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
static
void
print_ftrace_graph_addr
(
unsigned
long
addr
,
void
*
data
,
const
struct
stacktrace_ops
*
ops
,
struct
thread_info
*
tinfo
,
int
*
graph
)
{
struct
task_struct
*
task
=
tinfo
->
task
;
unsigned
long
ret_addr
;
int
index
=
task
->
curr_ret_stack
;
if
(
addr
!=
(
unsigned
long
)
return_to_handler
)
return
;
if
(
!
task
->
ret_stack
||
index
<
*
graph
)
return
;
index
-=
*
graph
;
ret_addr
=
task
->
ret_stack
[
index
].
ret
;
ops
->
address
(
data
,
ret_addr
,
1
);
(
*
graph
)
++
;
}
#else
static
inline
void
print_ftrace_graph_addr
(
unsigned
long
addr
,
void
*
data
,
const
struct
stacktrace_ops
*
ops
,
struct
thread_info
*
tinfo
,
int
*
graph
)
{
}
#endif
/*
* x86-64 can have up to three kernel stacks:
* process stack
* interrupt stack
* severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
*/
static
inline
int
valid_stack_ptr
(
struct
thread_info
*
tinfo
,
void
*
p
,
unsigned
int
size
,
void
*
end
)
{
void
*
t
=
tinfo
;
if
(
end
)
{
if
(
p
<
end
&&
p
>=
(
end
-
THREAD_SIZE
))
return
1
;
else
return
0
;
}
return
p
>
t
&&
p
<
t
+
THREAD_SIZE
-
size
;
}
unsigned
long
print_context_stack
(
struct
thread_info
*
tinfo
,
unsigned
long
*
stack
,
unsigned
long
bp
,
const
struct
stacktrace_ops
*
ops
,
void
*
data
,
unsigned
long
*
end
,
int
*
graph
)
{
struct
stack_frame
*
frame
=
(
struct
stack_frame
*
)
bp
;
while
(
valid_stack_ptr
(
tinfo
,
stack
,
sizeof
(
*
stack
),
end
))
{
unsigned
long
addr
;
addr
=
*
stack
;
if
(
__kernel_text_address
(
addr
))
{
if
((
unsigned
long
)
stack
==
bp
+
sizeof
(
long
))
{
ops
->
address
(
data
,
addr
,
1
);
frame
=
frame
->
next_frame
;
bp
=
(
unsigned
long
)
frame
;
}
else
{
ops
->
address
(
data
,
addr
,
bp
==
0
);
}
print_ftrace_graph_addr
(
addr
,
data
,
ops
,
tinfo
,
graph
);
}
stack
++
;
}
return
bp
;
}
static
void
print_trace_warning_symbol
(
void
*
data
,
char
*
msg
,
unsigned
long
symbol
)
{
printk
(
data
);
print_symbol
(
msg
,
symbol
);
printk
(
"
\n
"
);
}
static
void
print_trace_warning
(
void
*
data
,
char
*
msg
)
{
printk
(
"%s%s
\n
"
,
(
char
*
)
data
,
msg
);
}
static
int
print_trace_stack
(
void
*
data
,
char
*
name
)
{
printk
(
"%s <%s> "
,
(
char
*
)
data
,
name
);
return
0
;
}
/*
* Print one address/symbol entries per line.
*/
static
void
print_trace_address
(
void
*
data
,
unsigned
long
addr
,
int
reliable
)
{
touch_nmi_watchdog
();
printk
(
data
);
printk_address
(
addr
,
reliable
);
}
static
const
struct
stacktrace_ops
print_trace_ops
=
{
.
warning
=
print_trace_warning
,
.
warning_symbol
=
print_trace_warning_symbol
,
.
stack
=
print_trace_stack
,
.
address
=
print_trace_address
,
};
void
show_trace_log_lvl
(
struct
task_struct
*
task
,
struct
pt_regs
*
regs
,
unsigned
long
*
stack
,
unsigned
long
bp
,
char
*
log_lvl
)
{
printk
(
"%sCall Trace:
\n
"
,
log_lvl
);
dump_trace
(
task
,
regs
,
stack
,
bp
,
&
print_trace_ops
,
log_lvl
);
}
void
show_trace
(
struct
task_struct
*
task
,
struct
pt_regs
*
regs
,
unsigned
long
*
stack
,
unsigned
long
bp
)
{
show_trace_log_lvl
(
task
,
regs
,
stack
,
bp
,
""
);
}
void
show_stack
(
struct
task_struct
*
task
,
unsigned
long
*
sp
)
{
show_stack_log_lvl
(
task
,
NULL
,
sp
,
0
,
""
);
}
/*
* The architecture-independent dump_stack generator
*/
void
dump_stack
(
void
)
{
unsigned
long
bp
=
0
;
unsigned
long
stack
;
#ifdef CONFIG_FRAME_POINTER
if
(
!
bp
)
get_bp
(
bp
);
#endif
printk
(
"Pid: %d, comm: %.20s %s %s %.*s
\n
"
,
current
->
pid
,
current
->
comm
,
print_tainted
(),
init_utsname
()
->
release
,
(
int
)
strcspn
(
init_utsname
()
->
version
,
" "
),
init_utsname
()
->
version
);
show_trace
(
NULL
,
NULL
,
&
stack
,
bp
);
}
EXPORT_SYMBOL
(
dump_stack
);
static
raw_spinlock_t
die_lock
=
__RAW_SPIN_LOCK_UNLOCKED
;
static
int
die_owner
=
-
1
;
static
unsigned
int
die_nest_count
;
unsigned
__kprobes
long
oops_begin
(
void
)
{
int
cpu
;
unsigned
long
flags
;
oops_enter
();
/* racy, but better than risking deadlock. */
raw_local_irq_save
(
flags
);
cpu
=
smp_processor_id
();
if
(
!
__raw_spin_trylock
(
&
die_lock
))
{
if
(
cpu
==
die_owner
)
/* nested oops. should stop eventually */
;
else
__raw_spin_lock
(
&
die_lock
);
}
die_nest_count
++
;
die_owner
=
cpu
;
console_verbose
();
bust_spinlocks
(
1
);
return
flags
;
}
void
__kprobes
oops_end
(
unsigned
long
flags
,
struct
pt_regs
*
regs
,
int
signr
)
{
if
(
regs
&&
kexec_should_crash
(
current
))
crash_kexec
(
regs
);
bust_spinlocks
(
0
);
die_owner
=
-
1
;
add_taint
(
TAINT_DIE
);
die_nest_count
--
;
if
(
!
die_nest_count
)
/* Nest count reaches zero, release the lock. */
__raw_spin_unlock
(
&
die_lock
);
raw_local_irq_restore
(
flags
);
oops_exit
();
if
(
!
signr
)
return
;
if
(
in_interrupt
())
panic
(
"Fatal exception in interrupt"
);
if
(
panic_on_oops
)
panic
(
"Fatal exception"
);
do_exit
(
signr
);
}
int
__kprobes
__die
(
const
char
*
str
,
struct
pt_regs
*
regs
,
long
err
)
{
#ifdef CONFIG_X86_32
unsigned
short
ss
;
unsigned
long
sp
;
#endif
printk
(
KERN_EMERG
"%s: %04lx [#%d] "
,
str
,
err
&
0xffff
,
++
die_counter
);
#ifdef CONFIG_PREEMPT
printk
(
"PREEMPT "
);
#endif
#ifdef CONFIG_SMP
printk
(
"SMP "
);
#endif
#ifdef CONFIG_DEBUG_PAGEALLOC
printk
(
"DEBUG_PAGEALLOC"
);
#endif
printk
(
"
\n
"
);
sysfs_printk_last_file
();
if
(
notify_die
(
DIE_OOPS
,
str
,
regs
,
err
,
current
->
thread
.
trap_no
,
SIGSEGV
)
==
NOTIFY_STOP
)
return
1
;
show_registers
(
regs
);
#ifdef CONFIG_X86_32
sp
=
(
unsigned
long
)
(
&
regs
->
sp
);
savesegment
(
ss
,
ss
);
if
(
user_mode
(
regs
))
{
sp
=
regs
->
sp
;
ss
=
regs
->
ss
&
0xffff
;
}
printk
(
KERN_EMERG
"EIP: [<%08lx>] "
,
regs
->
ip
);
print_symbol
(
"%s"
,
regs
->
ip
);
printk
(
" SS:ESP %04x:%08lx
\n
"
,
ss
,
sp
);
#else
/* Executive summary in case the oops scrolled away */
printk
(
KERN_ALERT
"RIP "
);
printk_address
(
regs
->
ip
,
1
);
printk
(
" RSP <%016lx>
\n
"
,
regs
->
sp
);
#endif
return
0
;
}
/*
* This is gone through when something in the kernel has done something bad
* and is about to be terminated:
*/
void
die
(
const
char
*
str
,
struct
pt_regs
*
regs
,
long
err
)
{
unsigned
long
flags
=
oops_begin
();
int
sig
=
SIGSEGV
;
if
(
!
user_mode_vm
(
regs
))
report_bug
(
regs
->
ip
,
regs
);
if
(
__die
(
str
,
regs
,
err
))
sig
=
0
;
oops_end
(
flags
,
regs
,
sig
);
}
void
notrace
__kprobes
die_nmi
(
char
*
str
,
struct
pt_regs
*
regs
,
int
do_panic
)
{
unsigned
long
flags
;
if
(
notify_die
(
DIE_NMIWATCHDOG
,
str
,
regs
,
0
,
2
,
SIGINT
)
==
NOTIFY_STOP
)
return
;
/*
* We are in trouble anyway, lets at least try
* to get a message out.
*/
flags
=
oops_begin
();
printk
(
KERN_EMERG
"%s"
,
str
);
printk
(
" on CPU%d, ip %08lx, registers:
\n
"
,
smp_processor_id
(),
regs
->
ip
);
show_registers
(
regs
);
oops_end
(
flags
,
regs
,
0
);
if
(
do_panic
||
panic_on_oops
)
panic
(
"Non maskable interrupt"
);
nmi_exit
();
local_irq_enable
();
do_exit
(
SIGBUS
);
}
static
int
__init
oops_setup
(
char
*
s
)
{
if
(
!
s
)
return
-
EINVAL
;
if
(
!
strcmp
(
s
,
"panic"
))
panic_on_oops
=
1
;
return
0
;
}
early_param
(
"oops"
,
oops_setup
);
static
int
__init
kstack_setup
(
char
*
s
)
{
if
(
!
s
)
return
-
EINVAL
;
kstack_depth_to_print
=
simple_strtoul
(
s
,
NULL
,
0
);
return
0
;
}
early_param
(
"kstack"
,
kstack_setup
);
static
int
__init
code_bytes_setup
(
char
*
s
)
{
code_bytes
=
simple_strtoul
(
s
,
NULL
,
0
);
if
(
code_bytes
>
8192
)
code_bytes
=
8192
;
return
1
;
}
__setup
(
"code_bytes="
,
code_bytes_setup
);
arch/x86/kernel/dumpstack.h
0 → 100644
View file @
b29144c3
/*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
*/
#ifndef DUMPSTACK_H
#define DUMPSTACK_H
#ifdef CONFIG_X86_32
#define STACKSLOTS_PER_LINE 8
#define get_bp(bp) asm("movl %%ebp, %0" : "=r" (bp) :)
#else
#define STACKSLOTS_PER_LINE 4
#define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :)
#endif
extern
unsigned
long
print_context_stack
(
struct
thread_info
*
tinfo
,
unsigned
long
*
stack
,
unsigned
long
bp
,
const
struct
stacktrace_ops
*
ops
,
void
*
data
,
unsigned
long
*
end
,
int
*
graph
);
extern
void
show_trace_log_lvl
(
struct
task_struct
*
task
,
struct
pt_regs
*
regs
,
unsigned
long
*
stack
,
unsigned
long
bp
,
char
*
log_lvl
);
extern
void
show_stack_log_lvl
(
struct
task_struct
*
task
,
struct
pt_regs
*
regs
,
unsigned
long
*
sp
,
unsigned
long
bp
,
char
*
log_lvl
);
extern
unsigned
int
code_bytes
;
extern
int
kstack_depth_to_print
;
/* The form of the top of the frame on the stack */
struct
stack_frame
{
struct
stack_frame
*
next_frame
;
unsigned
long
return_address
;
};
#endif
arch/x86/kernel/dumpstack_32.c
View file @
b29144c3
...
...
@@ -17,69 +17,14 @@
#include <asm/stacktrace.h>
#define STACKSLOTS_PER_LINE 8
#define get_bp(bp) asm("movl %%ebp, %0" : "=r" (bp) :)
int
panic_on_unrecovered_nmi
;
int
kstack_depth_to_print
=
3
*
STACKSLOTS_PER_LINE
;
static
unsigned
int
code_bytes
=
64
;
static
int
die_counter
;
void
printk_address
(
unsigned
long
address
,
int
reliable
)
{
printk
(
" [<%p>] %s%pS
\n
"
,
(
void
*
)
address
,
reliable
?
""
:
"? "
,
(
void
*
)
address
);
}
static
inline
int
valid_stack_ptr
(
struct
thread_info
*
tinfo
,
void
*
p
,
unsigned
int
size
,
void
*
end
)
{
void
*
t
=
tinfo
;
if
(
end
)
{
if
(
p
<
end
&&
p
>=
(
end
-
THREAD_SIZE
))
return
1
;
else
return
0
;
}
return
p
>
t
&&
p
<
t
+
THREAD_SIZE
-
size
;
}
/* The form of the top of the frame on the stack */
struct
stack_frame
{
struct
stack_frame
*
next_frame
;
unsigned
long
return_address
;
};
static
inline
unsigned
long
print_context_stack
(
struct
thread_info
*
tinfo
,
unsigned
long
*
stack
,
unsigned
long
bp
,
const
struct
stacktrace_ops
*
ops
,
void
*
data
,
unsigned
long
*
end
)
{
struct
stack_frame
*
frame
=
(
struct
stack_frame
*
)
bp
;
while
(
valid_stack_ptr
(
tinfo
,
stack
,
sizeof
(
*
stack
),
end
))
{
unsigned
long
addr
;
addr
=
*
stack
;
if
(
__kernel_text_address
(
addr
))
{
if
((
unsigned
long
)
stack
==
bp
+
sizeof
(
long
))
{
ops
->
address
(
data
,
addr
,
1
);
frame
=
frame
->
next_frame
;
bp
=
(
unsigned
long
)
frame
;
}
else
{
ops
->
address
(
data
,
addr
,
bp
==
0
);
}
}
stack
++
;
}
return
bp
;
}
#include "dumpstack.h"
void
dump_trace
(
struct
task_struct
*
task
,
struct
pt_regs
*
regs
,
unsigned
long
*
stack
,
unsigned
long
bp
,
const
struct
stacktrace_ops
*
ops
,
void
*
data
)
{
int
graph
=
0
;
if
(
!
task
)
task
=
current
;
...
...
@@ -107,7 +52,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
context
=
(
struct
thread_info
*
)
((
unsigned
long
)
stack
&
(
~
(
THREAD_SIZE
-
1
)));
bp
=
print_context_stack
(
context
,
stack
,
bp
,
ops
,
data
,
NULL
);
bp
=
print_context_stack
(
context
,
stack
,
bp
,
ops
,
data
,
NULL
,
&
graph
);
stack
=
(
unsigned
long
*
)
context
->
previous_esp
;
if
(
!
stack
)
...
...
@@ -119,57 +65,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
}
EXPORT_SYMBOL
(
dump_trace
);
static
void
print_trace_warning_symbol
(
void
*
data
,
char
*
msg
,
unsigned
long
symbol
)
{
printk
(
data
);
print_symbol
(
msg
,
symbol
);
printk
(
"
\n
"
);
}
static
void
print_trace_warning
(
void
*
data
,
char
*
msg
)
{
printk
(
"%s%s
\n
"
,
(
char
*
)
data
,
msg
);
}
static
int
print_trace_stack
(
void
*
data
,
char
*
name
)
{
printk
(
"%s <%s> "
,
(
char
*
)
data
,
name
);
return
0
;
}
/*
* Print one address/symbol entries per line.
*/
static
void
print_trace_address
(
void
*
data
,
unsigned
long
addr
,
int
reliable
)
{
touch_nmi_watchdog
();
printk
(
data
);
printk_address
(
addr
,
reliable
);
}
static
const
struct
stacktrace_ops
print_trace_ops
=
{
.
warning
=
print_trace_warning
,
.
warning_symbol
=
print_trace_warning_symbol
,
.
stack
=
print_trace_stack
,
.
address
=
print_trace_address
,
};
static
void
show_trace_log_lvl
(
struct
task_struct
*
task
,
struct
pt_regs
*
regs
,
unsigned
long
*
stack
,
unsigned
long
bp
,
char
*
log_lvl
)
{
printk
(
"%sCall Trace:
\n
"
,
log_lvl
);
dump_trace
(
task
,
regs
,
stack
,
bp
,
&
print_trace_ops
,
log_lvl
);
}
void
show_trace
(
struct
task_struct
*
task
,
struct
pt_regs
*
regs
,
unsigned
long
*
stack
,
unsigned
long
bp
)
{
show_trace_log_lvl
(
task
,
regs
,
stack
,
bp
,
""
);
}
static
void
void
show_stack_log_lvl
(
struct
task_struct
*
task
,
struct
pt_regs
*
regs
,
unsigned
long
*
sp
,
unsigned
long
bp
,
char
*
log_lvl
)
{
...
...
@@ -196,33 +92,6 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
show_trace_log_lvl
(
task
,
regs
,
sp
,
bp
,
log_lvl
);
}
void
show_stack
(
struct
task_struct
*
task
,
unsigned
long
*
sp
)
{
show_stack_log_lvl
(
task
,
NULL
,
sp
,
0
,
""
);
}
/*
* The architecture-independent dump_stack generator
*/
void
dump_stack
(
void
)
{
unsigned
long
bp
=
0
;
unsigned
long
stack
;
#ifdef CONFIG_FRAME_POINTER
if
(
!
bp
)
get_bp
(
bp
);
#endif
printk
(
"Pid: %d, comm: %.20s %s %s %.*s
\n
"
,
current
->
pid
,
current
->
comm
,
print_tainted
(),
init_utsname
()
->
release
,
(
int
)
strcspn
(
init_utsname
()
->
version
,
" "
),
init_utsname
()
->
version
);
show_trace
(
NULL
,
NULL
,
&
stack
,
bp
);
}
EXPORT_SYMBOL
(
dump_stack
);
void
show_registers
(
struct
pt_regs
*
regs
)
{
...
...
@@ -283,167 +152,3 @@ int is_valid_bugaddr(unsigned long ip)
return
ud2
==
0x0b0f
;
}
static
raw_spinlock_t
die_lock
=
__RAW_SPIN_LOCK_UNLOCKED
;
static
int
die_owner
=
-
1
;
static
unsigned
int
die_nest_count
;
unsigned
__kprobes
long
oops_begin
(
void
)
{
unsigned
long
flags
;
oops_enter
();
if
(
die_owner
!=
raw_smp_processor_id
())
{
console_verbose
();
raw_local_irq_save
(
flags
);
__raw_spin_lock
(
&
die_lock
);
die_owner
=
smp_processor_id
();
die_nest_count
=
0
;
bust_spinlocks
(
1
);
}
else
{
raw_local_irq_save
(
flags
);
}
die_nest_count
++
;
return
flags
;
}
void
__kprobes
oops_end
(
unsigned
long
flags
,
struct
pt_regs
*
regs
,
int
signr
)
{
bust_spinlocks
(
0
);
die_owner
=
-
1
;
add_taint
(
TAINT_DIE
);
__raw_spin_unlock
(
&
die_lock
);
raw_local_irq_restore
(
flags
);
if
(
!
regs
)
return
;
if
(
kexec_should_crash
(
current
))
crash_kexec
(
regs
);
if
(
in_interrupt
())
panic
(
"Fatal exception in interrupt"
);
if
(
panic_on_oops
)
panic
(
"Fatal exception"
);
oops_exit
();
do_exit
(
signr
);
}
int
__kprobes
__die
(
const
char
*
str
,
struct
pt_regs
*
regs
,
long
err
)
{
unsigned
short
ss
;
unsigned
long
sp
;
printk
(
KERN_EMERG
"%s: %04lx [#%d] "
,
str
,
err
&
0xffff
,
++
die_counter
);
#ifdef CONFIG_PREEMPT
printk
(
"PREEMPT "
);
#endif
#ifdef CONFIG_SMP
printk
(
"SMP "
);
#endif
#ifdef CONFIG_DEBUG_PAGEALLOC
printk
(
"DEBUG_PAGEALLOC"
);
#endif
printk
(
"
\n
"
);
sysfs_printk_last_file
();
if
(
notify_die
(
DIE_OOPS
,
str
,
regs
,
err
,
current
->
thread
.
trap_no
,
SIGSEGV
)
==
NOTIFY_STOP
)
return
1
;
show_registers
(
regs
);
/* Executive summary in case the oops scrolled away */
sp
=
(
unsigned
long
)
(
&
regs
->
sp
);
savesegment
(
ss
,
ss
);
if
(
user_mode
(
regs
))
{
sp
=
regs
->
sp
;
ss
=
regs
->
ss
&
0xffff
;
}
printk
(
KERN_EMERG
"EIP: [<%08lx>] "
,
regs
->
ip
);
print_symbol
(
"%s"
,
regs
->
ip
);
printk
(
" SS:ESP %04x:%08lx
\n
"
,
ss
,
sp
);
return
0
;
}
/*
* This is gone through when something in the kernel has done something bad
* and is about to be terminated:
*/
void
die
(
const
char
*
str
,
struct
pt_regs
*
regs
,
long
err
)
{
unsigned
long
flags
=
oops_begin
();
if
(
die_nest_count
<
3
)
{
report_bug
(
regs
->
ip
,
regs
);
if
(
__die
(
str
,
regs
,
err
))
regs
=
NULL
;
}
else
{
printk
(
KERN_EMERG
"Recursive die() failure, output suppressed
\n
"
);
}
oops_end
(
flags
,
regs
,
SIGSEGV
);
}
static
DEFINE_SPINLOCK
(
nmi_print_lock
);
void
notrace
__kprobes
die_nmi
(
char
*
str
,
struct
pt_regs
*
regs
,
int
do_panic
)
{
if
(
notify_die
(
DIE_NMIWATCHDOG
,
str
,
regs
,
0
,
2
,
SIGINT
)
==
NOTIFY_STOP
)
return
;
spin_lock
(
&
nmi_print_lock
);
/*
* We are in trouble anyway, lets at least try
* to get a message out:
*/
bust_spinlocks
(
1
);
printk
(
KERN_EMERG
"%s"
,
str
);
printk
(
" on CPU%d, ip %08lx, registers:
\n
"
,
smp_processor_id
(),
regs
->
ip
);
show_registers
(
regs
);
if
(
do_panic
)
panic
(
"Non maskable interrupt"
);
console_silent
();
spin_unlock
(
&
nmi_print_lock
);
/*
* If we are in kernel we are probably nested up pretty bad
* and might aswell get out now while we still can:
*/
if
(
!
user_mode_vm
(
regs
))
{
current
->
thread
.
trap_no
=
2
;
crash_kexec
(
regs
);
}
bust_spinlocks
(
0
);
do_exit
(
SIGSEGV
);
}
static
int
__init
oops_setup
(
char
*
s
)
{
if
(
!
s
)
return
-
EINVAL
;
if
(
!
strcmp
(
s
,
"panic"
))
panic_on_oops
=
1
;
return
0
;
}
early_param
(
"oops"
,
oops_setup
);
static
int
__init
kstack_setup
(
char
*
s
)
{
if
(
!
s
)
return
-
EINVAL
;
kstack_depth_to_print
=
simple_strtoul
(
s
,
NULL
,
0
);
return
0
;
}
early_param
(
"kstack"
,
kstack_setup
);
static
int
__init
code_bytes_setup
(
char
*
s
)
{
code_bytes
=
simple_strtoul
(
s
,
NULL
,
0
);
if
(
code_bytes
>
8192
)
code_bytes
=
8192
;
return
1
;
}
__setup
(
"code_bytes="
,
code_bytes_setup
);
arch/x86/kernel/dumpstack_64.c
View file @
b29144c3
...
...
@@ -17,19 +17,7 @@
#include <asm/stacktrace.h>
#define STACKSLOTS_PER_LINE 4
#define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :)
int
panic_on_unrecovered_nmi
;
int
kstack_depth_to_print
=
3
*
STACKSLOTS_PER_LINE
;
static
unsigned
int
code_bytes
=
64
;
static
int
die_counter
;
void
printk_address
(
unsigned
long
address
,
int
reliable
)
{
printk
(
" [<%p>] %s%pS
\n
"
,
(
void
*
)
address
,
reliable
?
""
:
"? "
,
(
void
*
)
address
);
}
#include "dumpstack.h"
static
unsigned
long
*
in_exception_stack
(
unsigned
cpu
,
unsigned
long
stack
,
unsigned
*
usedp
,
char
**
idp
)
...
...
@@ -113,51 +101,6 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
* severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
*/
static
inline
int
valid_stack_ptr
(
struct
thread_info
*
tinfo
,
void
*
p
,
unsigned
int
size
,
void
*
end
)
{
void
*
t
=
tinfo
;
if
(
end
)
{
if
(
p
<
end
&&
p
>=
(
end
-
THREAD_SIZE
))
return
1
;
else
return
0
;
}
return
p
>
t
&&
p
<
t
+
THREAD_SIZE
-
size
;
}
/* The form of the top of the frame on the stack */
struct
stack_frame
{
struct
stack_frame
*
next_frame
;
unsigned
long
return_address
;
};
static
inline
unsigned
long
print_context_stack
(
struct
thread_info
*
tinfo
,
unsigned
long
*
stack
,
unsigned
long
bp
,
const
struct
stacktrace_ops
*
ops
,
void
*
data
,
unsigned
long
*
end
)
{
struct
stack_frame
*
frame
=
(
struct
stack_frame
*
)
bp
;
while
(
valid_stack_ptr
(
tinfo
,
stack
,
sizeof
(
*
stack
),
end
))
{
unsigned
long
addr
;
addr
=
*
stack
;
if
(
__kernel_text_address
(
addr
))
{
if
((
unsigned
long
)
stack
==
bp
+
sizeof
(
long
))
{
ops
->
address
(
data
,
addr
,
1
);
frame
=
frame
->
next_frame
;
bp
=
(
unsigned
long
)
frame
;
}
else
{
ops
->
address
(
data
,
addr
,
bp
==
0
);
}
}
stack
++
;
}
return
bp
;
}
void
dump_trace
(
struct
task_struct
*
task
,
struct
pt_regs
*
regs
,
unsigned
long
*
stack
,
unsigned
long
bp
,
const
struct
stacktrace_ops
*
ops
,
void
*
data
)
...
...
@@ -166,6 +109,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
unsigned
long
*
irqstack_end
=
(
unsigned
long
*
)
cpu_pda
(
cpu
)
->
irqstackptr
;
unsigned
used
=
0
;
struct
thread_info
*
tinfo
;
int
graph
=
0
;
if
(
!
task
)
task
=
current
;
...
...
@@ -206,7 +150,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
break
;
bp
=
print_context_stack
(
tinfo
,
stack
,
bp
,
ops
,
data
,
estack_end
);
data
,
estack_end
,
&
graph
);
ops
->
stack
(
data
,
"<EOE>"
);
/*
* We link to the next stack via the
...
...
@@ -225,7 +169,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
if
(
ops
->
stack
(
data
,
"IRQ"
)
<
0
)
break
;
bp
=
print_context_stack
(
tinfo
,
stack
,
bp
,
ops
,
data
,
irqstack_end
);
ops
,
data
,
irqstack_end
,
&
graph
);
/*
* We link to the next stack (which would be
* the process stack normally) the last
...
...
@@ -243,62 +187,12 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
/*
* This handles the process stack:
*/
bp
=
print_context_stack
(
tinfo
,
stack
,
bp
,
ops
,
data
,
NULL
);
bp
=
print_context_stack
(
tinfo
,
stack
,
bp
,
ops
,
data
,
NULL
,
&
graph
);
put_cpu
();
}
EXPORT_SYMBOL
(
dump_trace
);
static
void
print_trace_warning_symbol
(
void
*
data
,
char
*
msg
,
unsigned
long
symbol
)
{
printk
(
data
);
print_symbol
(
msg
,
symbol
);
printk
(
"
\n
"
);
}
static
void
print_trace_warning
(
void
*
data
,
char
*
msg
)
{
printk
(
"%s%s
\n
"
,
(
char
*
)
data
,
msg
);
}
static
int
print_trace_stack
(
void
*
data
,
char
*
name
)
{
printk
(
"%s <%s> "
,
(
char
*
)
data
,
name
);
return
0
;
}
/*
* Print one address/symbol entries per line.
*/
static
void
print_trace_address
(
void
*
data
,
unsigned
long
addr
,
int
reliable
)
{
touch_nmi_watchdog
();
printk
(
data
);
printk_address
(
addr
,
reliable
);
}
static
const
struct
stacktrace_ops
print_trace_ops
=
{
.
warning
=
print_trace_warning
,
.
warning_symbol
=
print_trace_warning_symbol
,
.
stack
=
print_trace_stack
,
.
address
=
print_trace_address
,
};
static
void
show_trace_log_lvl
(
struct
task_struct
*
task
,
struct
pt_regs
*
regs
,
unsigned
long
*
stack
,
unsigned
long
bp
,
char
*
log_lvl
)
{
printk
(
"%sCall Trace:
\n
"
,
log_lvl
);
dump_trace
(
task
,
regs
,
stack
,
bp
,
&
print_trace_ops
,
log_lvl
);
}
void
show_trace
(
struct
task_struct
*
task
,
struct
pt_regs
*
regs
,
unsigned
long
*
stack
,
unsigned
long
bp
)
{
show_trace_log_lvl
(
task
,
regs
,
stack
,
bp
,
""
);
}
static
void
void
show_stack_log_lvl
(
struct
task_struct
*
task
,
struct
pt_regs
*
regs
,
unsigned
long
*
sp
,
unsigned
long
bp
,
char
*
log_lvl
)
{
...
...
@@ -342,33 +236,6 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
show_trace_log_lvl
(
task
,
regs
,
sp
,
bp
,
log_lvl
);
}
void
show_stack
(
struct
task_struct
*
task
,
unsigned
long
*
sp
)
{
show_stack_log_lvl
(
task
,
NULL
,
sp
,
0
,
""
);
}
/*
* The architecture-independent dump_stack generator
*/
void
dump_stack
(
void
)
{
unsigned
long
bp
=
0
;
unsigned
long
stack
;
#ifdef CONFIG_FRAME_POINTER
if
(
!
bp
)
get_bp
(
bp
);
#endif
printk
(
"Pid: %d, comm: %.20s %s %s %.*s
\n
"
,
current
->
pid
,
current
->
comm
,
print_tainted
(),
init_utsname
()
->
release
,
(
int
)
strcspn
(
init_utsname
()
->
version
,
" "
),
init_utsname
()
->
version
);
show_trace
(
NULL
,
NULL
,
&
stack
,
bp
);
}
EXPORT_SYMBOL
(
dump_stack
);
void
show_registers
(
struct
pt_regs
*
regs
)
{
int
i
;
...
...
@@ -429,147 +296,3 @@ int is_valid_bugaddr(unsigned long ip)
return
ud2
==
0x0b0f
;
}
static
raw_spinlock_t
die_lock
=
__RAW_SPIN_LOCK_UNLOCKED
;
static
int
die_owner
=
-
1
;
static
unsigned
int
die_nest_count
;
unsigned
__kprobes
long
oops_begin
(
void
)
{
int
cpu
;
unsigned
long
flags
;
oops_enter
();
/* racy, but better than risking deadlock. */
raw_local_irq_save
(
flags
);
cpu
=
smp_processor_id
();
if
(
!
__raw_spin_trylock
(
&
die_lock
))
{
if
(
cpu
==
die_owner
)
/* nested oops. should stop eventually */
;
else
__raw_spin_lock
(
&
die_lock
);
}
die_nest_count
++
;
die_owner
=
cpu
;
console_verbose
();
bust_spinlocks
(
1
);
return
flags
;
}
void
__kprobes
oops_end
(
unsigned
long
flags
,
struct
pt_regs
*
regs
,
int
signr
)
{
die_owner
=
-
1
;
bust_spinlocks
(
0
);
die_nest_count
--
;
if
(
!
die_nest_count
)
/* Nest count reaches zero, release the lock. */
__raw_spin_unlock
(
&
die_lock
);
raw_local_irq_restore
(
flags
);
if
(
!
regs
)
{
oops_exit
();
return
;
}
if
(
in_interrupt
())
panic
(
"Fatal exception in interrupt"
);
if
(
panic_on_oops
)
panic
(
"Fatal exception"
);
oops_exit
();
do_exit
(
signr
);
}
int
__kprobes
__die
(
const
char
*
str
,
struct
pt_regs
*
regs
,
long
err
)
{
printk
(
KERN_EMERG
"%s: %04lx [#%d] "
,
str
,
err
&
0xffff
,
++
die_counter
);
#ifdef CONFIG_PREEMPT
printk
(
"PREEMPT "
);
#endif
#ifdef CONFIG_SMP
printk
(
"SMP "
);
#endif
#ifdef CONFIG_DEBUG_PAGEALLOC
printk
(
"DEBUG_PAGEALLOC"
);
#endif
printk
(
"
\n
"
);
sysfs_printk_last_file
();
if
(
notify_die
(
DIE_OOPS
,
str
,
regs
,
err
,
current
->
thread
.
trap_no
,
SIGSEGV
)
==
NOTIFY_STOP
)
return
1
;
show_registers
(
regs
);
add_taint
(
TAINT_DIE
);
/* Executive summary in case the oops scrolled away */
printk
(
KERN_ALERT
"RIP "
);
printk_address
(
regs
->
ip
,
1
);
printk
(
" RSP <%016lx>
\n
"
,
regs
->
sp
);
if
(
kexec_should_crash
(
current
))
crash_kexec
(
regs
);
return
0
;
}
void
die
(
const
char
*
str
,
struct
pt_regs
*
regs
,
long
err
)
{
unsigned
long
flags
=
oops_begin
();
if
(
!
user_mode
(
regs
))
report_bug
(
regs
->
ip
,
regs
);
if
(
__die
(
str
,
regs
,
err
))
regs
=
NULL
;
oops_end
(
flags
,
regs
,
SIGSEGV
);
}
notrace
__kprobes
void
die_nmi
(
char
*
str
,
struct
pt_regs
*
regs
,
int
do_panic
)
{
unsigned
long
flags
;
if
(
notify_die
(
DIE_NMIWATCHDOG
,
str
,
regs
,
0
,
2
,
SIGINT
)
==
NOTIFY_STOP
)
return
;
flags
=
oops_begin
();
/*
* We are in trouble anyway, lets at least try
* to get a message out.
*/
printk
(
KERN_EMERG
"%s"
,
str
);
printk
(
" on CPU%d, ip %08lx, registers:
\n
"
,
smp_processor_id
(),
regs
->
ip
);
show_registers
(
regs
);
if
(
kexec_should_crash
(
current
))
crash_kexec
(
regs
);
if
(
do_panic
||
panic_on_oops
)
panic
(
"Non maskable interrupt"
);
oops_end
(
flags
,
NULL
,
SIGBUS
);
nmi_exit
();
local_irq_enable
();
do_exit
(
SIGBUS
);
}
static
int
__init
oops_setup
(
char
*
s
)
{
if
(
!
s
)
return
-
EINVAL
;
if
(
!
strcmp
(
s
,
"panic"
))
panic_on_oops
=
1
;
return
0
;
}
early_param
(
"oops"
,
oops_setup
);
static
int
__init
kstack_setup
(
char
*
s
)
{
if
(
!
s
)
return
-
EINVAL
;
kstack_depth_to_print
=
simple_strtoul
(
s
,
NULL
,
0
);
return
0
;
}
early_param
(
"kstack"
,
kstack_setup
);
static
int
__init
code_bytes_setup
(
char
*
s
)
{
code_bytes
=
simple_strtoul
(
s
,
NULL
,
0
);
if
(
code_bytes
>
8192
)
code_bytes
=
8192
;
return
1
;
}
__setup
(
"code_bytes="
,
code_bytes_setup
);
arch/x86/kernel/entry_32.S
View file @
b29144c3
...
...
@@ -1196,6 +1196,9 @@ ENTRY(mcount)
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
cmpl
$ftrace_stub
,
ftrace_graph_return
jnz
ftrace_graph_caller
cmpl
$ftrace_graph_entry_stub
,
ftrace_graph_entry
jnz
ftrace_graph_caller
#endif
.
globl
ftrace_stub
ftrace_stub
:
...
...
@@ -1230,6 +1233,7 @@ ENTRY(ftrace_graph_caller)
pushl
%
edx
movl
0xc
(%
esp
),
%
edx
lea
0x4
(%
ebp
),
%
eax
subl
$MCOUNT_INSN_SIZE
,
%
edx
call
prepare_ftrace_return
popl
%
edx
popl
%
ecx
...
...
arch/x86/kernel/entry_64.S
View file @
b29144c3
...
...
@@ -120,6 +120,9 @@ ENTRY(mcount)
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
cmpq
$ftrace_stub
,
ftrace_graph_return
jnz
ftrace_graph_caller
cmpq
$ftrace_graph_entry_stub
,
ftrace_graph_entry
jnz
ftrace_graph_caller
#endif
.
globl
ftrace_stub
...
...
@@ -173,6 +176,7 @@ ENTRY(ftrace_graph_caller)
leaq
8
(%
rbp
),
%
rdi
movq
0x38
(%
rsp
),
%
rsi
subq
$MCOUNT_INSN_SIZE
,
%
rsi
call
prepare_ftrace_return
...
...
arch/x86/kernel/ftrace.c
View file @
b29144c3
...
...
@@ -420,12 +420,23 @@ static void pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret)
int
index
;
index
=
current
->
curr_ret_stack
;
if
(
unlikely
(
index
<
0
))
{
ftrace_graph_stop
();
WARN_ON
(
1
);
/* Might as well panic, otherwise we have no where to go */
*
ret
=
(
unsigned
long
)
panic
;
return
;
}
*
ret
=
current
->
ret_stack
[
index
].
ret
;
trace
->
func
=
current
->
ret_stack
[
index
].
func
;
trace
->
calltime
=
current
->
ret_stack
[
index
].
calltime
;
trace
->
overrun
=
atomic_read
(
&
current
->
trace_overrun
);
trace
->
depth
=
index
;
barrier
();
current
->
curr_ret_stack
--
;
}
/*
...
...
@@ -441,6 +452,13 @@ unsigned long ftrace_return_to_handler(void)
trace
.
rettime
=
cpu_clock
(
raw_smp_processor_id
());
ftrace_graph_return
(
&
trace
);
if
(
unlikely
(
!
ret
))
{
ftrace_graph_stop
();
WARN_ON
(
1
);
/* Might as well panic. What else to do? */
ret
=
(
unsigned
long
)
panic
;
}
return
ret
;
}
...
...
@@ -467,28 +485,16 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
* ignore such a protection.
*/
asm
volatile
(
#ifdef CONFIG_X86_64
"1: movq (%[parent_old]), %[old]
\n
"
"2: movq %[return_hooker], (%[parent_replaced])
\n
"
#else
"1: movl (%[parent_old]), %[old]
\n
"
"2: movl %[return_hooker], (%[parent_replaced])
\n
"
#endif
"1: "
_ASM_MOV
" (%[parent_old]), %[old]
\n
"
"2: "
_ASM_MOV
" %[return_hooker], (%[parent_replaced])
\n
"
" movl $0, %[faulted]
\n
"
".section .fixup,
\"
ax
\"\n
"
"3: movl $1, %[faulted]
\n
"
".previous
\n
"
".section __ex_table,
\"
a
\"\n
"
#ifdef CONFIG_X86_64
" .quad 1b, 3b
\n
"
" .quad 2b, 3b
\n
"
#else
" .long 1b, 3b
\n
"
" .long 2b, 3b
\n
"
#endif
".previous
\n
"
_ASM_EXTABLE
(
1
b
,
3
b
)
_ASM_EXTABLE
(
2
b
,
3
b
)
:
[
parent_replaced
]
"=r"
(
parent
),
[
old
]
"=r"
(
old
),
[
faulted
]
"=r"
(
faulted
)
...
...
@@ -496,14 +502,16 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
:
"memory"
);
if
(
WARN_ON
(
faulted
))
{
unregister_ftrace_graph
();
if
(
unlikely
(
faulted
))
{
ftrace_graph_stop
();
WARN_ON
(
1
);
return
;
}
if
(
WARN_ON
(
!
__kernel_text_address
(
old
)))
{
unregister_ftrace_graph
();
if
(
unlikely
(
!
__kernel_text_address
(
old
)))
{
ftrace_graph_stop
();
*
parent
=
old
;
WARN_ON
(
1
);
return
;
}
...
...
@@ -516,7 +524,11 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
}
trace
.
func
=
self_addr
;
ftrace_graph_entry
(
&
trace
);
/* Only trace if the calling function expects to */
if
(
!
ftrace_graph_entry
(
&
trace
))
{
current
->
curr_ret_stack
--
;
*
parent
=
old
;
}
}
#endif
/* CONFIG_FUNCTION_GRAPH_TRACER */
arch/x86/mm/fault.c
View file @
b29144c3
...
...
@@ -413,6 +413,7 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs,
unsigned
long
error_code
)
{
unsigned
long
flags
=
oops_begin
();
int
sig
=
SIGKILL
;
struct
task_struct
*
tsk
;
printk
(
KERN_ALERT
"%s: Corrupted page table at address %lx
\n
"
,
...
...
@@ -423,8 +424,8 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs,
tsk
->
thread
.
trap_no
=
14
;
tsk
->
thread
.
error_code
=
error_code
;
if
(
__die
(
"Bad pagetable"
,
regs
,
error_code
))
regs
=
NULL
;
oops_end
(
flags
,
regs
,
SIGKILL
);
sig
=
0
;
oops_end
(
flags
,
regs
,
sig
);
}
#endif
...
...
@@ -590,6 +591,7 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
int
fault
;
#ifdef CONFIG_X86_64
unsigned
long
flags
;
int
sig
;
#endif
tsk
=
current
;
...
...
@@ -849,11 +851,12 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
bust_spinlocks
(
0
);
do_exit
(
SIGKILL
);
#else
sig
=
SIGKILL
;
if
(
__die
(
"Oops"
,
regs
,
error_code
))
regs
=
NULL
;
sig
=
0
;
/* Executive summary in case the body of the oops scrolled away */
printk
(
KERN_EMERG
"CR2: %016lx
\n
"
,
address
);
oops_end
(
flags
,
regs
,
SIGKILL
);
oops_end
(
flags
,
regs
,
sig
);
#endif
/*
...
...
include/linux/ftrace.h
View file @
b29144c3
...
...
@@ -371,11 +371,13 @@ struct ftrace_graph_ret {
#define FTRACE_RETSTACK_ALLOC_SIZE 32
/* Type of the callback handlers for tracing function graph*/
typedef
void
(
*
trace_func_graph_ret_t
)(
struct
ftrace_graph_ret
*
);
/* return */
typedef
void
(
*
trace_func_graph_ent_t
)(
struct
ftrace_graph_ent
*
);
/* entry */
typedef
int
(
*
trace_func_graph_ent_t
)(
struct
ftrace_graph_ent
*
);
/* entry */
extern
int
register_ftrace_graph
(
trace_func_graph_ret_t
retfunc
,
trace_func_graph_ent_t
entryfunc
);
extern
void
ftrace_graph_stop
(
void
);
/* The current handlers in use */
extern
trace_func_graph_ret_t
ftrace_graph_return
;
extern
trace_func_graph_ent_t
ftrace_graph_entry
;
...
...
include/linux/ring_buffer.h
View file @
b29144c3
...
...
@@ -124,6 +124,11 @@ void tracing_on(void);
void
tracing_off
(
void
);
void
tracing_off_permanent
(
void
);
void
*
ring_buffer_alloc_read_page
(
struct
ring_buffer
*
buffer
);
void
ring_buffer_free_read_page
(
struct
ring_buffer
*
buffer
,
void
*
data
);
int
ring_buffer_read_page
(
struct
ring_buffer
*
buffer
,
void
**
data_page
,
int
cpu
,
int
full
);
enum
ring_buffer_flags
{
RB_FL_OVERWRITE
=
1
<<
0
,
};
...
...
kernel/fork.c
View file @
b29144c3
...
...
@@ -1137,6 +1137,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
}
}
ftrace_graph_init_task
(
p
);
p
->
pid
=
pid_nr
(
pid
);
p
->
tgid
=
p
->
pid
;
if
(
clone_flags
&
CLONE_THREAD
)
...
...
@@ -1145,7 +1147,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
if
(
current
->
nsproxy
!=
p
->
nsproxy
)
{
retval
=
ns_cgroup_clone
(
p
,
pid
);
if
(
retval
)
goto
bad_fork_free_
pid
;
goto
bad_fork_free_
graph
;
}
p
->
set_child_tid
=
(
clone_flags
&
CLONE_CHILD_SETTID
)
?
child_tidptr
:
NULL
;
...
...
@@ -1238,7 +1240,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
spin_unlock
(
&
current
->
sighand
->
siglock
);
write_unlock_irq
(
&
tasklist_lock
);
retval
=
-
ERESTARTNOINTR
;
goto
bad_fork_free_
pid
;
goto
bad_fork_free_
graph
;
}
if
(
clone_flags
&
CLONE_THREAD
)
{
...
...
@@ -1271,11 +1273,12 @@ static struct task_struct *copy_process(unsigned long clone_flags,
total_forks
++
;
spin_unlock
(
&
current
->
sighand
->
siglock
);
write_unlock_irq
(
&
tasklist_lock
);
ftrace_graph_init_task
(
p
);
proc_fork_connector
(
p
);
cgroup_post_fork
(
p
);
return
p
;
bad_fork_free_graph:
ftrace_graph_exit_task
(
p
);
bad_fork_free_pid:
if
(
pid
!=
&
init_struct_pid
)
free_pid
(
pid
);
...
...
kernel/lockdep.c
View file @
b29144c3
...
...
@@ -25,6 +25,7 @@
* Thanks to Arjan van de Ven for coming up with the initial idea of
* mapping lock dependencies runtime.
*/
#define DISABLE_BRANCH_PROFILING
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/delay.h>
...
...
kernel/trace/Kconfig
View file @
b29144c3
...
...
@@ -67,6 +67,7 @@ config FUNCTION_GRAPH_TRACER
bool "Kernel Function Graph Tracer"
depends on HAVE_FUNCTION_GRAPH_TRACER
depends on FUNCTION_TRACER
default y
help
Enable the kernel to trace a function at both its return
and its entry.
...
...
kernel/trace/ftrace.c
View file @
b29144c3
...
...
@@ -1636,11 +1636,15 @@ ftrace_enable_sysctl(struct ctl_table *table, int write,
static
atomic_t
ftrace_graph_active
;
int
ftrace_graph_entry_stub
(
struct
ftrace_graph_ent
*
trace
)
{
return
0
;
}
/* The callbacks that hook a function */
trace_func_graph_ret_t
ftrace_graph_return
=
(
trace_func_graph_ret_t
)
ftrace_stub
;
trace_func_graph_ent_t
ftrace_graph_entry
=
(
trace_func_graph_ent_t
)
ftrace_stub
;
trace_func_graph_ent_t
ftrace_graph_entry
=
ftrace_graph_entry_stub
;
/* Try to assign a return stack array on FTRACE_RETSTACK_ALLOC_SIZE tasks. */
static
int
alloc_retstack_tasklist
(
struct
ftrace_ret_stack
**
ret_stack_list
)
...
...
@@ -1738,7 +1742,7 @@ void unregister_ftrace_graph(void)
atomic_dec
(
&
ftrace_graph_active
);
ftrace_graph_return
=
(
trace_func_graph_ret_t
)
ftrace_stub
;
ftrace_graph_entry
=
(
trace_func_graph_ent_t
)
ftrace
_stub
;
ftrace_graph_entry
=
ftrace_graph_entry
_stub
;
ftrace_shutdown
(
FTRACE_STOP_FUNC_RET
);
mutex_unlock
(
&
ftrace_sysctl_lock
);
...
...
@@ -1769,5 +1773,10 @@ void ftrace_graph_exit_task(struct task_struct *t)
kfree
(
ret_stack
);
}
void
ftrace_graph_stop
(
void
)
{
ftrace_stop
();
}
#endif
kernel/trace/ring_buffer.c
View file @
b29144c3
...
...
@@ -195,20 +195,24 @@ void *ring_buffer_event_data(struct ring_buffer_event *event)
#define TS_MASK ((1ULL << TS_SHIFT) - 1)
#define TS_DELTA_TEST (~TS_MASK)
/*
* This hack stolen from mm/slob.c.
* We can store per page timing information in the page frame of the page.
* Thanks to Peter Zijlstra for suggesting this idea.
*/
struct
buffer_page
{
struct
buffer_data_page
{
u64
time_stamp
;
/* page time stamp */
local_t
write
;
/* index for next write */
local_t
commit
;
/* write commited index */
unsigned
char
data
[];
/* data of buffer page */
};
struct
buffer_page
{
local_t
write
;
/* index for next write */
unsigned
read
;
/* index for next read */
struct
list_head
list
;
/* list of free pages */
void
*
page
;
/* Actual data page */
struct
buffer_data_page
*
page
;
/* Actual data page */
};
static
void
rb_init_page
(
struct
buffer_data_page
*
bpage
)
{
local_set
(
&
bpage
->
commit
,
0
);
}
/*
* Also stolen from mm/slob.c. Thanks to Mathieu Desnoyers for pointing
* this issue out.
...
...
@@ -230,7 +234,7 @@ static inline int test_time_stamp(u64 delta)
return
0
;
}
#define BUF_PAGE_SIZE
PAGE_SIZE
#define BUF_PAGE_SIZE
(PAGE_SIZE - sizeof(struct buffer_data_page))
/*
* head_page == tail_page && head == tail then buffer is empty.
...
...
@@ -294,19 +298,19 @@ struct ring_buffer_iter {
static
int
rb_check_pages
(
struct
ring_buffer_per_cpu
*
cpu_buffer
)
{
struct
list_head
*
head
=
&
cpu_buffer
->
pages
;
struct
buffer_page
*
page
,
*
tmp
;
struct
buffer_page
*
b
page
,
*
tmp
;
if
(
RB_WARN_ON
(
cpu_buffer
,
head
->
next
->
prev
!=
head
))
return
-
1
;
if
(
RB_WARN_ON
(
cpu_buffer
,
head
->
prev
->
next
!=
head
))
return
-
1
;
list_for_each_entry_safe
(
page
,
tmp
,
head
,
list
)
{
list_for_each_entry_safe
(
b
page
,
tmp
,
head
,
list
)
{
if
(
RB_WARN_ON
(
cpu_buffer
,
page
->
list
.
next
->
prev
!=
&
page
->
list
))
bpage
->
list
.
next
->
prev
!=
&
b
page
->
list
))
return
-
1
;
if
(
RB_WARN_ON
(
cpu_buffer
,
page
->
list
.
prev
->
next
!=
&
page
->
list
))
bpage
->
list
.
prev
->
next
!=
&
b
page
->
list
))
return
-
1
;
}
...
...
@@ -317,22 +321,23 @@ static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
unsigned
nr_pages
)
{
struct
list_head
*
head
=
&
cpu_buffer
->
pages
;
struct
buffer_page
*
page
,
*
tmp
;
struct
buffer_page
*
b
page
,
*
tmp
;
unsigned
long
addr
;
LIST_HEAD
(
pages
);
unsigned
i
;
for
(
i
=
0
;
i
<
nr_pages
;
i
++
)
{
page
=
kzalloc_node
(
ALIGN
(
sizeof
(
*
page
),
cache_line_size
()),
bpage
=
kzalloc_node
(
ALIGN
(
sizeof
(
*
b
page
),
cache_line_size
()),
GFP_KERNEL
,
cpu_to_node
(
cpu_buffer
->
cpu
));
if
(
!
page
)
if
(
!
b
page
)
goto
free_pages
;
list_add
(
&
page
->
list
,
&
pages
);
list_add
(
&
b
page
->
list
,
&
pages
);
addr
=
__get_free_page
(
GFP_KERNEL
);
if
(
!
addr
)
goto
free_pages
;
page
->
page
=
(
void
*
)
addr
;
bpage
->
page
=
(
void
*
)
addr
;
rb_init_page
(
bpage
->
page
);
}
list_splice
(
&
pages
,
head
);
...
...
@@ -342,9 +347,9 @@ static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
return
0
;
free_pages:
list_for_each_entry_safe
(
page
,
tmp
,
&
pages
,
list
)
{
list_del_init
(
&
page
->
list
);
free_buffer_page
(
page
);
list_for_each_entry_safe
(
b
page
,
tmp
,
&
pages
,
list
)
{
list_del_init
(
&
b
page
->
list
);
free_buffer_page
(
b
page
);
}
return
-
ENOMEM
;
}
...
...
@@ -353,7 +358,7 @@ static struct ring_buffer_per_cpu *
rb_allocate_cpu_buffer
(
struct
ring_buffer
*
buffer
,
int
cpu
)
{
struct
ring_buffer_per_cpu
*
cpu_buffer
;
struct
buffer_page
*
page
;
struct
buffer_page
*
b
page
;
unsigned
long
addr
;
int
ret
;
...
...
@@ -368,16 +373,17 @@ rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu)
cpu_buffer
->
lock
=
(
raw_spinlock_t
)
__RAW_SPIN_LOCK_UNLOCKED
;
INIT_LIST_HEAD
(
&
cpu_buffer
->
pages
);
page
=
kzalloc_node
(
ALIGN
(
sizeof
(
*
page
),
cache_line_size
()),
bpage
=
kzalloc_node
(
ALIGN
(
sizeof
(
*
b
page
),
cache_line_size
()),
GFP_KERNEL
,
cpu_to_node
(
cpu
));
if
(
!
page
)
if
(
!
b
page
)
goto
fail_free_buffer
;
cpu_buffer
->
reader_page
=
page
;
cpu_buffer
->
reader_page
=
b
page
;
addr
=
__get_free_page
(
GFP_KERNEL
);
if
(
!
addr
)
goto
fail_free_reader
;
page
->
page
=
(
void
*
)
addr
;
bpage
->
page
=
(
void
*
)
addr
;
rb_init_page
(
bpage
->
page
);
INIT_LIST_HEAD
(
&
cpu_buffer
->
reader_page
->
list
);
...
...
@@ -402,14 +408,14 @@ rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu)
static
void
rb_free_cpu_buffer
(
struct
ring_buffer_per_cpu
*
cpu_buffer
)
{
struct
list_head
*
head
=
&
cpu_buffer
->
pages
;
struct
buffer_page
*
page
,
*
tmp
;
struct
buffer_page
*
b
page
,
*
tmp
;
list_del_init
(
&
cpu_buffer
->
reader_page
->
list
);
free_buffer_page
(
cpu_buffer
->
reader_page
);
list_for_each_entry_safe
(
page
,
tmp
,
head
,
list
)
{
list_del_init
(
&
page
->
list
);
free_buffer_page
(
page
);
list_for_each_entry_safe
(
b
page
,
tmp
,
head
,
list
)
{
list_del_init
(
&
b
page
->
list
);
free_buffer_page
(
b
page
);
}
kfree
(
cpu_buffer
);
}
...
...
@@ -506,7 +512,7 @@ static void rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer);
static
void
rb_remove_pages
(
struct
ring_buffer_per_cpu
*
cpu_buffer
,
unsigned
nr_pages
)
{
struct
buffer_page
*
page
;
struct
buffer_page
*
b
page
;
struct
list_head
*
p
;
unsigned
i
;
...
...
@@ -517,9 +523,9 @@ rb_remove_pages(struct ring_buffer_per_cpu *cpu_buffer, unsigned nr_pages)
if
(
RB_WARN_ON
(
cpu_buffer
,
list_empty
(
&
cpu_buffer
->
pages
)))
return
;
p
=
cpu_buffer
->
pages
.
next
;
page
=
list_entry
(
p
,
struct
buffer_page
,
list
);
list_del_init
(
&
page
->
list
);
free_buffer_page
(
page
);
b
page
=
list_entry
(
p
,
struct
buffer_page
,
list
);
list_del_init
(
&
b
page
->
list
);
free_buffer_page
(
b
page
);
}
if
(
RB_WARN_ON
(
cpu_buffer
,
list_empty
(
&
cpu_buffer
->
pages
)))
return
;
...
...
@@ -536,7 +542,7 @@ static void
rb_insert_pages
(
struct
ring_buffer_per_cpu
*
cpu_buffer
,
struct
list_head
*
pages
,
unsigned
nr_pages
)
{
struct
buffer_page
*
page
;
struct
buffer_page
*
b
page
;
struct
list_head
*
p
;
unsigned
i
;
...
...
@@ -547,9 +553,9 @@ rb_insert_pages(struct ring_buffer_per_cpu *cpu_buffer,
if
(
RB_WARN_ON
(
cpu_buffer
,
list_empty
(
pages
)))
return
;
p
=
pages
->
next
;
page
=
list_entry
(
p
,
struct
buffer_page
,
list
);
list_del_init
(
&
page
->
list
);
list_add_tail
(
&
page
->
list
,
&
cpu_buffer
->
pages
);
b
page
=
list_entry
(
p
,
struct
buffer_page
,
list
);
list_del_init
(
&
b
page
->
list
);
list_add_tail
(
&
b
page
->
list
,
&
cpu_buffer
->
pages
);
}
rb_reset_cpu
(
cpu_buffer
);
...
...
@@ -576,7 +582,7 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size)
{
struct
ring_buffer_per_cpu
*
cpu_buffer
;
unsigned
nr_pages
,
rm_pages
,
new_pages
;
struct
buffer_page
*
page
,
*
tmp
;
struct
buffer_page
*
b
page
,
*
tmp
;
unsigned
long
buffer_size
;
unsigned
long
addr
;
LIST_HEAD
(
pages
);
...
...
@@ -637,16 +643,17 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size)
for_each_buffer_cpu
(
buffer
,
cpu
)
{
for
(
i
=
0
;
i
<
new_pages
;
i
++
)
{
page
=
kzalloc_node
(
ALIGN
(
sizeof
(
*
page
),
bpage
=
kzalloc_node
(
ALIGN
(
sizeof
(
*
b
page
),
cache_line_size
()),
GFP_KERNEL
,
cpu_to_node
(
cpu
));
if
(
!
page
)
if
(
!
b
page
)
goto
free_pages
;
list_add
(
&
page
->
list
,
&
pages
);
list_add
(
&
b
page
->
list
,
&
pages
);
addr
=
__get_free_page
(
GFP_KERNEL
);
if
(
!
addr
)
goto
free_pages
;
page
->
page
=
(
void
*
)
addr
;
bpage
->
page
=
(
void
*
)
addr
;
rb_init_page
(
bpage
->
page
);
}
}
...
...
@@ -667,9 +674,9 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size)
return
size
;
free_pages:
list_for_each_entry_safe
(
page
,
tmp
,
&
pages
,
list
)
{
list_del_init
(
&
page
->
list
);
free_buffer_page
(
page
);
list_for_each_entry_safe
(
b
page
,
tmp
,
&
pages
,
list
)
{
list_del_init
(
&
b
page
->
list
);
free_buffer_page
(
b
page
);
}
mutex_unlock
(
&
buffer
->
mutex
);
return
-
ENOMEM
;
...
...
@@ -680,9 +687,15 @@ static inline int rb_null_event(struct ring_buffer_event *event)
return
event
->
type
==
RINGBUF_TYPE_PADDING
;
}
static
inline
void
*
__rb_page_index
(
struct
buffer_page
*
page
,
unsigned
index
)
static
inline
void
*
__rb_data_page_index
(
struct
buffer_data_page
*
bpage
,
unsigned
index
)
{
return
page
->
page
+
index
;
return
bpage
->
data
+
index
;
}
static
inline
void
*
__rb_page_index
(
struct
buffer_page
*
bpage
,
unsigned
index
)
{
return
bpage
->
page
->
data
+
index
;
}
static
inline
struct
ring_buffer_event
*
...
...
@@ -712,7 +725,7 @@ static inline unsigned rb_page_write(struct buffer_page *bpage)
static
inline
unsigned
rb_page_commit
(
struct
buffer_page
*
bpage
)
{
return
local_read
(
&
bpage
->
commit
);
return
local_read
(
&
bpage
->
page
->
commit
);
}
/* Size is determined by what has been commited */
...
...
@@ -758,14 +771,14 @@ static void rb_update_overflow(struct ring_buffer_per_cpu *cpu_buffer)
}
static
inline
void
rb_inc_page
(
struct
ring_buffer_per_cpu
*
cpu_buffer
,
struct
buffer_page
**
page
)
struct
buffer_page
**
b
page
)
{
struct
list_head
*
p
=
(
*
page
)
->
list
.
next
;
struct
list_head
*
p
=
(
*
b
page
)
->
list
.
next
;
if
(
p
==
&
cpu_buffer
->
pages
)
p
=
p
->
next
;
*
page
=
list_entry
(
p
,
struct
buffer_page
,
list
);
*
b
page
=
list_entry
(
p
,
struct
buffer_page
,
list
);
}
static
inline
unsigned
...
...
@@ -804,14 +817,15 @@ rb_set_commit_event(struct ring_buffer_per_cpu *cpu_buffer,
if
(
RB_WARN_ON
(
cpu_buffer
,
cpu_buffer
->
commit_page
==
cpu_buffer
->
tail_page
))
return
;
cpu_buffer
->
commit_page
->
commit
=
cpu_buffer
->
commit_page
->
page
->
commit
=
cpu_buffer
->
commit_page
->
write
;
rb_inc_page
(
cpu_buffer
,
&
cpu_buffer
->
commit_page
);
cpu_buffer
->
write_stamp
=
cpu_buffer
->
commit_page
->
time_stamp
;
cpu_buffer
->
write_stamp
=
cpu_buffer
->
commit_page
->
page
->
time_stamp
;
}
/* Now set the commit to the event's index */
local_set
(
&
cpu_buffer
->
commit_page
->
commit
,
index
);
local_set
(
&
cpu_buffer
->
commit_page
->
page
->
commit
,
index
);
}
static
inline
void
...
...
@@ -826,16 +840,17 @@ rb_set_commit_to_write(struct ring_buffer_per_cpu *cpu_buffer)
* assign the commit to the tail.
*/
while
(
cpu_buffer
->
commit_page
!=
cpu_buffer
->
tail_page
)
{
cpu_buffer
->
commit_page
->
commit
=
cpu_buffer
->
commit_page
->
page
->
commit
=
cpu_buffer
->
commit_page
->
write
;
rb_inc_page
(
cpu_buffer
,
&
cpu_buffer
->
commit_page
);
cpu_buffer
->
write_stamp
=
cpu_buffer
->
commit_page
->
time_stamp
;
cpu_buffer
->
write_stamp
=
cpu_buffer
->
commit_page
->
page
->
time_stamp
;
/* add barrier to keep gcc from optimizing too much */
barrier
();
}
while
(
rb_commit_index
(
cpu_buffer
)
!=
rb_page_write
(
cpu_buffer
->
commit_page
))
{
cpu_buffer
->
commit_page
->
commit
=
cpu_buffer
->
commit_page
->
page
->
commit
=
cpu_buffer
->
commit_page
->
write
;
barrier
();
}
...
...
@@ -843,7 +858,7 @@ rb_set_commit_to_write(struct ring_buffer_per_cpu *cpu_buffer)
static
void
rb_reset_reader_page
(
struct
ring_buffer_per_cpu
*
cpu_buffer
)
{
cpu_buffer
->
read_stamp
=
cpu_buffer
->
reader_page
->
time_stamp
;
cpu_buffer
->
read_stamp
=
cpu_buffer
->
reader_page
->
page
->
time_stamp
;
cpu_buffer
->
reader_page
->
read
=
0
;
}
...
...
@@ -862,7 +877,7 @@ static inline void rb_inc_iter(struct ring_buffer_iter *iter)
else
rb_inc_page
(
cpu_buffer
,
&
iter
->
head_page
);
iter
->
read_stamp
=
iter
->
head_page
->
time_stamp
;
iter
->
read_stamp
=
iter
->
head_page
->
page
->
time_stamp
;
iter
->
head
=
0
;
}
...
...
@@ -998,12 +1013,12 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
*/
if
(
tail_page
==
cpu_buffer
->
tail_page
)
{
local_set
(
&
next_page
->
write
,
0
);
local_set
(
&
next_page
->
commit
,
0
);
local_set
(
&
next_page
->
page
->
commit
,
0
);
cpu_buffer
->
tail_page
=
next_page
;
/* reread the time stamp */
*
ts
=
ring_buffer_time_stamp
(
cpu_buffer
->
cpu
);
cpu_buffer
->
tail_page
->
time_stamp
=
*
ts
;
cpu_buffer
->
tail_page
->
page
->
time_stamp
=
*
ts
;
}
/*
...
...
@@ -1048,7 +1063,7 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
* this page's time stamp.
*/
if
(
!
tail
&&
rb_is_commit
(
cpu_buffer
,
event
))
cpu_buffer
->
commit_page
->
time_stamp
=
*
ts
;
cpu_buffer
->
commit_page
->
page
->
time_stamp
=
*
ts
;
return
event
;
...
...
@@ -1099,7 +1114,7 @@ rb_add_time_stamp(struct ring_buffer_per_cpu *cpu_buffer,
event
->
time_delta
=
*
delta
&
TS_MASK
;
event
->
array
[
0
]
=
*
delta
>>
TS_SHIFT
;
}
else
{
cpu_buffer
->
commit_page
->
time_stamp
=
*
ts
;
cpu_buffer
->
commit_page
->
page
->
time_stamp
=
*
ts
;
event
->
time_delta
=
0
;
event
->
array
[
0
]
=
0
;
}
...
...
@@ -1552,7 +1567,7 @@ static void rb_iter_reset(struct ring_buffer_iter *iter)
if
(
iter
->
head
)
iter
->
read_stamp
=
cpu_buffer
->
read_stamp
;
else
iter
->
read_stamp
=
iter
->
head_page
->
time_stamp
;
iter
->
read_stamp
=
iter
->
head_page
->
page
->
time_stamp
;
}
/**
...
...
@@ -1696,7 +1711,7 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
cpu_buffer
->
reader_page
->
list
.
prev
=
reader
->
list
.
prev
;
local_set
(
&
cpu_buffer
->
reader_page
->
write
,
0
);
local_set
(
&
cpu_buffer
->
reader_page
->
commit
,
0
);
local_set
(
&
cpu_buffer
->
reader_page
->
page
->
commit
,
0
);
/* Make the reader page now replace the head */
reader
->
list
.
prev
->
next
=
&
cpu_buffer
->
reader_page
->
list
;
...
...
@@ -2088,7 +2103,7 @@ rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer)
cpu_buffer
->
head_page
=
list_entry
(
cpu_buffer
->
pages
.
next
,
struct
buffer_page
,
list
);
local_set
(
&
cpu_buffer
->
head_page
->
write
,
0
);
local_set
(
&
cpu_buffer
->
head_page
->
commit
,
0
);
local_set
(
&
cpu_buffer
->
head_page
->
page
->
commit
,
0
);
cpu_buffer
->
head_page
->
read
=
0
;
...
...
@@ -2097,7 +2112,7 @@ rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer)
INIT_LIST_HEAD
(
&
cpu_buffer
->
reader_page
->
list
);
local_set
(
&
cpu_buffer
->
reader_page
->
write
,
0
);
local_set
(
&
cpu_buffer
->
reader_page
->
commit
,
0
);
local_set
(
&
cpu_buffer
->
reader_page
->
page
->
commit
,
0
);
cpu_buffer
->
reader_page
->
read
=
0
;
cpu_buffer
->
overrun
=
0
;
...
...
@@ -2223,6 +2238,166 @@ int ring_buffer_swap_cpu(struct ring_buffer *buffer_a,
return
0
;
}
static
void
rb_remove_entries
(
struct
ring_buffer_per_cpu
*
cpu_buffer
,
struct
buffer_data_page
*
bpage
)
{
struct
ring_buffer_event
*
event
;
unsigned
long
head
;
__raw_spin_lock
(
&
cpu_buffer
->
lock
);
for
(
head
=
0
;
head
<
local_read
(
&
bpage
->
commit
);
head
+=
rb_event_length
(
event
))
{
event
=
__rb_data_page_index
(
bpage
,
head
);
if
(
RB_WARN_ON
(
cpu_buffer
,
rb_null_event
(
event
)))
return
;
/* Only count data entries */
if
(
event
->
type
!=
RINGBUF_TYPE_DATA
)
continue
;
cpu_buffer
->
entries
--
;
}
__raw_spin_unlock
(
&
cpu_buffer
->
lock
);
}
/**
* ring_buffer_alloc_read_page - allocate a page to read from buffer
* @buffer: the buffer to allocate for.
*
* This function is used in conjunction with ring_buffer_read_page.
* When reading a full page from the ring buffer, these functions
* can be used to speed up the process. The calling function should
* allocate a few pages first with this function. Then when it
* needs to get pages from the ring buffer, it passes the result
* of this function into ring_buffer_read_page, which will swap
* the page that was allocated, with the read page of the buffer.
*
* Returns:
* The page allocated, or NULL on error.
*/
void
*
ring_buffer_alloc_read_page
(
struct
ring_buffer
*
buffer
)
{
unsigned
long
addr
;
struct
buffer_data_page
*
bpage
;
addr
=
__get_free_page
(
GFP_KERNEL
);
if
(
!
addr
)
return
NULL
;
bpage
=
(
void
*
)
addr
;
return
bpage
;
}
/**
* ring_buffer_free_read_page - free an allocated read page
* @buffer: the buffer the page was allocate for
* @data: the page to free
*
* Free a page allocated from ring_buffer_alloc_read_page.
*/
void
ring_buffer_free_read_page
(
struct
ring_buffer
*
buffer
,
void
*
data
)
{
free_page
((
unsigned
long
)
data
);
}
/**
* ring_buffer_read_page - extract a page from the ring buffer
* @buffer: buffer to extract from
* @data_page: the page to use allocated from ring_buffer_alloc_read_page
* @cpu: the cpu of the buffer to extract
* @full: should the extraction only happen when the page is full.
*
* This function will pull out a page from the ring buffer and consume it.
* @data_page must be the address of the variable that was returned
* from ring_buffer_alloc_read_page. This is because the page might be used
* to swap with a page in the ring buffer.
*
* for example:
* rpage = ring_buffer_alloc_page(buffer);
* if (!rpage)
* return error;
* ret = ring_buffer_read_page(buffer, &rpage, cpu, 0);
* if (ret)
* process_page(rpage);
*
* When @full is set, the function will not return true unless
* the writer is off the reader page.
*
* Note: it is up to the calling functions to handle sleeps and wakeups.
* The ring buffer can be used anywhere in the kernel and can not
* blindly call wake_up. The layer that uses the ring buffer must be
* responsible for that.
*
* Returns:
* 1 if data has been transferred
* 0 if no data has been transferred.
*/
int
ring_buffer_read_page
(
struct
ring_buffer
*
buffer
,
void
**
data_page
,
int
cpu
,
int
full
)
{
struct
ring_buffer_per_cpu
*
cpu_buffer
=
buffer
->
buffers
[
cpu
];
struct
ring_buffer_event
*
event
;
struct
buffer_data_page
*
bpage
;
unsigned
long
flags
;
int
ret
=
0
;
if
(
!
data_page
)
return
0
;
bpage
=
*
data_page
;
if
(
!
bpage
)
return
0
;
spin_lock_irqsave
(
&
cpu_buffer
->
reader_lock
,
flags
);
/*
* rb_buffer_peek will get the next ring buffer if
* the current reader page is empty.
*/
event
=
rb_buffer_peek
(
buffer
,
cpu
,
NULL
);
if
(
!
event
)
goto
out
;
/* check for data */
if
(
!
local_read
(
&
cpu_buffer
->
reader_page
->
page
->
commit
))
goto
out
;
/*
* If the writer is already off of the read page, then simply
* switch the read page with the given page. Otherwise
* we need to copy the data from the reader to the writer.
*/
if
(
cpu_buffer
->
reader_page
==
cpu_buffer
->
commit_page
)
{
unsigned
int
read
=
cpu_buffer
->
reader_page
->
read
;
if
(
full
)
goto
out
;
/* The writer is still on the reader page, we must copy */
bpage
=
cpu_buffer
->
reader_page
->
page
;
memcpy
(
bpage
->
data
,
cpu_buffer
->
reader_page
->
page
->
data
+
read
,
local_read
(
&
bpage
->
commit
)
-
read
);
/* consume what was read */
cpu_buffer
->
reader_page
+=
read
;
}
else
{
/* swap the pages */
rb_init_page
(
bpage
);
bpage
=
cpu_buffer
->
reader_page
->
page
;
cpu_buffer
->
reader_page
->
page
=
*
data_page
;
cpu_buffer
->
reader_page
->
read
=
0
;
*
data_page
=
bpage
;
}
ret
=
1
;
/* update the entry counter */
rb_remove_entries
(
cpu_buffer
,
bpage
);
out:
spin_unlock_irqrestore
(
&
cpu_buffer
->
reader_lock
,
flags
);
return
ret
;
}
static
ssize_t
rb_simple_read
(
struct
file
*
filp
,
char
__user
*
ubuf
,
size_t
cnt
,
loff_t
*
ppos
)
...
...
kernel/trace/trace.c
View file @
b29144c3
...
...
@@ -1200,7 +1200,7 @@ function_trace_call(unsigned long ip, unsigned long parent_ip)
}
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
void
trace_graph_entry
(
struct
ftrace_graph_ent
*
trace
)
int
trace_graph_entry
(
struct
ftrace_graph_ent
*
trace
)
{
struct
trace_array
*
tr
=
&
global_trace
;
struct
trace_array_cpu
*
data
;
...
...
@@ -1209,7 +1209,7 @@ void trace_graph_entry(struct ftrace_graph_ent *trace)
int
cpu
;
int
pc
;
raw_
local_irq_save
(
flags
);
local_irq_save
(
flags
);
cpu
=
raw_smp_processor_id
();
data
=
tr
->
data
[
cpu
];
disabled
=
atomic_inc_return
(
&
data
->
disabled
);
...
...
@@ -1218,7 +1218,9 @@ void trace_graph_entry(struct ftrace_graph_ent *trace)
__trace_graph_entry
(
tr
,
data
,
trace
,
flags
,
pc
);
}
atomic_dec
(
&
data
->
disabled
);
raw_local_irq_restore
(
flags
);
local_irq_restore
(
flags
);
return
1
;
}
void
trace_graph_return
(
struct
ftrace_graph_ret
*
trace
)
...
...
@@ -1230,7 +1232,7 @@ void trace_graph_return(struct ftrace_graph_ret *trace)
int
cpu
;
int
pc
;
raw_
local_irq_save
(
flags
);
local_irq_save
(
flags
);
cpu
=
raw_smp_processor_id
();
data
=
tr
->
data
[
cpu
];
disabled
=
atomic_inc_return
(
&
data
->
disabled
);
...
...
@@ -1239,7 +1241,7 @@ void trace_graph_return(struct ftrace_graph_ret *trace)
__trace_graph_return
(
tr
,
data
,
trace
,
flags
,
pc
);
}
atomic_dec
(
&
data
->
disabled
);
raw_
local_irq_restore
(
flags
);
local_irq_restore
(
flags
);
}
#endif
/* CONFIG_FUNCTION_GRAPH_TRACER */
...
...
@@ -2645,7 +2647,7 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf,
if
(
err
)
goto
err_unlock
;
raw_
local_irq_disable
();
local_irq_disable
();
__raw_spin_lock
(
&
ftrace_max_lock
);
for_each_tracing_cpu
(
cpu
)
{
/*
...
...
@@ -2662,7 +2664,7 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf,
}
}
__raw_spin_unlock
(
&
ftrace_max_lock
);
raw_
local_irq_enable
();
local_irq_enable
();
tracing_cpumask
=
tracing_cpumask_new
;
...
...
kernel/trace/trace.h
View file @
b29144c3
...
...
@@ -412,7 +412,7 @@ void trace_function(struct trace_array *tr,
unsigned
long
flags
,
int
pc
);
void
trace_graph_return
(
struct
ftrace_graph_ret
*
trace
);
void
trace_graph_entry
(
struct
ftrace_graph_ent
*
trace
);
int
trace_graph_entry
(
struct
ftrace_graph_ent
*
trace
);
void
trace_bts
(
struct
trace_array
*
tr
,
unsigned
long
from
,
unsigned
long
to
);
...
...
kernel/trace/trace_branch.c
View file @
b29144c3
...
...
@@ -42,7 +42,7 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect)
if
(
unlikely
(
!
tr
))
return
;
raw_
local_irq_save
(
flags
);
local_irq_save
(
flags
);
cpu
=
raw_smp_processor_id
();
if
(
atomic_inc_return
(
&
tr
->
data
[
cpu
]
->
disabled
)
!=
1
)
goto
out
;
...
...
@@ -74,7 +74,7 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect)
out:
atomic_dec
(
&
tr
->
data
[
cpu
]
->
disabled
);
raw_
local_irq_restore
(
flags
);
local_irq_restore
(
flags
);
}
static
inline
...
...
kernel/trace/trace_functions_graph.c
View file @
b29144c3
...
...
@@ -19,6 +19,7 @@
#define TRACE_GRAPH_PRINT_OVERRUN 0x1
#define TRACE_GRAPH_PRINT_CPU 0x2
#define TRACE_GRAPH_PRINT_OVERHEAD 0x4
#define TRACE_GRAPH_PRINT_PROC 0x8
static
struct
tracer_opt
trace_opts
[]
=
{
/* Display overruns ? */
...
...
@@ -27,11 +28,13 @@ static struct tracer_opt trace_opts[] = {
{
TRACER_OPT
(
funcgraph
-
cpu
,
TRACE_GRAPH_PRINT_CPU
)
},
/* Display Overhead ? */
{
TRACER_OPT
(
funcgraph
-
overhead
,
TRACE_GRAPH_PRINT_OVERHEAD
)
},
/* Display proc name/pid */
{
TRACER_OPT
(
funcgraph
-
proc
,
TRACE_GRAPH_PRINT_PROC
)
},
{
}
/* Empty entry */
};
static
struct
tracer_flags
tracer_flags
=
{
/* Don't display overruns by default */
/* Don't display overruns
and proc
by default */
.
val
=
TRACE_GRAPH_PRINT_CPU
|
TRACE_GRAPH_PRINT_OVERHEAD
,
.
opts
=
trace_opts
};
...
...
@@ -104,23 +107,63 @@ print_graph_cpu(struct trace_seq *s, int cpu)
return
TRACE_TYPE_HANDLED
;
}
#define TRACE_GRAPH_PROCINFO_LENGTH 14
static
enum
print_line_t
print_graph_proc
(
struct
trace_seq
*
s
,
pid_t
pid
)
{
int
i
;
int
ret
;
int
len
;
char
comm
[
8
];
int
spaces
=
0
;
/* sign + log10(MAX_INT) + '\0' */
char
pid_str
[
11
];
strncpy
(
comm
,
trace_find_cmdline
(
pid
),
7
);
comm
[
7
]
=
'\0'
;
sprintf
(
pid_str
,
"%d"
,
pid
);
/* 1 stands for the "-" character */
len
=
strlen
(
comm
)
+
strlen
(
pid_str
)
+
1
;
if
(
len
<
TRACE_GRAPH_PROCINFO_LENGTH
)
spaces
=
TRACE_GRAPH_PROCINFO_LENGTH
-
len
;
/* First spaces to align center */
for
(
i
=
0
;
i
<
spaces
/
2
;
i
++
)
{
ret
=
trace_seq_printf
(
s
,
" "
);
if
(
!
ret
)
return
TRACE_TYPE_PARTIAL_LINE
;
}
ret
=
trace_seq_printf
(
s
,
"%s-%s"
,
comm
,
pid_str
);
if
(
!
ret
)
return
TRACE_TYPE_PARTIAL_LINE
;
/* Last spaces to align center */
for
(
i
=
0
;
i
<
spaces
-
(
spaces
/
2
);
i
++
)
{
ret
=
trace_seq_printf
(
s
,
" "
);
if
(
!
ret
)
return
TRACE_TYPE_PARTIAL_LINE
;
}
return
TRACE_TYPE_HANDLED
;
}
/* If the pid changed since the last trace, output this event */
static
int
verif_pid
(
struct
trace_seq
*
s
,
pid_t
pid
,
int
cpu
)
static
enum
print_line_t
verif_pid
(
struct
trace_seq
*
s
,
pid_t
pid
,
int
cpu
)
{
char
*
comm
,
*
prev_comm
;
pid_t
prev_pid
;
int
ret
;
if
(
last_pid
[
cpu
]
!=
-
1
&&
last_pid
[
cpu
]
==
pid
)
return
1
;
return
TRACE_TYPE_HANDLED
;
prev_pid
=
last_pid
[
cpu
];
last_pid
[
cpu
]
=
pid
;
comm
=
trace_find_cmdline
(
pid
);
prev_comm
=
trace_find_cmdline
(
prev_pid
);
/*
* Context-switch trace line:
...
...
@@ -130,11 +173,31 @@ static int verif_pid(struct trace_seq *s, pid_t pid, int cpu)
*/
ret
=
trace_seq_printf
(
s
,
" ------------------------------------------
\n
"
);
ret
+=
trace_seq_printf
(
s
,
" | %d) %s-%d => %s-%d
\n
"
,
cpu
,
prev_comm
,
prev_pid
,
comm
,
pid
);
ret
+=
trace_seq_printf
(
s
,
" ------------------------------------------
\n\n
"
);
"
\n
------------------------------------------
\n
|"
);
if
(
!
ret
)
TRACE_TYPE_PARTIAL_LINE
;
ret
=
print_graph_cpu
(
s
,
cpu
);
if
(
ret
==
TRACE_TYPE_PARTIAL_LINE
)
TRACE_TYPE_PARTIAL_LINE
;
ret
=
print_graph_proc
(
s
,
prev_pid
);
if
(
ret
==
TRACE_TYPE_PARTIAL_LINE
)
TRACE_TYPE_PARTIAL_LINE
;
ret
=
trace_seq_printf
(
s
,
" => "
);
if
(
!
ret
)
TRACE_TYPE_PARTIAL_LINE
;
ret
=
print_graph_proc
(
s
,
pid
);
if
(
ret
==
TRACE_TYPE_PARTIAL_LINE
)
TRACE_TYPE_PARTIAL_LINE
;
ret
=
trace_seq_printf
(
s
,
"
\n
------------------------------------------
\n\n
"
);
if
(
!
ret
)
TRACE_TYPE_PARTIAL_LINE
;
return
ret
;
}
...
...
@@ -169,11 +232,50 @@ trace_branch_is_leaf(struct trace_iterator *iter,
}
static
inline
in
t
static
enum
print_line_
t
print_graph_duration
(
unsigned
long
long
duration
,
struct
trace_seq
*
s
)
{
unsigned
long
nsecs_rem
=
do_div
(
duration
,
1000
);
return
trace_seq_printf
(
s
,
"%4llu.%3lu us | "
,
duration
,
nsecs_rem
);
/* log10(ULONG_MAX) + '\0' */
char
msecs_str
[
21
];
char
nsecs_str
[
5
];
int
ret
,
len
;
int
i
;
sprintf
(
msecs_str
,
"%lu"
,
(
unsigned
long
)
duration
);
/* Print msecs */
ret
=
trace_seq_printf
(
s
,
msecs_str
);
if
(
!
ret
)
return
TRACE_TYPE_PARTIAL_LINE
;
len
=
strlen
(
msecs_str
);
/* Print nsecs (we don't want to exceed 7 numbers) */
if
(
len
<
7
)
{
snprintf
(
nsecs_str
,
8
-
len
,
"%03lu"
,
nsecs_rem
);
ret
=
trace_seq_printf
(
s
,
".%s"
,
nsecs_str
);
if
(
!
ret
)
return
TRACE_TYPE_PARTIAL_LINE
;
len
+=
strlen
(
nsecs_str
);
}
ret
=
trace_seq_printf
(
s
,
" us "
);
if
(
!
ret
)
return
TRACE_TYPE_PARTIAL_LINE
;
/* Print remaining spaces to fit the row's width */
for
(
i
=
len
;
i
<
7
;
i
++
)
{
ret
=
trace_seq_printf
(
s
,
" "
);
if
(
!
ret
)
return
TRACE_TYPE_PARTIAL_LINE
;
}
ret
=
trace_seq_printf
(
s
,
"| "
);
if
(
!
ret
)
return
TRACE_TYPE_PARTIAL_LINE
;
return
TRACE_TYPE_HANDLED
;
}
/* Signal a overhead of time execution to the output */
...
...
@@ -210,10 +312,6 @@ print_graph_entry_leaf(struct trace_iterator *iter,
call
=
&
entry
->
graph_ent
;
duration
=
graph_ret
->
rettime
-
graph_ret
->
calltime
;
/* Must not exceed 8 characters: 9999.999 us */
if
(
duration
>
10000000ULL
)
duration
=
9999999ULL
;
/* Overhead */
if
(
tracer_flags
.
val
&
TRACE_GRAPH_PRINT_OVERHEAD
)
{
ret
=
print_graph_overhead
(
duration
,
s
);
...
...
@@ -223,7 +321,7 @@ print_graph_entry_leaf(struct trace_iterator *iter,
/* Duration */
ret
=
print_graph_duration
(
duration
,
s
);
if
(
!
ret
)
if
(
ret
==
TRACE_TYPE_PARTIAL_LINE
)
return
TRACE_TYPE_PARTIAL_LINE
;
/* Function */
...
...
@@ -288,12 +386,23 @@ print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s,
struct
trace_entry
*
ent
=
iter
->
ent
;
/* Pid */
if
(
!
verif_pid
(
s
,
ent
->
pid
,
cpu
)
)
if
(
verif_pid
(
s
,
ent
->
pid
,
cpu
)
==
TRACE_TYPE_PARTIAL_LINE
)
return
TRACE_TYPE_PARTIAL_LINE
;
/* Cpu */
if
(
tracer_flags
.
val
&
TRACE_GRAPH_PRINT_CPU
)
{
ret
=
print_graph_cpu
(
s
,
cpu
);
if
(
ret
==
TRACE_TYPE_PARTIAL_LINE
)
return
TRACE_TYPE_PARTIAL_LINE
;
}
/* Proc */
if
(
tracer_flags
.
val
&
TRACE_GRAPH_PRINT_PROC
)
{
ret
=
print_graph_proc
(
s
,
ent
->
pid
);
if
(
ret
==
TRACE_TYPE_PARTIAL_LINE
)
return
TRACE_TYPE_PARTIAL_LINE
;
ret
=
trace_seq_printf
(
s
,
" | "
);
if
(
!
ret
)
return
TRACE_TYPE_PARTIAL_LINE
;
}
...
...
@@ -313,17 +422,24 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
int
ret
;
unsigned
long
long
duration
=
trace
->
rettime
-
trace
->
calltime
;
/* Must not exceed 8 characters: xxxx.yyy us */
if
(
duration
>
10000000ULL
)
duration
=
9999999ULL
;
/* Pid */
if
(
!
verif_pid
(
s
,
ent
->
pid
,
cpu
)
)
if
(
verif_pid
(
s
,
ent
->
pid
,
cpu
)
==
TRACE_TYPE_PARTIAL_LINE
)
return
TRACE_TYPE_PARTIAL_LINE
;
/* Cpu */
if
(
tracer_flags
.
val
&
TRACE_GRAPH_PRINT_CPU
)
{
ret
=
print_graph_cpu
(
s
,
cpu
);
if
(
ret
==
TRACE_TYPE_PARTIAL_LINE
)
return
TRACE_TYPE_PARTIAL_LINE
;
}
/* Proc */
if
(
tracer_flags
.
val
&
TRACE_GRAPH_PRINT_PROC
)
{
ret
=
print_graph_proc
(
s
,
ent
->
pid
);
if
(
ret
==
TRACE_TYPE_PARTIAL_LINE
)
return
TRACE_TYPE_PARTIAL_LINE
;
ret
=
trace_seq_printf
(
s
,
" | "
);
if
(
!
ret
)
return
TRACE_TYPE_PARTIAL_LINE
;
}
...
...
@@ -337,7 +453,7 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
/* Duration */
ret
=
print_graph_duration
(
duration
,
s
);
if
(
!
ret
)
if
(
ret
==
TRACE_TYPE_PARTIAL_LINE
)
return
TRACE_TYPE_PARTIAL_LINE
;
/* Closing brace */
...
...
kernel/trace/trace_stack.c
View file @
b29144c3
...
...
@@ -48,7 +48,7 @@ static inline void check_stack(void)
if
(
!
object_is_on_stack
(
&
this_size
))
return
;
raw_
local_irq_save
(
flags
);
local_irq_save
(
flags
);
__raw_spin_lock
(
&
max_stack_lock
);
/* a race could have already updated it */
...
...
@@ -78,6 +78,7 @@ static inline void check_stack(void)
* on a new max, so it is far from a fast path.
*/
while
(
i
<
max_stack_trace
.
nr_entries
)
{
int
found
=
0
;
stack_dump_index
[
i
]
=
this_size
;
p
=
start
;
...
...
@@ -86,17 +87,19 @@ static inline void check_stack(void)
if
(
*
p
==
stack_dump_trace
[
i
])
{
this_size
=
stack_dump_index
[
i
++
]
=
(
top
-
p
)
*
sizeof
(
unsigned
long
);
found
=
1
;
/* Start the search from here */
start
=
p
+
1
;
}
}
i
++
;
if
(
!
found
)
i
++
;
}
out:
__raw_spin_unlock
(
&
max_stack_lock
);
raw_
local_irq_restore
(
flags
);
local_irq_restore
(
flags
);
}
static
void
...
...
@@ -162,11 +165,11 @@ stack_max_size_write(struct file *filp, const char __user *ubuf,
if
(
ret
<
0
)
return
ret
;
raw_
local_irq_save
(
flags
);
local_irq_save
(
flags
);
__raw_spin_lock
(
&
max_stack_lock
);
*
ptr
=
val
;
__raw_spin_unlock
(
&
max_stack_lock
);
raw_
local_irq_restore
(
flags
);
local_irq_restore
(
flags
);
return
count
;
}
...
...
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