Merge branch 'tracing/core-v2' into tracing-for-linus
Conflicts: include/linux/slub_def.h lib/Kconfig.debug mm/slob.c mm/slub.c
This commit is contained in:
commit
8302294f43
|
@ -0,0 +1,71 @@
|
|||
What: /sys/kernel/debug/kmemtrace/
|
||||
Date: July 2008
|
||||
Contact: Eduard - Gabriel Munteanu <eduard.munteanu@linux360.ro>
|
||||
Description:
|
||||
|
||||
In kmemtrace-enabled kernels, the following files are created:
|
||||
|
||||
/sys/kernel/debug/kmemtrace/
|
||||
cpu<n> (0400) Per-CPU tracing data, see below. (binary)
|
||||
total_overruns (0400) Total number of bytes which were dropped from
|
||||
cpu<n> files because of full buffer condition,
|
||||
non-binary. (text)
|
||||
abi_version (0400) Kernel's kmemtrace ABI version. (text)
|
||||
|
||||
Each per-CPU file should be read according to the relay interface. That is,
|
||||
the reader should set affinity to that specific CPU and, as currently done by
|
||||
the userspace application (though there are other methods), use poll() with
|
||||
an infinite timeout before every read(). Otherwise, erroneous data may be
|
||||
read. The binary data has the following _core_ format:
|
||||
|
||||
Event ID (1 byte) Unsigned integer, one of:
|
||||
0 - represents an allocation (KMEMTRACE_EVENT_ALLOC)
|
||||
1 - represents a freeing of previously allocated memory
|
||||
(KMEMTRACE_EVENT_FREE)
|
||||
Type ID (1 byte) Unsigned integer, one of:
|
||||
0 - this is a kmalloc() / kfree()
|
||||
1 - this is a kmem_cache_alloc() / kmem_cache_free()
|
||||
2 - this is a __get_free_pages() et al.
|
||||
Event size (2 bytes) Unsigned integer representing the
|
||||
size of this event. Used to extend
|
||||
kmemtrace. Discard the bytes you
|
||||
don't know about.
|
||||
Sequence number (4 bytes) Signed integer used to reorder data
|
||||
logged on SMP machines. Wraparound
|
||||
must be taken into account, although
|
||||
it is unlikely.
|
||||
Caller address (8 bytes) Return address to the caller.
|
||||
Pointer to mem (8 bytes) Pointer to target memory area. Can be
|
||||
NULL, but not all such calls might be
|
||||
recorded.
|
||||
|
||||
In case of KMEMTRACE_EVENT_ALLOC events, the next fields follow:
|
||||
|
||||
Requested bytes (8 bytes) Total number of requested bytes,
|
||||
unsigned, must not be zero.
|
||||
Allocated bytes (8 bytes) Total number of actually allocated
|
||||
bytes, unsigned, must not be lower
|
||||
than requested bytes.
|
||||
Requested flags (4 bytes) GFP flags supplied by the caller.
|
||||
Target CPU (4 bytes) Signed integer, valid for event id 1.
|
||||
If equal to -1, target CPU is the same
|
||||
as origin CPU, but the reverse might
|
||||
not be true.
|
||||
|
||||
The data is made available in the same endianness the machine has.
|
||||
|
||||
Other event ids and type ids may be defined and added. Other fields may be
|
||||
added by increasing event size, but see below for details.
|
||||
Every modification to the ABI, including new id definitions, are followed
|
||||
by bumping the ABI version by one.
|
||||
|
||||
Adding new data to the packet (features) is done at the end of the mandatory
|
||||
data:
|
||||
Feature size (2 byte)
|
||||
Feature ID (1 byte)
|
||||
Feature data (Feature size - 3 bytes)
|
||||
|
||||
|
||||
Users:
|
||||
kmemtrace-user - git://repo.or.cz/kmemtrace-user.git
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -50,6 +50,7 @@ parameter is applicable:
|
|||
ISAPNP ISA PnP code is enabled.
|
||||
ISDN Appropriate ISDN support is enabled.
|
||||
JOY Appropriate joystick support is enabled.
|
||||
KMEMTRACE kmemtrace is enabled.
|
||||
LIBATA Libata driver is enabled
|
||||
LP Printer support is enabled.
|
||||
LOOP Loopback device support is enabled.
|
||||
|
@ -1078,6 +1079,15 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
use the HighMem zone if it exists, and the Normal
|
||||
zone if it does not.
|
||||
|
||||
kmemtrace.enable= [KNL,KMEMTRACE] Format: { yes | no }
|
||||
Controls whether kmemtrace is enabled
|
||||
at boot-time.
|
||||
|
||||
kmemtrace.subbufs=n [KNL,KMEMTRACE] Overrides the number of
|
||||
subbufs kmemtrace's relay channel has. Set this
|
||||
higher than default (KMEMTRACE_N_SUBBUFS in code) if
|
||||
you experience buffer overruns.
|
||||
|
||||
movablecore=nn[KMG] [KNL,X86-32,IA-64,PPC,X86-64] This parameter
|
||||
is similar to kernelcore except it specifies the
|
||||
amount of memory used for migratable allocations.
|
||||
|
@ -2362,6 +2372,8 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
|
||||
tp720= [HW,PS2]
|
||||
|
||||
trace_buf_size=nn[KMG] [ftrace] will set tracing buffer size.
|
||||
|
||||
trix= [HW,OSS] MediaTrix AudioTrix Pro
|
||||
Format:
|
||||
<io>,<irq>,<dma>,<dma2>,<sb_io>,<sb_irq>,<sb_dma>,<mpu_io>,<mpu_irq>
|
||||
|
|
|
@ -115,6 +115,8 @@ On all - write a character to /proc/sysrq-trigger. e.g.:
|
|||
|
||||
'x' - Used by xmon interface on ppc/powerpc platforms.
|
||||
|
||||
'z' - Dump the ftrace buffer
|
||||
|
||||
'0'-'9' - Sets the console log level, controlling which kernel messages
|
||||
will be printed to your console. ('0', for example would make
|
||||
it so that only emergency messages like PANICs or OOPSes would
|
||||
|
|
|
@ -45,8 +45,8 @@ In include/trace/subsys.h :
|
|||
#include <linux/tracepoint.h>
|
||||
|
||||
DECLARE_TRACE(subsys_eventname,
|
||||
TPPROTO(int firstarg, struct task_struct *p),
|
||||
TPARGS(firstarg, p));
|
||||
TP_PROTO(int firstarg, struct task_struct *p),
|
||||
TP_ARGS(firstarg, p));
|
||||
|
||||
In subsys/file.c (where the tracing statement must be added) :
|
||||
|
||||
|
@ -66,10 +66,10 @@ Where :
|
|||
- subsys is the name of your subsystem.
|
||||
- eventname is the name of the event to trace.
|
||||
|
||||
- TPPROTO(int firstarg, struct task_struct *p) is the prototype of the
|
||||
- TP_PROTO(int firstarg, struct task_struct *p) is the prototype of the
|
||||
function called by this tracepoint.
|
||||
|
||||
- TPARGS(firstarg, p) are the parameters names, same as found in the
|
||||
- TP_ARGS(firstarg, p) are the parameters names, same as found in the
|
||||
prototype.
|
||||
|
||||
Connecting a function (probe) to a tracepoint is done by providing a
|
||||
|
@ -103,13 +103,14 @@ used to export the defined tracepoints.
|
|||
|
||||
* Probe / tracepoint example
|
||||
|
||||
See the example provided in samples/tracepoints/src
|
||||
See the example provided in samples/tracepoints
|
||||
|
||||
Compile them with your kernel.
|
||||
Compile them with your kernel. They are built during 'make' (not
|
||||
'make modules') when CONFIG_SAMPLE_TRACEPOINTS=m.
|
||||
|
||||
Run, as root :
|
||||
modprobe tracepoint-example (insmod order is not important)
|
||||
modprobe tracepoint-probe-example
|
||||
cat /proc/tracepoint-example (returns an expected error)
|
||||
rmmod tracepoint-example tracepoint-probe-example
|
||||
modprobe tracepoint-sample (insmod order is not important)
|
||||
modprobe tracepoint-probe-sample
|
||||
cat /proc/tracepoint-sample (returns an expected error)
|
||||
rmmod tracepoint-sample tracepoint-probe-sample
|
||||
dmesg
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
kmemtrace - Kernel Memory Tracer
|
||||
|
||||
by Eduard - Gabriel Munteanu
|
||||
<eduard.munteanu@linux360.ro>
|
||||
|
||||
I. Introduction
|
||||
===============
|
||||
|
||||
kmemtrace helps kernel developers figure out two things:
|
||||
1) how different allocators (SLAB, SLUB etc.) perform
|
||||
2) how kernel code allocates memory and how much
|
||||
|
||||
To do this, we trace every allocation and export information to the userspace
|
||||
through the relay interface. We export things such as the number of requested
|
||||
bytes, the number of bytes actually allocated (i.e. including internal
|
||||
fragmentation), whether this is a slab allocation or a plain kmalloc() and so
|
||||
on.
|
||||
|
||||
The actual analysis is performed by a userspace tool (see section III for
|
||||
details on where to get it from). It logs the data exported by the kernel,
|
||||
processes it and (as of writing this) can provide the following information:
|
||||
- the total amount of memory allocated and fragmentation per call-site
|
||||
- the amount of memory allocated and fragmentation per allocation
|
||||
- total memory allocated and fragmentation in the collected dataset
|
||||
- number of cross-CPU allocation and frees (makes sense in NUMA environments)
|
||||
|
||||
Moreover, it can potentially find inconsistent and erroneous behavior in
|
||||
kernel code, such as using slab free functions on kmalloc'ed memory or
|
||||
allocating less memory than requested (but not truly failed allocations).
|
||||
|
||||
kmemtrace also makes provisions for tracing on some arch and analysing the
|
||||
data on another.
|
||||
|
||||
II. Design and goals
|
||||
====================
|
||||
|
||||
kmemtrace was designed to handle rather large amounts of data. Thus, it uses
|
||||
the relay interface to export whatever is logged to userspace, which then
|
||||
stores it. Analysis and reporting is done asynchronously, that is, after the
|
||||
data is collected and stored. By design, it allows one to log and analyse
|
||||
on different machines and different arches.
|
||||
|
||||
As of writing this, the ABI is not considered stable, though it might not
|
||||
change much. However, no guarantees are made about compatibility yet. When
|
||||
deemed stable, the ABI should still allow easy extension while maintaining
|
||||
backward compatibility. This is described further in Documentation/ABI.
|
||||
|
||||
Summary of design goals:
|
||||
- allow logging and analysis to be done across different machines
|
||||
- be fast and anticipate usage in high-load environments (*)
|
||||
- be reasonably extensible
|
||||
- make it possible for GNU/Linux distributions to have kmemtrace
|
||||
included in their repositories
|
||||
|
||||
(*) - one of the reasons Pekka Enberg's original userspace data analysis
|
||||
tool's code was rewritten from Perl to C (although this is more than a
|
||||
simple conversion)
|
||||
|
||||
|
||||
III. Quick usage guide
|
||||
======================
|
||||
|
||||
1) Get a kernel that supports kmemtrace and build it accordingly (i.e. enable
|
||||
CONFIG_KMEMTRACE).
|
||||
|
||||
2) Get the userspace tool and build it:
|
||||
$ git-clone git://repo.or.cz/kmemtrace-user.git # current repository
|
||||
$ cd kmemtrace-user/
|
||||
$ ./autogen.sh
|
||||
$ ./configure
|
||||
$ make
|
||||
|
||||
3) Boot the kmemtrace-enabled kernel if you haven't, preferably in the
|
||||
'single' runlevel (so that relay buffers don't fill up easily), and run
|
||||
kmemtrace:
|
||||
# '$' does not mean user, but root here.
|
||||
$ mount -t debugfs none /sys/kernel/debug
|
||||
$ mount -t proc none /proc
|
||||
$ cd path/to/kmemtrace-user/
|
||||
$ ./kmemtraced
|
||||
Wait a bit, then stop it with CTRL+C.
|
||||
$ cat /sys/kernel/debug/kmemtrace/total_overruns # Check if we didn't
|
||||
# overrun, should
|
||||
# be zero.
|
||||
$ (Optionally) [Run kmemtrace_check separately on each cpu[0-9]*.out file to
|
||||
check its correctness]
|
||||
$ ./kmemtrace-report
|
||||
|
||||
Now you should have a nice and short summary of how the allocator performs.
|
||||
|
||||
IV. FAQ and known issues
|
||||
========================
|
||||
|
||||
Q: 'cat /sys/kernel/debug/kmemtrace/total_overruns' is non-zero, how do I fix
|
||||
this? Should I worry?
|
||||
A: If it's non-zero, this affects kmemtrace's accuracy, depending on how
|
||||
large the number is. You can fix it by supplying a higher
|
||||
'kmemtrace.subbufs=N' kernel parameter.
|
||||
---
|
||||
|
||||
Q: kmemtrace_check reports errors, how do I fix this? Should I worry?
|
||||
A: This is a bug and should be reported. It can occur for a variety of
|
||||
reasons:
|
||||
- possible bugs in relay code
|
||||
- possible misuse of relay by kmemtrace
|
||||
- timestamps being collected unorderly
|
||||
Or you may fix it yourself and send us a patch.
|
||||
---
|
||||
|
||||
Q: kmemtrace_report shows many errors, how do I fix this? Should I worry?
|
||||
A: This is a known issue and I'm working on it. These might be true errors
|
||||
in kernel code, which may have inconsistent behavior (e.g. allocating memory
|
||||
with kmem_cache_alloc() and freeing it with kfree()). Pekka Enberg pointed
|
||||
out this behavior may work with SLAB, but may fail with other allocators.
|
||||
|
||||
It may also be due to lack of tracing in some unusual allocator functions.
|
||||
|
||||
We don't want bug reports regarding this issue yet.
|
||||
---
|
||||
|
||||
V. See also
|
||||
===========
|
||||
|
||||
Documentation/kernel-parameters.txt
|
||||
Documentation/ABI/testing/debugfs-kmemtrace
|
||||
|
|
@ -2642,6 +2642,12 @@ M: jason.wessel@windriver.com
|
|||
L: kgdb-bugreport@lists.sourceforge.net
|
||||
S: Maintained
|
||||
|
||||
KMEMTRACE
|
||||
P: Eduard - Gabriel Munteanu
|
||||
M: eduard.munteanu@linux360.ro
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
KPROBES
|
||||
P: Ananth N Mavinakayanahalli
|
||||
M: ananth@in.ibm.com
|
||||
|
|
|
@ -6,6 +6,7 @@ config OPROFILE
|
|||
tristate "OProfile system profiling (EXPERIMENTAL)"
|
||||
depends on PROFILING
|
||||
depends on HAVE_OPROFILE
|
||||
depends on TRACING_SUPPORT
|
||||
select TRACING
|
||||
select RING_BUFFER
|
||||
help
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/* empty */
|
|
@ -14,17 +14,4 @@ typedef struct {
|
|||
|
||||
void ack_bad_irq(unsigned int irq);
|
||||
|
||||
#define HARDIRQ_BITS 12
|
||||
|
||||
/*
|
||||
* The hardirq mask has to be large enough to have
|
||||
* space for potentially nestable IRQ sources in the system
|
||||
* to nest on a single CPU. On Alpha, interrupts are masked at the CPU
|
||||
* by IPL as well as at the system level. We only have 8 IPLs (UNIX PALcode)
|
||||
* so we really only have 8 nestable IRQs, but allow some overhead
|
||||
*/
|
||||
#if (1 << HARDIRQ_BITS) < 16
|
||||
#error HARDIRQ_BITS is too low!
|
||||
#endif
|
||||
|
||||
#endif /* _ALPHA_HARDIRQ_H */
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/* empty */
|
|
@ -20,15 +20,4 @@ void ack_bad_irq(unsigned int irq);
|
|||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#define HARDIRQ_BITS 12
|
||||
|
||||
/*
|
||||
* The hardirq mask has to be large enough to have
|
||||
* space for potentially all IRQ sources in the system
|
||||
* nesting on a single CPU:
|
||||
*/
|
||||
#if (1 << HARDIRQ_BITS) < NR_IRQS
|
||||
# error HARDIRQ_BITS is too low!
|
||||
#endif
|
||||
|
||||
#endif /* __ASM_AVR32_HARDIRQ_H */
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/* empty */
|
|
@ -0,0 +1 @@
|
|||
/* empty */
|
|
@ -0,0 +1 @@
|
|||
/* empty */
|
|
@ -22,6 +22,9 @@ config IA64
|
|||
select HAVE_OPROFILE
|
||||
select HAVE_KPROBES
|
||||
select HAVE_KRETPROBES
|
||||
select HAVE_FTRACE_MCOUNT_RECORD
|
||||
select HAVE_DYNAMIC_FTRACE if (!ITANIUM)
|
||||
select HAVE_FUNCTION_TRACER
|
||||
select HAVE_DMA_ATTRS
|
||||
select HAVE_KVM
|
||||
select HAVE_ARCH_TRACEHOOK
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef _ASM_IA64_FTRACE_H
|
||||
#define _ASM_IA64_FTRACE_H
|
||||
|
||||
#ifdef CONFIG_FUNCTION_TRACER
|
||||
#define MCOUNT_INSN_SIZE 32 /* sizeof mcount call */
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
extern void _mcount(unsigned long pfs, unsigned long r1, unsigned long b0, unsigned long r0);
|
||||
#define mcount _mcount
|
||||
|
||||
#include <asm/kprobes.h>
|
||||
/* In IA64, MCOUNT_ADDR is set in link time, so it's not a constant at compile time */
|
||||
#define MCOUNT_ADDR (((struct fnptr *)mcount)->ip)
|
||||
#define FTRACE_ADDR (((struct fnptr *)ftrace_caller)->ip)
|
||||
|
||||
static inline unsigned long ftrace_call_adjust(unsigned long addr)
|
||||
{
|
||||
/* second bundle, insn 2 */
|
||||
return addr - 0x12;
|
||||
}
|
||||
|
||||
struct dyn_arch_ftrace {
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_FUNCTION_TRACER */
|
||||
|
||||
#endif /* _ASM_IA64_FTRACE_H */
|
|
@ -20,16 +20,6 @@
|
|||
|
||||
#define local_softirq_pending() (local_cpu_data->softirq_pending)
|
||||
|
||||
#define HARDIRQ_BITS 14
|
||||
|
||||
/*
|
||||
* The hardirq mask has to be large enough to have space for potentially all IRQ sources
|
||||
* in the system nesting on a single CPU:
|
||||
*/
|
||||
#if (1 << HARDIRQ_BITS) < NR_IRQS
|
||||
# error HARDIRQ_BITS is too low!
|
||||
#endif
|
||||
|
||||
extern void __iomem *ipi_base_addr;
|
||||
|
||||
void ack_bad_irq(unsigned int irq);
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
# Makefile for the linux kernel.
|
||||
#
|
||||
|
||||
ifdef CONFIG_DYNAMIC_FTRACE
|
||||
CFLAGS_REMOVE_ftrace.o = -pg
|
||||
endif
|
||||
|
||||
extra-y := head.o init_task.o vmlinux.lds
|
||||
|
||||
obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o \
|
||||
|
@ -28,6 +32,7 @@ obj-$(CONFIG_IA64_CYCLONE) += cyclone.o
|
|||
obj-$(CONFIG_CPU_FREQ) += cpufreq/
|
||||
obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
|
||||
obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o
|
||||
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
|
||||
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o
|
||||
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
|
||||
obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include <asm/processor.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/unistd.h>
|
||||
#include <asm/ftrace.h>
|
||||
|
||||
#include "minstate.h"
|
||||
|
||||
|
@ -1404,6 +1405,105 @@ GLOBAL_ENTRY(unw_init_running)
|
|||
br.ret.sptk.many rp
|
||||
END(unw_init_running)
|
||||
|
||||
#ifdef CONFIG_FUNCTION_TRACER
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
GLOBAL_ENTRY(_mcount)
|
||||
br ftrace_stub
|
||||
END(_mcount)
|
||||
|
||||
.here:
|
||||
br.ret.sptk.many b0
|
||||
|
||||
GLOBAL_ENTRY(ftrace_caller)
|
||||
alloc out0 = ar.pfs, 8, 0, 4, 0
|
||||
mov out3 = r0
|
||||
;;
|
||||
mov out2 = b0
|
||||
add r3 = 0x20, r3
|
||||
mov out1 = r1;
|
||||
br.call.sptk.many b0 = ftrace_patch_gp
|
||||
//this might be called from module, so we must patch gp
|
||||
ftrace_patch_gp:
|
||||
movl gp=__gp
|
||||
mov b0 = r3
|
||||
;;
|
||||
.global ftrace_call;
|
||||
ftrace_call:
|
||||
{
|
||||
.mlx
|
||||
nop.m 0x0
|
||||
movl r3 = .here;;
|
||||
}
|
||||
alloc loc0 = ar.pfs, 4, 4, 2, 0
|
||||
;;
|
||||
mov loc1 = b0
|
||||
mov out0 = b0
|
||||
mov loc2 = r8
|
||||
mov loc3 = r15
|
||||
;;
|
||||
adds out0 = -MCOUNT_INSN_SIZE, out0
|
||||
mov out1 = in2
|
||||
mov b6 = r3
|
||||
|
||||
br.call.sptk.many b0 = b6
|
||||
;;
|
||||
mov ar.pfs = loc0
|
||||
mov b0 = loc1
|
||||
mov r8 = loc2
|
||||
mov r15 = loc3
|
||||
br ftrace_stub
|
||||
;;
|
||||
END(ftrace_caller)
|
||||
|
||||
#else
|
||||
GLOBAL_ENTRY(_mcount)
|
||||
movl r2 = ftrace_stub
|
||||
movl r3 = ftrace_trace_function;;
|
||||
ld8 r3 = [r3];;
|
||||
ld8 r3 = [r3];;
|
||||
cmp.eq p7,p0 = r2, r3
|
||||
(p7) br.sptk.many ftrace_stub
|
||||
;;
|
||||
|
||||
alloc loc0 = ar.pfs, 4, 4, 2, 0
|
||||
;;
|
||||
mov loc1 = b0
|
||||
mov out0 = b0
|
||||
mov loc2 = r8
|
||||
mov loc3 = r15
|
||||
;;
|
||||
adds out0 = -MCOUNT_INSN_SIZE, out0
|
||||
mov out1 = in2
|
||||
mov b6 = r3
|
||||
|
||||
br.call.sptk.many b0 = b6
|
||||
;;
|
||||
mov ar.pfs = loc0
|
||||
mov b0 = loc1
|
||||
mov r8 = loc2
|
||||
mov r15 = loc3
|
||||
br ftrace_stub
|
||||
;;
|
||||
END(_mcount)
|
||||
#endif
|
||||
|
||||
GLOBAL_ENTRY(ftrace_stub)
|
||||
mov r3 = b0
|
||||
movl r2 = _mcount_ret_helper
|
||||
;;
|
||||
mov b6 = r2
|
||||
mov b7 = r3
|
||||
br.ret.sptk.many b6
|
||||
|
||||
_mcount_ret_helper:
|
||||
mov b0 = r42
|
||||
mov r1 = r41
|
||||
mov ar.pfs = r40
|
||||
br b7
|
||||
END(ftrace_stub)
|
||||
|
||||
#endif /* CONFIG_FUNCTION_TRACER */
|
||||
|
||||
.rodata
|
||||
.align 8
|
||||
.globl sys_call_table
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* Dynamic function tracing support.
|
||||
*
|
||||
* Copyright (C) 2008 Shaohua Li <shaohua.li@intel.com>
|
||||
*
|
||||
* For licencing details, see COPYING.
|
||||
*
|
||||
* Defines low-level handling of mcount calls when the kernel
|
||||
* is compiled with the -pg flag. When using dynamic ftrace, the
|
||||
* mcount call-sites get patched lazily with NOP till they are
|
||||
* enabled. All code mutation routines here take effect atomically.
|
||||
*/
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/ftrace.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/patch.h>
|
||||
|
||||
/* In IA64, each function will be added below two bundles with -pg option */
|
||||
static unsigned char __attribute__((aligned(8)))
|
||||
ftrace_orig_code[MCOUNT_INSN_SIZE] = {
|
||||
0x02, 0x40, 0x31, 0x10, 0x80, 0x05, /* alloc r40=ar.pfs,12,8,0 */
|
||||
0xb0, 0x02, 0x00, 0x00, 0x42, 0x40, /* mov r43=r0;; */
|
||||
0x05, 0x00, 0xc4, 0x00, /* mov r42=b0 */
|
||||
0x11, 0x48, 0x01, 0x02, 0x00, 0x21, /* mov r41=r1 */
|
||||
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, /* nop.i 0x0 */
|
||||
0x08, 0x00, 0x00, 0x50 /* br.call.sptk.many b0 = _mcount;; */
|
||||
};
|
||||
|
||||
struct ftrace_orig_insn {
|
||||
u64 dummy1, dummy2, dummy3;
|
||||
u64 dummy4:64-41+13;
|
||||
u64 imm20:20;
|
||||
u64 dummy5:3;
|
||||
u64 sign:1;
|
||||
u64 dummy6:4;
|
||||
};
|
||||
|
||||
/* mcount stub will be converted below for nop */
|
||||
static unsigned char ftrace_nop_code[MCOUNT_INSN_SIZE] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MII] nop.m 0x0 */
|
||||
0x30, 0x00, 0x00, 0x60, 0x00, 0x00, /* mov r3=ip */
|
||||
0x00, 0x00, 0x04, 0x00, /* nop.i 0x0 */
|
||||
0x05, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MLX] nop.m 0x0 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* nop.x 0x0;; */
|
||||
0x00, 0x00, 0x04, 0x00
|
||||
};
|
||||
|
||||
static unsigned char *ftrace_nop_replace(void)
|
||||
{
|
||||
return ftrace_nop_code;
|
||||
}
|
||||
|
||||
/*
|
||||
* mcount stub will be converted below for call
|
||||
* Note: Just the last instruction is changed against nop
|
||||
* */
|
||||
static unsigned char __attribute__((aligned(8)))
|
||||
ftrace_call_code[MCOUNT_INSN_SIZE] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MII] nop.m 0x0 */
|
||||
0x30, 0x00, 0x00, 0x60, 0x00, 0x00, /* mov r3=ip */
|
||||
0x00, 0x00, 0x04, 0x00, /* nop.i 0x0 */
|
||||
0x05, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MLX] nop.m 0x0 */
|
||||
0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, /* brl.many .;;*/
|
||||
0xf8, 0xff, 0xff, 0xc8
|
||||
};
|
||||
|
||||
struct ftrace_call_insn {
|
||||
u64 dummy1, dummy2;
|
||||
u64 dummy3:48;
|
||||
u64 imm39_l:16;
|
||||
u64 imm39_h:23;
|
||||
u64 dummy4:13;
|
||||
u64 imm20:20;
|
||||
u64 dummy5:3;
|
||||
u64 i:1;
|
||||
u64 dummy6:4;
|
||||
};
|
||||
|
||||
static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
|
||||
{
|
||||
struct ftrace_call_insn *code = (void *)ftrace_call_code;
|
||||
unsigned long offset = addr - (ip + 0x10);
|
||||
|
||||
code->imm39_l = offset >> 24;
|
||||
code->imm39_h = offset >> 40;
|
||||
code->imm20 = offset >> 4;
|
||||
code->i = offset >> 63;
|
||||
return ftrace_call_code;
|
||||
}
|
||||
|
||||
static int
|
||||
ftrace_modify_code(unsigned long ip, unsigned char *old_code,
|
||||
unsigned char *new_code, int do_check)
|
||||
{
|
||||
unsigned char replaced[MCOUNT_INSN_SIZE];
|
||||
|
||||
/*
|
||||
* Note: Due to modules and __init, code can
|
||||
* disappear and change, we need to protect against faulting
|
||||
* as well as code changing. We do this by using the
|
||||
* probe_kernel_* functions.
|
||||
*
|
||||
* No real locking needed, this code is run through
|
||||
* kstop_machine, or before SMP starts.
|
||||
*/
|
||||
|
||||
if (!do_check)
|
||||
goto skip_check;
|
||||
|
||||
/* read the text we want to modify */
|
||||
if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
|
||||
return -EFAULT;
|
||||
|
||||
/* Make sure it is what we expect it to be */
|
||||
if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
skip_check:
|
||||
/* replace the text with the new text */
|
||||
if (probe_kernel_write(((void *)ip), new_code, MCOUNT_INSN_SIZE))
|
||||
return -EPERM;
|
||||
flush_icache_range(ip, ip + MCOUNT_INSN_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ftrace_make_nop_check(struct dyn_ftrace *rec, unsigned long addr)
|
||||
{
|
||||
unsigned char __attribute__((aligned(8))) replaced[MCOUNT_INSN_SIZE];
|
||||
unsigned long ip = rec->ip;
|
||||
|
||||
if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
|
||||
return -EFAULT;
|
||||
if (rec->flags & FTRACE_FL_CONVERTED) {
|
||||
struct ftrace_call_insn *call_insn, *tmp_call;
|
||||
|
||||
call_insn = (void *)ftrace_call_code;
|
||||
tmp_call = (void *)replaced;
|
||||
call_insn->imm39_l = tmp_call->imm39_l;
|
||||
call_insn->imm39_h = tmp_call->imm39_h;
|
||||
call_insn->imm20 = tmp_call->imm20;
|
||||
call_insn->i = tmp_call->i;
|
||||
if (memcmp(replaced, ftrace_call_code, MCOUNT_INSN_SIZE) != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
} else {
|
||||
struct ftrace_orig_insn *call_insn, *tmp_call;
|
||||
|
||||
call_insn = (void *)ftrace_orig_code;
|
||||
tmp_call = (void *)replaced;
|
||||
call_insn->sign = tmp_call->sign;
|
||||
call_insn->imm20 = tmp_call->imm20;
|
||||
if (memcmp(replaced, ftrace_orig_code, MCOUNT_INSN_SIZE) != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int ftrace_make_nop(struct module *mod,
|
||||
struct dyn_ftrace *rec, unsigned long addr)
|
||||
{
|
||||
int ret;
|
||||
char *new;
|
||||
|
||||
ret = ftrace_make_nop_check(rec, addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
new = ftrace_nop_replace();
|
||||
return ftrace_modify_code(rec->ip, NULL, new, 0);
|
||||
}
|
||||
|
||||
int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
|
||||
{
|
||||
unsigned long ip = rec->ip;
|
||||
unsigned char *old, *new;
|
||||
|
||||
old= ftrace_nop_replace();
|
||||
new = ftrace_call_replace(ip, addr);
|
||||
return ftrace_modify_code(ip, old, new, 1);
|
||||
}
|
||||
|
||||
/* in IA64, _mcount can't directly call ftrace_stub. Only jump is ok */
|
||||
int ftrace_update_ftrace_func(ftrace_func_t func)
|
||||
{
|
||||
unsigned long ip;
|
||||
unsigned long addr = ((struct fnptr *)ftrace_call)->ip;
|
||||
|
||||
if (func == ftrace_stub)
|
||||
return 0;
|
||||
ip = ((struct fnptr *)func)->ip;
|
||||
|
||||
ia64_patch_imm64(addr + 2, ip);
|
||||
|
||||
flush_icache_range(addr, addr + 16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* run from kstop_machine */
|
||||
int __init ftrace_dyn_arch_init(void *data)
|
||||
{
|
||||
*(unsigned long *)data = 0;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -112,3 +112,9 @@ EXPORT_SYMBOL_GPL(esi_call_phys);
|
|||
#endif
|
||||
extern char ia64_ivt[];
|
||||
EXPORT_SYMBOL(ia64_ivt);
|
||||
|
||||
#include <asm/ftrace.h>
|
||||
#ifdef CONFIG_FUNCTION_TRACER
|
||||
/* mcount is defined in assembly */
|
||||
EXPORT_SYMBOL(_mcount);
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/* empty */
|
|
@ -0,0 +1 @@
|
|||
/* empty */
|
|
@ -0,0 +1 @@
|
|||
/* empty */
|
|
@ -0,0 +1 @@
|
|||
/* empty */
|
|
@ -34,6 +34,8 @@ config X86
|
|||
select HAVE_FUNCTION_TRACER
|
||||
select HAVE_FUNCTION_GRAPH_TRACER
|
||||
select HAVE_FUNCTION_TRACE_MCOUNT_TEST
|
||||
select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE
|
||||
select HAVE_FTRACE_SYSCALLS
|
||||
select HAVE_KVM
|
||||
select HAVE_ARCH_KGDB
|
||||
select HAVE_ARCH_TRACEHOOK
|
||||
|
|
|
@ -126,6 +126,11 @@ void clflush_cache_range(void *addr, unsigned int size);
|
|||
#ifdef CONFIG_DEBUG_RODATA
|
||||
void mark_rodata_ro(void);
|
||||
extern const int rodata_test_data;
|
||||
void set_kernel_text_rw(void);
|
||||
void set_kernel_text_ro(void);
|
||||
#else
|
||||
static inline void set_kernel_text_rw(void) { }
|
||||
static inline void set_kernel_text_ro(void) { }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_RODATA_TEST
|
||||
|
|
|
@ -111,6 +111,8 @@ enum fixed_addresses {
|
|||
#ifdef CONFIG_PARAVIRT
|
||||
FIX_PARAVIRT_BOOTMAP,
|
||||
#endif
|
||||
FIX_TEXT_POKE0, /* reserve 2 pages for text_poke() */
|
||||
FIX_TEXT_POKE1,
|
||||
__end_of_permanent_fixed_addresses,
|
||||
#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
|
||||
FIX_OHCI1394_BASE,
|
||||
|
|
|
@ -28,6 +28,13 @@
|
|||
|
||||
#endif
|
||||
|
||||
/* FIXME: I don't want to stay hardcoded */
|
||||
#ifdef CONFIG_X86_64
|
||||
# define FTRACE_SYSCALL_MAX 296
|
||||
#else
|
||||
# define FTRACE_SYSCALL_MAX 333
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FUNCTION_TRACER
|
||||
#define MCOUNT_ADDR ((long)(mcount))
|
||||
#define MCOUNT_INSN_SIZE 5 /* sizeof mcount call */
|
||||
|
|
|
@ -80,8 +80,6 @@
|
|||
|
||||
#define PTRACE_SINGLEBLOCK 33 /* resume execution until next branch */
|
||||
|
||||
#ifdef CONFIG_X86_PTRACE_BTS
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <linux/types.h>
|
||||
|
||||
|
@ -140,6 +138,5 @@ struct ptrace_bts_config {
|
|||
BTS records are read from oldest to newest.
|
||||
Returns number of BTS records drained.
|
||||
*/
|
||||
#endif /* CONFIG_X86_PTRACE_BTS */
|
||||
|
||||
#endif /* _ASM_X86_PTRACE_ABI_H */
|
||||
|
|
|
@ -94,6 +94,7 @@ struct thread_info {
|
|||
#define TIF_FORCED_TF 24 /* true if TF in eflags artificially */
|
||||
#define TIF_DEBUGCTLMSR 25 /* uses thread_struct.debugctlmsr */
|
||||
#define TIF_DS_AREA_MSR 26 /* uses thread_struct.ds_area_msr */
|
||||
#define TIF_SYSCALL_FTRACE 27 /* for ftrace syscall instrumentation */
|
||||
|
||||
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
|
||||
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
|
||||
|
@ -115,15 +116,17 @@ struct thread_info {
|
|||
#define _TIF_FORCED_TF (1 << TIF_FORCED_TF)
|
||||
#define _TIF_DEBUGCTLMSR (1 << TIF_DEBUGCTLMSR)
|
||||
#define _TIF_DS_AREA_MSR (1 << TIF_DS_AREA_MSR)
|
||||
#define _TIF_SYSCALL_FTRACE (1 << TIF_SYSCALL_FTRACE)
|
||||
|
||||
/* work to do in syscall_trace_enter() */
|
||||
#define _TIF_WORK_SYSCALL_ENTRY \
|
||||
(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU | \
|
||||
(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU | _TIF_SYSCALL_FTRACE | \
|
||||
_TIF_SYSCALL_AUDIT | _TIF_SECCOMP | _TIF_SINGLESTEP)
|
||||
|
||||
/* work to do in syscall_trace_leave() */
|
||||
#define _TIF_WORK_SYSCALL_EXIT \
|
||||
(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP)
|
||||
(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP | \
|
||||
_TIF_SYSCALL_FTRACE)
|
||||
|
||||
/* work to do on interrupt/exception return */
|
||||
#define _TIF_WORK_MASK \
|
||||
|
@ -132,7 +135,7 @@ struct thread_info {
|
|||
_TIF_SINGLESTEP|_TIF_SECCOMP|_TIF_SYSCALL_EMU))
|
||||
|
||||
/* work to do on any return to user space */
|
||||
#define _TIF_ALLWORK_MASK (0x0000FFFF & ~_TIF_SECCOMP)
|
||||
#define _TIF_ALLWORK_MASK ((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_FTRACE)
|
||||
|
||||
/* Only used for 64 bit */
|
||||
#define _TIF_DO_NOTIFY_MASK \
|
||||
|
|
|
@ -66,7 +66,8 @@ obj-$(CONFIG_X86_MPPARSE) += mpparse.o
|
|||
obj-y += apic/
|
||||
obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o
|
||||
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
|
||||
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
|
||||
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
|
||||
obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o
|
||||
obj-$(CONFIG_KEXEC) += machine_kexec_$(BITS).o
|
||||
obj-$(CONFIG_KEXEC) += relocate_kernel_$(BITS).o crash.o
|
||||
obj-$(CONFIG_CRASH_DUMP) += crash_dump_$(BITS).o
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <linux/kprobes.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/memory.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
@ -12,7 +13,9 @@
|
|||
#include <asm/nmi.h>
|
||||
#include <asm/vsyscall.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/fixmap.h>
|
||||
|
||||
#define MAX_PATCH_LEN (255-1)
|
||||
|
||||
|
@ -226,6 +229,7 @@ static void alternatives_smp_lock(u8 **start, u8 **end, u8 *text, u8 *text_end)
|
|||
{
|
||||
u8 **ptr;
|
||||
|
||||
mutex_lock(&text_mutex);
|
||||
for (ptr = start; ptr < end; ptr++) {
|
||||
if (*ptr < text)
|
||||
continue;
|
||||
|
@ -234,6 +238,7 @@ static void alternatives_smp_lock(u8 **start, u8 **end, u8 *text, u8 *text_end)
|
|||
/* turn DS segment override prefix into lock prefix */
|
||||
text_poke(*ptr, ((unsigned char []){0xf0}), 1);
|
||||
};
|
||||
mutex_unlock(&text_mutex);
|
||||
}
|
||||
|
||||
static void alternatives_smp_unlock(u8 **start, u8 **end, u8 *text, u8 *text_end)
|
||||
|
@ -243,6 +248,7 @@ static void alternatives_smp_unlock(u8 **start, u8 **end, u8 *text, u8 *text_end
|
|||
if (noreplace_smp)
|
||||
return;
|
||||
|
||||
mutex_lock(&text_mutex);
|
||||
for (ptr = start; ptr < end; ptr++) {
|
||||
if (*ptr < text)
|
||||
continue;
|
||||
|
@ -251,6 +257,7 @@ static void alternatives_smp_unlock(u8 **start, u8 **end, u8 *text, u8 *text_end
|
|||
/* turn lock prefix into DS segment override prefix */
|
||||
text_poke(*ptr, ((unsigned char []){0x3E}), 1);
|
||||
};
|
||||
mutex_unlock(&text_mutex);
|
||||
}
|
||||
|
||||
struct smp_alt_module {
|
||||
|
@ -500,15 +507,16 @@ void *text_poke_early(void *addr, const void *opcode, size_t len)
|
|||
* It means the size must be writable atomically and the address must be aligned
|
||||
* in a way that permits an atomic write. It also makes sure we fit on a single
|
||||
* page.
|
||||
*
|
||||
* Note: Must be called under text_mutex.
|
||||
*/
|
||||
void *__kprobes text_poke(void *addr, const void *opcode, size_t len)
|
||||
{
|
||||
unsigned long flags;
|
||||
char *vaddr;
|
||||
int nr_pages = 2;
|
||||
struct page *pages[2];
|
||||
int i;
|
||||
|
||||
might_sleep();
|
||||
if (!core_kernel_text((unsigned long)addr)) {
|
||||
pages[0] = vmalloc_to_page(addr);
|
||||
pages[1] = vmalloc_to_page(addr + PAGE_SIZE);
|
||||
|
@ -518,18 +526,21 @@ void *__kprobes text_poke(void *addr, const void *opcode, size_t len)
|
|||
pages[1] = virt_to_page(addr + PAGE_SIZE);
|
||||
}
|
||||
BUG_ON(!pages[0]);
|
||||
if (!pages[1])
|
||||
nr_pages = 1;
|
||||
vaddr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL);
|
||||
BUG_ON(!vaddr);
|
||||
local_irq_disable();
|
||||
local_irq_save(flags);
|
||||
set_fixmap(FIX_TEXT_POKE0, page_to_phys(pages[0]));
|
||||
if (pages[1])
|
||||
set_fixmap(FIX_TEXT_POKE1, page_to_phys(pages[1]));
|
||||
vaddr = (char *)fix_to_virt(FIX_TEXT_POKE0);
|
||||
memcpy(&vaddr[(unsigned long)addr & ~PAGE_MASK], opcode, len);
|
||||
local_irq_enable();
|
||||
vunmap(vaddr);
|
||||
clear_fixmap(FIX_TEXT_POKE0);
|
||||
if (pages[1])
|
||||
clear_fixmap(FIX_TEXT_POKE1);
|
||||
local_flush_tlb();
|
||||
sync_core();
|
||||
/* Could also do a CLFLUSH here to speed up CPU recovery; but
|
||||
that causes hangs on some VIA CPUs. */
|
||||
for (i = 0; i < len; i++)
|
||||
BUG_ON(((char *)addr)[i] != ((char *)opcode)[i]);
|
||||
local_irq_restore(flags);
|
||||
return addr;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#include <linux/cpufreq.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include <trace/power.h>
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/io.h>
|
||||
|
@ -72,6 +72,8 @@ struct acpi_cpufreq_data {
|
|||
|
||||
static DEFINE_PER_CPU(struct acpi_cpufreq_data *, drv_data);
|
||||
|
||||
DEFINE_TRACE(power_mark);
|
||||
|
||||
/* acpi_perf_data is a pointer to percpu data. */
|
||||
static struct acpi_processor_performance *acpi_perf_data;
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/bug.h>
|
||||
#include <linux/nmi.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/ftrace.h>
|
||||
|
||||
#include <asm/stacktrace.h>
|
||||
|
||||
|
@ -196,6 +197,11 @@ unsigned __kprobes long oops_begin(void)
|
|||
int cpu;
|
||||
unsigned long flags;
|
||||
|
||||
/* notify the hw-branch tracer so it may disable tracing and
|
||||
add the last trace to the trace buffer -
|
||||
the earlier this happens, the more useful the trace. */
|
||||
trace_hw_branch_oops();
|
||||
|
||||
oops_enter();
|
||||
|
||||
/* racy, but better than risking deadlock. */
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/ftrace.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include <asm/nops.h>
|
||||
|
@ -26,6 +27,18 @@
|
|||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
|
||||
int ftrace_arch_code_modify_prepare(void)
|
||||
{
|
||||
set_kernel_text_rw();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ftrace_arch_code_modify_post_process(void)
|
||||
{
|
||||
set_kernel_text_ro();
|
||||
return 0;
|
||||
}
|
||||
|
||||
union ftrace_code_union {
|
||||
char code[MCOUNT_INSN_SIZE];
|
||||
struct {
|
||||
|
@ -66,11 +79,11 @@ static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
|
|||
*
|
||||
* 1) Put the instruction pointer into the IP buffer
|
||||
* and the new code into the "code" buffer.
|
||||
* 2) Set a flag that says we are modifying code
|
||||
* 3) Wait for any running NMIs to finish.
|
||||
* 4) Write the code
|
||||
* 5) clear the flag.
|
||||
* 6) Wait for any running NMIs to finish.
|
||||
* 2) Wait for any running NMIs to finish and set a flag that says
|
||||
* we are modifying code, it is done in an atomic operation.
|
||||
* 3) Write the code
|
||||
* 4) clear the flag.
|
||||
* 5) Wait for any running NMIs to finish.
|
||||
*
|
||||
* If an NMI is executed, the first thing it does is to call
|
||||
* "ftrace_nmi_enter". This will check if the flag is set to write
|
||||
|
@ -82,9 +95,9 @@ static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
|
|||
* are the same as what exists.
|
||||
*/
|
||||
|
||||
static atomic_t in_nmi = ATOMIC_INIT(0);
|
||||
#define MOD_CODE_WRITE_FLAG (1 << 31) /* set when NMI should do the write */
|
||||
static atomic_t nmi_running = ATOMIC_INIT(0);
|
||||
static int mod_code_status; /* holds return value of text write */
|
||||
static int mod_code_write; /* set when NMI should do the write */
|
||||
static void *mod_code_ip; /* holds the IP to write to */
|
||||
static void *mod_code_newcode; /* holds the text to write to the IP */
|
||||
|
||||
|
@ -101,6 +114,20 @@ int ftrace_arch_read_dyn_info(char *buf, int size)
|
|||
return r;
|
||||
}
|
||||
|
||||
static void clear_mod_flag(void)
|
||||
{
|
||||
int old = atomic_read(&nmi_running);
|
||||
|
||||
for (;;) {
|
||||
int new = old & ~MOD_CODE_WRITE_FLAG;
|
||||
|
||||
if (old == new)
|
||||
break;
|
||||
|
||||
old = atomic_cmpxchg(&nmi_running, old, new);
|
||||
}
|
||||
}
|
||||
|
||||
static void ftrace_mod_code(void)
|
||||
{
|
||||
/*
|
||||
|
@ -111,37 +138,52 @@ static void ftrace_mod_code(void)
|
|||
*/
|
||||
mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode,
|
||||
MCOUNT_INSN_SIZE);
|
||||
|
||||
/* if we fail, then kill any new writers */
|
||||
if (mod_code_status)
|
||||
clear_mod_flag();
|
||||
}
|
||||
|
||||
void ftrace_nmi_enter(void)
|
||||
{
|
||||
atomic_inc(&in_nmi);
|
||||
/* Must have in_nmi seen before reading write flag */
|
||||
smp_mb();
|
||||
if (mod_code_write) {
|
||||
if (atomic_inc_return(&nmi_running) & MOD_CODE_WRITE_FLAG) {
|
||||
smp_rmb();
|
||||
ftrace_mod_code();
|
||||
atomic_inc(&nmi_update_count);
|
||||
}
|
||||
/* Must have previous changes seen before executions */
|
||||
smp_mb();
|
||||
}
|
||||
|
||||
void ftrace_nmi_exit(void)
|
||||
{
|
||||
/* Finish all executions before clearing in_nmi */
|
||||
smp_wmb();
|
||||
atomic_dec(&in_nmi);
|
||||
/* Finish all executions before clearing nmi_running */
|
||||
smp_mb();
|
||||
atomic_dec(&nmi_running);
|
||||
}
|
||||
|
||||
static void wait_for_nmi_and_set_mod_flag(void)
|
||||
{
|
||||
if (!atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG))
|
||||
return;
|
||||
|
||||
do {
|
||||
cpu_relax();
|
||||
} while (atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG));
|
||||
|
||||
nmi_wait_count++;
|
||||
}
|
||||
|
||||
static void wait_for_nmi(void)
|
||||
{
|
||||
int waited = 0;
|
||||
if (!atomic_read(&nmi_running))
|
||||
return;
|
||||
|
||||
while (atomic_read(&in_nmi)) {
|
||||
waited = 1;
|
||||
do {
|
||||
cpu_relax();
|
||||
}
|
||||
} while (atomic_read(&nmi_running));
|
||||
|
||||
if (waited)
|
||||
nmi_wait_count++;
|
||||
nmi_wait_count++;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -151,14 +193,9 @@ do_ftrace_mod_code(unsigned long ip, void *new_code)
|
|||
mod_code_newcode = new_code;
|
||||
|
||||
/* The buffers need to be visible before we let NMIs write them */
|
||||
smp_wmb();
|
||||
|
||||
mod_code_write = 1;
|
||||
|
||||
/* Make sure write bit is visible before we wait on NMIs */
|
||||
smp_mb();
|
||||
|
||||
wait_for_nmi();
|
||||
wait_for_nmi_and_set_mod_flag();
|
||||
|
||||
/* Make sure all running NMIs have finished before we write the code */
|
||||
smp_mb();
|
||||
|
@ -166,13 +203,9 @@ do_ftrace_mod_code(unsigned long ip, void *new_code)
|
|||
ftrace_mod_code();
|
||||
|
||||
/* Make sure the write happens before clearing the bit */
|
||||
smp_wmb();
|
||||
|
||||
mod_code_write = 0;
|
||||
|
||||
/* make sure NMIs see the cleared bit */
|
||||
smp_mb();
|
||||
|
||||
clear_mod_flag();
|
||||
wait_for_nmi();
|
||||
|
||||
return mod_code_status;
|
||||
|
@ -368,25 +401,6 @@ int ftrace_disable_ftrace_graph_caller(void)
|
|||
return ftrace_mod_jmp(ip, old_offset, new_offset);
|
||||
}
|
||||
|
||||
#else /* CONFIG_DYNAMIC_FTRACE */
|
||||
|
||||
/*
|
||||
* These functions are picked from those used on
|
||||
* this page for dynamic ftrace. They have been
|
||||
* simplified to ignore all traces in NMI context.
|
||||
*/
|
||||
static atomic_t in_nmi;
|
||||
|
||||
void ftrace_nmi_enter(void)
|
||||
{
|
||||
atomic_inc(&in_nmi);
|
||||
}
|
||||
|
||||
void ftrace_nmi_exit(void)
|
||||
{
|
||||
atomic_dec(&in_nmi);
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_DYNAMIC_FTRACE */
|
||||
|
||||
/*
|
||||
|
@ -396,14 +410,13 @@ void ftrace_nmi_exit(void)
|
|||
void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
|
||||
{
|
||||
unsigned long old;
|
||||
unsigned long long calltime;
|
||||
int faulted;
|
||||
struct ftrace_graph_ent trace;
|
||||
unsigned long return_hooker = (unsigned long)
|
||||
&return_to_handler;
|
||||
|
||||
/* Nmi's are currently unsupported */
|
||||
if (unlikely(atomic_read(&in_nmi)))
|
||||
if (unlikely(in_nmi()))
|
||||
return;
|
||||
|
||||
if (unlikely(atomic_read(¤t->tracing_graph_pause)))
|
||||
|
@ -439,17 +452,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
|
|||
return;
|
||||
}
|
||||
|
||||
if (unlikely(!__kernel_text_address(old))) {
|
||||
ftrace_graph_stop();
|
||||
*parent = old;
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
|
||||
calltime = cpu_clock(raw_smp_processor_id());
|
||||
|
||||
if (ftrace_push_return_trace(old, calltime,
|
||||
self_addr, &trace.depth) == -EBUSY) {
|
||||
if (ftrace_push_return_trace(old, self_addr, &trace.depth) == -EBUSY) {
|
||||
*parent = old;
|
||||
return;
|
||||
}
|
||||
|
@ -463,3 +466,66 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
|
|||
}
|
||||
}
|
||||
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
|
||||
|
||||
#ifdef CONFIG_FTRACE_SYSCALLS
|
||||
|
||||
extern unsigned long __start_syscalls_metadata[];
|
||||
extern unsigned long __stop_syscalls_metadata[];
|
||||
extern unsigned long *sys_call_table;
|
||||
|
||||
static struct syscall_metadata **syscalls_metadata;
|
||||
|
||||
static struct syscall_metadata *find_syscall_meta(unsigned long *syscall)
|
||||
{
|
||||
struct syscall_metadata *start;
|
||||
struct syscall_metadata *stop;
|
||||
char str[KSYM_SYMBOL_LEN];
|
||||
|
||||
|
||||
start = (struct syscall_metadata *)__start_syscalls_metadata;
|
||||
stop = (struct syscall_metadata *)__stop_syscalls_metadata;
|
||||
kallsyms_lookup((unsigned long) syscall, NULL, NULL, NULL, str);
|
||||
|
||||
for ( ; start < stop; start++) {
|
||||
if (start->name && !strcmp(start->name, str))
|
||||
return start;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct syscall_metadata *syscall_nr_to_meta(int nr)
|
||||
{
|
||||
if (!syscalls_metadata || nr >= FTRACE_SYSCALL_MAX || nr < 0)
|
||||
return NULL;
|
||||
|
||||
return syscalls_metadata[nr];
|
||||
}
|
||||
|
||||
void arch_init_ftrace_syscalls(void)
|
||||
{
|
||||
int i;
|
||||
struct syscall_metadata *meta;
|
||||
unsigned long **psys_syscall_table = &sys_call_table;
|
||||
static atomic_t refs;
|
||||
|
||||
if (atomic_inc_return(&refs) != 1)
|
||||
goto end;
|
||||
|
||||
syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) *
|
||||
FTRACE_SYSCALL_MAX, GFP_KERNEL);
|
||||
if (!syscalls_metadata) {
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < FTRACE_SYSCALL_MAX; i++) {
|
||||
meta = find_syscall_meta(psys_syscall_table[i]);
|
||||
syscalls_metadata[i] = meta;
|
||||
}
|
||||
return;
|
||||
|
||||
/* Paranoid: avoid overflow */
|
||||
end:
|
||||
atomic_dec(&refs);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -638,13 +638,13 @@ static void __used __kprobes kretprobe_trampoline_holder(void)
|
|||
#else
|
||||
" pushf\n"
|
||||
/*
|
||||
* Skip cs, ip, orig_ax.
|
||||
* Skip cs, ip, orig_ax and gs.
|
||||
* trampoline_handler() will plug in these values
|
||||
*/
|
||||
" subl $12, %esp\n"
|
||||
" subl $16, %esp\n"
|
||||
" pushl %fs\n"
|
||||
" pushl %ds\n"
|
||||
" pushl %es\n"
|
||||
" pushl %ds\n"
|
||||
" pushl %eax\n"
|
||||
" pushl %ebp\n"
|
||||
" pushl %edi\n"
|
||||
|
@ -655,10 +655,10 @@ static void __used __kprobes kretprobe_trampoline_holder(void)
|
|||
" movl %esp, %eax\n"
|
||||
" call trampoline_handler\n"
|
||||
/* Move flags to cs */
|
||||
" movl 52(%esp), %edx\n"
|
||||
" movl %edx, 48(%esp)\n"
|
||||
" movl 56(%esp), %edx\n"
|
||||
" movl %edx, 52(%esp)\n"
|
||||
/* Replace saved flags with true return address. */
|
||||
" movl %eax, 52(%esp)\n"
|
||||
" movl %eax, 56(%esp)\n"
|
||||
" popl %ebx\n"
|
||||
" popl %ecx\n"
|
||||
" popl %edx\n"
|
||||
|
@ -666,8 +666,8 @@ static void __used __kprobes kretprobe_trampoline_holder(void)
|
|||
" popl %edi\n"
|
||||
" popl %ebp\n"
|
||||
" popl %eax\n"
|
||||
/* Skip ip, orig_ax, es, ds, fs */
|
||||
" addl $20, %esp\n"
|
||||
/* Skip ds, es, fs, gs, orig_ax and ip */
|
||||
" addl $24, %esp\n"
|
||||
" popf\n"
|
||||
#endif
|
||||
" ret\n");
|
||||
|
@ -691,6 +691,7 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs)
|
|||
regs->cs = __KERNEL_CS;
|
||||
#else
|
||||
regs->cs = __KERNEL_CS | get_kernel_rpl();
|
||||
regs->gs = 0;
|
||||
#endif
|
||||
regs->ip = trampoline_address;
|
||||
regs->orig_ax = ~0UL;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include <trace/power.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/idle.h>
|
||||
|
@ -22,6 +22,9 @@ EXPORT_SYMBOL(idle_nomwait);
|
|||
|
||||
struct kmem_cache *task_xstate_cachep;
|
||||
|
||||
DEFINE_TRACE(power_start);
|
||||
DEFINE_TRACE(power_end);
|
||||
|
||||
int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
|
||||
{
|
||||
*dst = *src;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/audit.h>
|
||||
#include <linux/seccomp.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/ftrace.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
@ -1415,6 +1416,9 @@ asmregparm long syscall_trace_enter(struct pt_regs *regs)
|
|||
tracehook_report_syscall_entry(regs))
|
||||
ret = -1L;
|
||||
|
||||
if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE)))
|
||||
ftrace_syscall_enter(regs);
|
||||
|
||||
if (unlikely(current->audit_context)) {
|
||||
if (IS_IA32)
|
||||
audit_syscall_entry(AUDIT_ARCH_I386,
|
||||
|
@ -1438,6 +1442,9 @@ asmregparm void syscall_trace_leave(struct pt_regs *regs)
|
|||
if (unlikely(current->audit_context))
|
||||
audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
|
||||
|
||||
if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE)))
|
||||
ftrace_syscall_exit(regs);
|
||||
|
||||
if (test_thread_flag(TIF_SYSCALL_TRACE))
|
||||
tracehook_report_syscall_exit(regs, 0);
|
||||
|
||||
|
|
|
@ -59,7 +59,8 @@ config KVM_AMD
|
|||
|
||||
config KVM_TRACE
|
||||
bool "KVM trace support"
|
||||
depends on KVM && MARKERS && SYSFS
|
||||
depends on KVM && SYSFS
|
||||
select MARKERS
|
||||
select RELAY
|
||||
select DEBUG_FS
|
||||
default n
|
||||
|
|
|
@ -1054,17 +1054,47 @@ static noinline int do_test_wp_bit(void)
|
|||
const int rodata_test_data = 0xC3;
|
||||
EXPORT_SYMBOL_GPL(rodata_test_data);
|
||||
|
||||
static int kernel_set_to_readonly;
|
||||
|
||||
void set_kernel_text_rw(void)
|
||||
{
|
||||
unsigned long start = PFN_ALIGN(_text);
|
||||
unsigned long size = PFN_ALIGN(_etext) - start;
|
||||
|
||||
if (!kernel_set_to_readonly)
|
||||
return;
|
||||
|
||||
pr_debug("Set kernel text: %lx - %lx for read write\n",
|
||||
start, start+size);
|
||||
|
||||
set_pages_rw(virt_to_page(start), size >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
void set_kernel_text_ro(void)
|
||||
{
|
||||
unsigned long start = PFN_ALIGN(_text);
|
||||
unsigned long size = PFN_ALIGN(_etext) - start;
|
||||
|
||||
if (!kernel_set_to_readonly)
|
||||
return;
|
||||
|
||||
pr_debug("Set kernel text: %lx - %lx for read only\n",
|
||||
start, start+size);
|
||||
|
||||
set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
void mark_rodata_ro(void)
|
||||
{
|
||||
unsigned long start = PFN_ALIGN(_text);
|
||||
unsigned long size = PFN_ALIGN(_etext) - start;
|
||||
|
||||
#ifndef CONFIG_DYNAMIC_FTRACE
|
||||
/* Dynamic tracing modifies the kernel text section */
|
||||
set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT);
|
||||
printk(KERN_INFO "Write protecting the kernel text: %luk\n",
|
||||
size >> 10);
|
||||
|
||||
kernel_set_to_readonly = 1;
|
||||
|
||||
#ifdef CONFIG_CPA_DEBUG
|
||||
printk(KERN_INFO "Testing CPA: Reverting %lx-%lx\n",
|
||||
start, start+size);
|
||||
|
@ -1073,7 +1103,6 @@ void mark_rodata_ro(void)
|
|||
printk(KERN_INFO "Testing CPA: write protecting again\n");
|
||||
set_pages_ro(virt_to_page(start), size>>PAGE_SHIFT);
|
||||
#endif
|
||||
#endif /* CONFIG_DYNAMIC_FTRACE */
|
||||
|
||||
start += size;
|
||||
size = (unsigned long)__end_rodata - start;
|
||||
|
|
|
@ -734,21 +734,48 @@ void __init mem_init(void)
|
|||
const int rodata_test_data = 0xC3;
|
||||
EXPORT_SYMBOL_GPL(rodata_test_data);
|
||||
|
||||
static int kernel_set_to_readonly;
|
||||
|
||||
void set_kernel_text_rw(void)
|
||||
{
|
||||
unsigned long start = PFN_ALIGN(_stext);
|
||||
unsigned long end = PFN_ALIGN(__start_rodata);
|
||||
|
||||
if (!kernel_set_to_readonly)
|
||||
return;
|
||||
|
||||
pr_debug("Set kernel text: %lx - %lx for read write\n",
|
||||
start, end);
|
||||
|
||||
set_memory_rw(start, (end - start) >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
void set_kernel_text_ro(void)
|
||||
{
|
||||
unsigned long start = PFN_ALIGN(_stext);
|
||||
unsigned long end = PFN_ALIGN(__start_rodata);
|
||||
|
||||
if (!kernel_set_to_readonly)
|
||||
return;
|
||||
|
||||
pr_debug("Set kernel text: %lx - %lx for read only\n",
|
||||
start, end);
|
||||
|
||||
set_memory_ro(start, (end - start) >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
void mark_rodata_ro(void)
|
||||
{
|
||||
unsigned long start = PFN_ALIGN(_stext), end = PFN_ALIGN(__end_rodata);
|
||||
unsigned long rodata_start =
|
||||
((unsigned long)__start_rodata + PAGE_SIZE - 1) & PAGE_MASK;
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
/* Dynamic tracing modifies the kernel text section */
|
||||
start = rodata_start;
|
||||
#endif
|
||||
|
||||
printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n",
|
||||
(end - start) >> 10);
|
||||
set_memory_ro(start, (end - start) >> PAGE_SHIFT);
|
||||
|
||||
kernel_set_to_readonly = 1;
|
||||
|
||||
/*
|
||||
* The rodata section (but not the kernel text!) should also be
|
||||
* not-executable.
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/* empty */
|
|
@ -44,22 +44,6 @@ config LBD
|
|||
|
||||
If unsure, say N.
|
||||
|
||||
config BLK_DEV_IO_TRACE
|
||||
bool "Support for tracing block io actions"
|
||||
depends on SYSFS
|
||||
select RELAY
|
||||
select DEBUG_FS
|
||||
select TRACEPOINTS
|
||||
help
|
||||
Say Y here if you want to be able to trace the block layer actions
|
||||
on a given queue. Tracing allows you to see any traffic happening
|
||||
on a block device queue. For more information (and the userspace
|
||||
support tools needed), fetch the blktrace tools from:
|
||||
|
||||
git://git.kernel.dk/blktrace.git
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config BLK_DEV_BSG
|
||||
bool "Block layer SG support v4 (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL
|
||||
|
|
|
@ -13,6 +13,5 @@ obj-$(CONFIG_IOSCHED_AS) += as-iosched.o
|
|||
obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o
|
||||
obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o
|
||||
|
||||
obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o
|
||||
obj-$(CONFIG_BLOCK_COMPAT) += compat_ioctl.o
|
||||
obj-$(CONFIG_BLK_DEV_INTEGRITY) += blk-integrity.o
|
||||
|
|
|
@ -283,7 +283,7 @@ static void sysrq_ftrace_dump(int key, struct tty_struct *tty)
|
|||
}
|
||||
static struct sysrq_key_op sysrq_ftrace_dump_op = {
|
||||
.handler = sysrq_ftrace_dump,
|
||||
.help_msg = "dumpZ-ftrace-buffer",
|
||||
.help_msg = "dump-ftrace-buffer(Z)",
|
||||
.action_msg = "Dump ftrace buffer",
|
||||
.enable_mask = SYSRQ_ENABLE_DUMP,
|
||||
};
|
||||
|
|
|
@ -161,7 +161,7 @@ struct op_sample
|
|||
{
|
||||
entry->event = ring_buffer_lock_reserve
|
||||
(op_ring_buffer_write, sizeof(struct op_sample) +
|
||||
size * sizeof(entry->sample->data[0]), &entry->irq_flags);
|
||||
size * sizeof(entry->sample->data[0]));
|
||||
if (entry->event)
|
||||
entry->sample = ring_buffer_event_data(entry->event);
|
||||
else
|
||||
|
@ -178,8 +178,7 @@ struct op_sample
|
|||
|
||||
int op_cpu_buffer_write_commit(struct op_entry *entry)
|
||||
{
|
||||
return ring_buffer_unlock_commit(op_ring_buffer_write, entry->event,
|
||||
entry->irq_flags);
|
||||
return ring_buffer_unlock_commit(op_ring_buffer_write, entry->event);
|
||||
}
|
||||
|
||||
struct op_sample *op_cpu_buffer_read_entry(struct op_entry *entry, int cpu)
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
static struct vfsmount *debugfs_mount;
|
||||
static int debugfs_mount_count;
|
||||
static bool debugfs_registered;
|
||||
|
||||
static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t dev)
|
||||
{
|
||||
|
@ -496,6 +497,16 @@ exit:
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(debugfs_rename);
|
||||
|
||||
/**
|
||||
* debugfs_initialized - Tells whether debugfs has been registered
|
||||
*/
|
||||
bool debugfs_initialized(void)
|
||||
{
|
||||
return debugfs_registered;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(debugfs_initialized);
|
||||
|
||||
|
||||
static struct kobject *debug_kobj;
|
||||
|
||||
static int __init debugfs_init(void)
|
||||
|
@ -509,11 +520,16 @@ static int __init debugfs_init(void)
|
|||
retval = register_filesystem(&debug_fs_type);
|
||||
if (retval)
|
||||
kobject_put(debug_kobj);
|
||||
else
|
||||
debugfs_registered = true;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit debugfs_exit(void)
|
||||
{
|
||||
debugfs_registered = false;
|
||||
|
||||
simple_release_fs(&debugfs_mount, &debugfs_mount_count);
|
||||
unregister_filesystem(&debug_fs_type);
|
||||
kobject_put(debug_kobj);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/kmod.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/genhd.h>
|
||||
#include <linux/blktrace_api.h>
|
||||
|
||||
#include "check.h"
|
||||
|
||||
|
@ -294,6 +295,9 @@ static struct attribute_group part_attr_group = {
|
|||
|
||||
static struct attribute_group *part_attr_groups[] = {
|
||||
&part_attr_group,
|
||||
#ifdef CONFIG_BLK_DEV_IO_TRACE
|
||||
&blk_trace_attr_group,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/* empty */
|
|
@ -61,6 +61,30 @@
|
|||
#define BRANCH_PROFILE()
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EVENT_TRACER
|
||||
#define FTRACE_EVENTS() VMLINUX_SYMBOL(__start_ftrace_events) = .; \
|
||||
*(_ftrace_events) \
|
||||
VMLINUX_SYMBOL(__stop_ftrace_events) = .;
|
||||
#else
|
||||
#define FTRACE_EVENTS()
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TRACING
|
||||
#define TRACE_PRINTKS() VMLINUX_SYMBOL(__start___trace_bprintk_fmt) = .; \
|
||||
*(__trace_printk_fmt) /* Trace_printk fmt' pointer */ \
|
||||
VMLINUX_SYMBOL(__stop___trace_bprintk_fmt) = .;
|
||||
#else
|
||||
#define TRACE_PRINTKS()
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FTRACE_SYSCALLS
|
||||
#define TRACE_SYSCALLS() VMLINUX_SYMBOL(__start_syscalls_metadata) = .; \
|
||||
*(__syscalls_metadata) \
|
||||
VMLINUX_SYMBOL(__stop_syscalls_metadata) = .;
|
||||
#else
|
||||
#define TRACE_SYSCALLS()
|
||||
#endif
|
||||
|
||||
/* .data section */
|
||||
#define DATA_DATA \
|
||||
*(.data) \
|
||||
|
@ -86,7 +110,10 @@
|
|||
*(__verbose) \
|
||||
VMLINUX_SYMBOL(__stop___verbose) = .; \
|
||||
LIKELY_PROFILE() \
|
||||
BRANCH_PROFILE()
|
||||
BRANCH_PROFILE() \
|
||||
TRACE_PRINTKS() \
|
||||
FTRACE_EVENTS() \
|
||||
TRACE_SYSCALLS()
|
||||
|
||||
#define RO_DATA(align) \
|
||||
. = ALIGN((align)); \
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/* empty */
|
|
@ -0,0 +1 @@
|
|||
/* empty */
|
|
@ -144,6 +144,9 @@ struct blk_user_trace_setup {
|
|||
|
||||
#ifdef __KERNEL__
|
||||
#if defined(CONFIG_BLK_DEV_IO_TRACE)
|
||||
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
struct blk_trace {
|
||||
int trace_state;
|
||||
struct rchan *rchan;
|
||||
|
@ -194,6 +197,8 @@ extern int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
|
|||
extern int blk_trace_startstop(struct request_queue *q, int start);
|
||||
extern int blk_trace_remove(struct request_queue *q);
|
||||
|
||||
extern struct attribute_group blk_trace_attr_group;
|
||||
|
||||
#else /* !CONFIG_BLK_DEV_IO_TRACE */
|
||||
#define blk_trace_ioctl(bdev, cmd, arg) (-ENOTTY)
|
||||
#define blk_trace_shutdown(q) do { } while (0)
|
||||
|
|
|
@ -68,6 +68,7 @@ struct ftrace_branch_data {
|
|||
unsigned long miss;
|
||||
unsigned long hit;
|
||||
};
|
||||
unsigned long miss_hit[2];
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -125,10 +126,7 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
|
|||
.line = __LINE__, \
|
||||
}; \
|
||||
______r = !!(cond); \
|
||||
if (______r) \
|
||||
______f.hit++; \
|
||||
else \
|
||||
______f.miss++; \
|
||||
______f.miss_hit[______r]++; \
|
||||
______r; \
|
||||
}))
|
||||
#endif /* CONFIG_PROFILE_ALL_BRANCHES */
|
||||
|
|
|
@ -71,6 +71,9 @@ struct dentry *debugfs_create_bool(const char *name, mode_t mode,
|
|||
struct dentry *debugfs_create_blob(const char *name, mode_t mode,
|
||||
struct dentry *parent,
|
||||
struct debugfs_blob_wrapper *blob);
|
||||
|
||||
bool debugfs_initialized(void);
|
||||
|
||||
#else
|
||||
|
||||
#include <linux/err.h>
|
||||
|
@ -183,6 +186,11 @@ static inline struct dentry *debugfs_create_blob(const char *name, mode_t mode,
|
|||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline bool debugfs_initialized(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
#ifndef _LINUX_FTRACE_H
|
||||
#define _LINUX_FTRACE_H
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/trace_clock.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include <asm/ftrace.h>
|
||||
|
||||
#ifdef CONFIG_FUNCTION_TRACER
|
||||
|
||||
|
@ -95,9 +98,41 @@ stack_trace_sysctl(struct ctl_table *table, int write,
|
|||
loff_t *ppos);
|
||||
#endif
|
||||
|
||||
struct ftrace_func_command {
|
||||
struct list_head list;
|
||||
char *name;
|
||||
int (*func)(char *func, char *cmd,
|
||||
char *params, int enable);
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
/* asm/ftrace.h must be defined for archs supporting dynamic ftrace */
|
||||
#include <asm/ftrace.h>
|
||||
|
||||
int ftrace_arch_code_modify_prepare(void);
|
||||
int ftrace_arch_code_modify_post_process(void);
|
||||
|
||||
struct seq_file;
|
||||
|
||||
struct ftrace_probe_ops {
|
||||
void (*func)(unsigned long ip,
|
||||
unsigned long parent_ip,
|
||||
void **data);
|
||||
int (*callback)(unsigned long ip, void **data);
|
||||
void (*free)(void **data);
|
||||
int (*print)(struct seq_file *m,
|
||||
unsigned long ip,
|
||||
struct ftrace_probe_ops *ops,
|
||||
void *data);
|
||||
};
|
||||
|
||||
extern int
|
||||
register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
|
||||
void *data);
|
||||
extern void
|
||||
unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
|
||||
void *data);
|
||||
extern void
|
||||
unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops);
|
||||
extern void unregister_ftrace_function_probe_all(char *glob);
|
||||
|
||||
enum {
|
||||
FTRACE_FL_FREE = (1 << 0),
|
||||
|
@ -110,15 +145,23 @@ enum {
|
|||
};
|
||||
|
||||
struct dyn_ftrace {
|
||||
struct list_head list;
|
||||
unsigned long ip; /* address of mcount call-site */
|
||||
unsigned long flags;
|
||||
struct dyn_arch_ftrace arch;
|
||||
union {
|
||||
unsigned long ip; /* address of mcount call-site */
|
||||
struct dyn_ftrace *freelist;
|
||||
};
|
||||
union {
|
||||
unsigned long flags;
|
||||
struct dyn_ftrace *newlist;
|
||||
};
|
||||
struct dyn_arch_ftrace arch;
|
||||
};
|
||||
|
||||
int ftrace_force_update(void);
|
||||
void ftrace_set_filter(unsigned char *buf, int len, int reset);
|
||||
|
||||
int register_ftrace_command(struct ftrace_func_command *cmd);
|
||||
int unregister_ftrace_command(struct ftrace_func_command *cmd);
|
||||
|
||||
/* defined in arch */
|
||||
extern int ftrace_ip_converted(unsigned long ip);
|
||||
extern int ftrace_dyn_arch_init(void *data);
|
||||
|
@ -126,6 +169,10 @@ extern int ftrace_update_ftrace_func(ftrace_func_t func);
|
|||
extern void ftrace_caller(void);
|
||||
extern void ftrace_call(void);
|
||||
extern void mcount_call(void);
|
||||
|
||||
#ifndef FTRACE_ADDR
|
||||
#define FTRACE_ADDR ((unsigned long)ftrace_caller)
|
||||
#endif
|
||||
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||
extern void ftrace_graph_caller(void);
|
||||
extern int ftrace_enable_ftrace_graph_caller(void);
|
||||
|
@ -136,7 +183,7 @@ static inline int ftrace_disable_ftrace_graph_caller(void) { return 0; }
|
|||
#endif
|
||||
|
||||
/**
|
||||
* ftrace_make_nop - convert code into top
|
||||
* ftrace_make_nop - convert code into nop
|
||||
* @mod: module structure if called by module load initialization
|
||||
* @rec: the mcount call site record
|
||||
* @addr: the address that the call site should be calling
|
||||
|
@ -181,7 +228,6 @@ extern int ftrace_make_nop(struct module *mod,
|
|||
*/
|
||||
extern int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr);
|
||||
|
||||
|
||||
/* May be defined in arch */
|
||||
extern int ftrace_arch_read_dyn_info(char *buf, int size);
|
||||
|
||||
|
@ -198,6 +244,14 @@ extern void ftrace_enable_daemon(void);
|
|||
# define ftrace_disable_daemon() do { } while (0)
|
||||
# define ftrace_enable_daemon() do { } while (0)
|
||||
static inline void ftrace_release(void *start, unsigned long size) { }
|
||||
static inline int register_ftrace_command(struct ftrace_func_command *cmd)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
static inline int unregister_ftrace_command(char *cmd_name)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif /* CONFIG_DYNAMIC_FTRACE */
|
||||
|
||||
/* totally disable ftrace - can not re-enable after this */
|
||||
|
@ -233,24 +287,25 @@ static inline void __ftrace_enabled_restore(int enabled)
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FRAME_POINTER
|
||||
/* TODO: need to fix this for ARM */
|
||||
# define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0))
|
||||
# define CALLER_ADDR1 ((unsigned long)__builtin_return_address(1))
|
||||
# define CALLER_ADDR2 ((unsigned long)__builtin_return_address(2))
|
||||
# define CALLER_ADDR3 ((unsigned long)__builtin_return_address(3))
|
||||
# define CALLER_ADDR4 ((unsigned long)__builtin_return_address(4))
|
||||
# define CALLER_ADDR5 ((unsigned long)__builtin_return_address(5))
|
||||
# define CALLER_ADDR6 ((unsigned long)__builtin_return_address(6))
|
||||
#else
|
||||
# define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0))
|
||||
# define CALLER_ADDR1 0UL
|
||||
# define CALLER_ADDR2 0UL
|
||||
# define CALLER_ADDR3 0UL
|
||||
# define CALLER_ADDR4 0UL
|
||||
# define CALLER_ADDR5 0UL
|
||||
# define CALLER_ADDR6 0UL
|
||||
#endif
|
||||
#ifndef HAVE_ARCH_CALLER_ADDR
|
||||
# ifdef CONFIG_FRAME_POINTER
|
||||
# define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0))
|
||||
# define CALLER_ADDR1 ((unsigned long)__builtin_return_address(1))
|
||||
# define CALLER_ADDR2 ((unsigned long)__builtin_return_address(2))
|
||||
# define CALLER_ADDR3 ((unsigned long)__builtin_return_address(3))
|
||||
# define CALLER_ADDR4 ((unsigned long)__builtin_return_address(4))
|
||||
# define CALLER_ADDR5 ((unsigned long)__builtin_return_address(5))
|
||||
# define CALLER_ADDR6 ((unsigned long)__builtin_return_address(6))
|
||||
# else
|
||||
# define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0))
|
||||
# define CALLER_ADDR1 0UL
|
||||
# define CALLER_ADDR2 0UL
|
||||
# define CALLER_ADDR3 0UL
|
||||
# define CALLER_ADDR4 0UL
|
||||
# define CALLER_ADDR5 0UL
|
||||
# define CALLER_ADDR6 0UL
|
||||
# endif
|
||||
#endif /* ifndef HAVE_ARCH_CALLER_ADDR */
|
||||
|
||||
#ifdef CONFIG_IRQSOFF_TRACER
|
||||
extern void time_hardirqs_on(unsigned long a0, unsigned long a1);
|
||||
|
@ -268,54 +323,6 @@ static inline void __ftrace_enabled_restore(int enabled)
|
|||
# define trace_preempt_off(a0, a1) do { } while (0)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TRACING
|
||||
extern int ftrace_dump_on_oops;
|
||||
|
||||
extern void tracing_start(void);
|
||||
extern void tracing_stop(void);
|
||||
extern void ftrace_off_permanent(void);
|
||||
|
||||
extern void
|
||||
ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3);
|
||||
|
||||
/**
|
||||
* ftrace_printk - printf formatting in the ftrace buffer
|
||||
* @fmt: the printf format for printing
|
||||
*
|
||||
* Note: __ftrace_printk is an internal function for ftrace_printk and
|
||||
* the @ip is passed in via the ftrace_printk macro.
|
||||
*
|
||||
* This function allows a kernel developer to debug fast path sections
|
||||
* that printk is not appropriate for. By scattering in various
|
||||
* printk like tracing in the code, a developer can quickly see
|
||||
* where problems are occurring.
|
||||
*
|
||||
* This is intended as a debugging tool for the developer only.
|
||||
* Please refrain from leaving ftrace_printks scattered around in
|
||||
* your code.
|
||||
*/
|
||||
# define ftrace_printk(fmt...) __ftrace_printk(_THIS_IP_, fmt)
|
||||
extern int
|
||||
__ftrace_printk(unsigned long ip, const char *fmt, ...)
|
||||
__attribute__ ((format (printf, 2, 3)));
|
||||
extern void ftrace_dump(void);
|
||||
#else
|
||||
static inline void
|
||||
ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3) { }
|
||||
static inline int
|
||||
ftrace_printk(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
|
||||
static inline void tracing_start(void) { }
|
||||
static inline void tracing_stop(void) { }
|
||||
static inline void ftrace_off_permanent(void) { }
|
||||
static inline int
|
||||
ftrace_printk(const char *fmt, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void ftrace_dump(void) { }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FTRACE_MCOUNT_RECORD
|
||||
extern void ftrace_init(void);
|
||||
extern void ftrace_init_module(struct module *mod,
|
||||
|
@ -327,36 +334,6 @@ ftrace_init_module(struct module *mod,
|
|||
unsigned long *start, unsigned long *end) { }
|
||||
#endif
|
||||
|
||||
enum {
|
||||
POWER_NONE = 0,
|
||||
POWER_CSTATE = 1,
|
||||
POWER_PSTATE = 2,
|
||||
};
|
||||
|
||||
struct power_trace {
|
||||
#ifdef CONFIG_POWER_TRACER
|
||||
ktime_t stamp;
|
||||
ktime_t end;
|
||||
int type;
|
||||
int state;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_POWER_TRACER
|
||||
extern void trace_power_start(struct power_trace *it, unsigned int type,
|
||||
unsigned int state);
|
||||
extern void trace_power_mark(struct power_trace *it, unsigned int type,
|
||||
unsigned int state);
|
||||
extern void trace_power_end(struct power_trace *it);
|
||||
#else
|
||||
static inline void trace_power_start(struct power_trace *it, unsigned int type,
|
||||
unsigned int state) { }
|
||||
static inline void trace_power_mark(struct power_trace *it, unsigned int type,
|
||||
unsigned int state) { }
|
||||
static inline void trace_power_end(struct power_trace *it) { }
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Structure that defines an entry function trace.
|
||||
*/
|
||||
|
@ -398,8 +375,7 @@ struct ftrace_ret_stack {
|
|||
extern void return_to_handler(void);
|
||||
|
||||
extern int
|
||||
ftrace_push_return_trace(unsigned long ret, unsigned long long time,
|
||||
unsigned long func, int *depth);
|
||||
ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth);
|
||||
extern void
|
||||
ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret);
|
||||
|
||||
|
@ -514,6 +490,50 @@ static inline int test_tsk_trace_graph(struct task_struct *tsk)
|
|||
return tsk->trace & TSK_TRACE_FL_GRAPH;
|
||||
}
|
||||
|
||||
extern int ftrace_dump_on_oops;
|
||||
|
||||
#endif /* CONFIG_TRACING */
|
||||
|
||||
|
||||
#ifdef CONFIG_HW_BRANCH_TRACER
|
||||
|
||||
void trace_hw_branch(u64 from, u64 to);
|
||||
void trace_hw_branch_oops(void);
|
||||
|
||||
#else /* CONFIG_HW_BRANCH_TRACER */
|
||||
|
||||
static inline void trace_hw_branch(u64 from, u64 to) {}
|
||||
static inline void trace_hw_branch_oops(void) {}
|
||||
|
||||
#endif /* CONFIG_HW_BRANCH_TRACER */
|
||||
|
||||
/*
|
||||
* A syscall entry in the ftrace syscalls array.
|
||||
*
|
||||
* @name: name of the syscall
|
||||
* @nb_args: number of parameters it takes
|
||||
* @types: list of types as strings
|
||||
* @args: list of args as strings (args[i] matches types[i])
|
||||
*/
|
||||
struct syscall_metadata {
|
||||
const char *name;
|
||||
int nb_args;
|
||||
const char **types;
|
||||
const char **args;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_FTRACE_SYSCALLS
|
||||
extern void arch_init_ftrace_syscalls(void);
|
||||
extern struct syscall_metadata *syscall_nr_to_meta(int nr);
|
||||
extern void start_ftrace_syscalls(void);
|
||||
extern void stop_ftrace_syscalls(void);
|
||||
extern void ftrace_syscall_enter(struct pt_regs *regs);
|
||||
extern void ftrace_syscall_exit(struct pt_regs *regs);
|
||||
#else
|
||||
static inline void start_ftrace_syscalls(void) { }
|
||||
static inline void stop_ftrace_syscalls(void) { }
|
||||
static inline void ftrace_syscall_enter(struct pt_regs *regs) { }
|
||||
static inline void ftrace_syscall_exit(struct pt_regs *regs) { }
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_FTRACE_H */
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define _LINUX_FTRACE_IRQ_H
|
||||
|
||||
|
||||
#if defined(CONFIG_DYNAMIC_FTRACE) || defined(CONFIG_FUNCTION_GRAPH_TRACER)
|
||||
#ifdef CONFIG_FTRACE_NMI_ENTER
|
||||
extern void ftrace_nmi_enter(void);
|
||||
extern void ftrace_nmi_exit(void);
|
||||
#else
|
||||
|
|
|
@ -15,55 +15,61 @@
|
|||
* - bits 0-7 are the preemption count (max preemption depth: 256)
|
||||
* - bits 8-15 are the softirq count (max # of softirqs: 256)
|
||||
*
|
||||
* The hardirq count can be overridden per architecture, the default is:
|
||||
* The hardirq count can in theory reach the same as NR_IRQS.
|
||||
* In reality, the number of nested IRQS is limited to the stack
|
||||
* size as well. For archs with over 1000 IRQS it is not practical
|
||||
* to expect that they will all nest. We give a max of 10 bits for
|
||||
* hardirq nesting. An arch may choose to give less than 10 bits.
|
||||
* m68k expects it to be 8.
|
||||
*
|
||||
* - bits 16-27 are the hardirq count (max # of hardirqs: 4096)
|
||||
* - ( bit 28 is the PREEMPT_ACTIVE flag. )
|
||||
* - bits 16-25 are the hardirq count (max # of nested hardirqs: 1024)
|
||||
* - bit 26 is the NMI_MASK
|
||||
* - bit 28 is the PREEMPT_ACTIVE flag
|
||||
*
|
||||
* PREEMPT_MASK: 0x000000ff
|
||||
* SOFTIRQ_MASK: 0x0000ff00
|
||||
* HARDIRQ_MASK: 0x0fff0000
|
||||
* HARDIRQ_MASK: 0x03ff0000
|
||||
* NMI_MASK: 0x04000000
|
||||
*/
|
||||
#define PREEMPT_BITS 8
|
||||
#define SOFTIRQ_BITS 8
|
||||
#define NMI_BITS 1
|
||||
|
||||
#define MAX_HARDIRQ_BITS 10
|
||||
|
||||
#ifndef HARDIRQ_BITS
|
||||
#define HARDIRQ_BITS 12
|
||||
|
||||
#ifndef MAX_HARDIRQS_PER_CPU
|
||||
#define MAX_HARDIRQS_PER_CPU NR_IRQS
|
||||
# define HARDIRQ_BITS MAX_HARDIRQ_BITS
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The hardirq mask has to be large enough to have space for potentially
|
||||
* all IRQ sources in the system nesting on a single CPU.
|
||||
*/
|
||||
#if (1 << HARDIRQ_BITS) < MAX_HARDIRQS_PER_CPU
|
||||
# error HARDIRQ_BITS is too low!
|
||||
#endif
|
||||
#if HARDIRQ_BITS > MAX_HARDIRQ_BITS
|
||||
#error HARDIRQ_BITS too high!
|
||||
#endif
|
||||
|
||||
#define PREEMPT_SHIFT 0
|
||||
#define SOFTIRQ_SHIFT (PREEMPT_SHIFT + PREEMPT_BITS)
|
||||
#define HARDIRQ_SHIFT (SOFTIRQ_SHIFT + SOFTIRQ_BITS)
|
||||
#define NMI_SHIFT (HARDIRQ_SHIFT + HARDIRQ_BITS)
|
||||
|
||||
#define __IRQ_MASK(x) ((1UL << (x))-1)
|
||||
|
||||
#define PREEMPT_MASK (__IRQ_MASK(PREEMPT_BITS) << PREEMPT_SHIFT)
|
||||
#define SOFTIRQ_MASK (__IRQ_MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT)
|
||||
#define HARDIRQ_MASK (__IRQ_MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT)
|
||||
#define NMI_MASK (__IRQ_MASK(NMI_BITS) << NMI_SHIFT)
|
||||
|
||||
#define PREEMPT_OFFSET (1UL << PREEMPT_SHIFT)
|
||||
#define SOFTIRQ_OFFSET (1UL << SOFTIRQ_SHIFT)
|
||||
#define HARDIRQ_OFFSET (1UL << HARDIRQ_SHIFT)
|
||||
#define NMI_OFFSET (1UL << NMI_SHIFT)
|
||||
|
||||
#if PREEMPT_ACTIVE < (1 << (HARDIRQ_SHIFT + HARDIRQ_BITS))
|
||||
#if PREEMPT_ACTIVE < (1 << (NMI_SHIFT + NMI_BITS))
|
||||
#error PREEMPT_ACTIVE is too low!
|
||||
#endif
|
||||
|
||||
#define hardirq_count() (preempt_count() & HARDIRQ_MASK)
|
||||
#define softirq_count() (preempt_count() & SOFTIRQ_MASK)
|
||||
#define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK))
|
||||
#define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK \
|
||||
| NMI_MASK))
|
||||
|
||||
/*
|
||||
* Are we doing bottom half or hardware interrupt processing?
|
||||
|
@ -73,6 +79,11 @@
|
|||
#define in_softirq() (softirq_count())
|
||||
#define in_interrupt() (irq_count())
|
||||
|
||||
/*
|
||||
* Are we in NMI context?
|
||||
*/
|
||||
#define in_nmi() (preempt_count() & NMI_MASK)
|
||||
|
||||
#if defined(CONFIG_PREEMPT)
|
||||
# define PREEMPT_INATOMIC_BASE kernel_locked()
|
||||
# define PREEMPT_CHECK_OFFSET 1
|
||||
|
@ -164,20 +175,24 @@ extern void irq_enter(void);
|
|||
*/
|
||||
extern void irq_exit(void);
|
||||
|
||||
#define nmi_enter() \
|
||||
do { \
|
||||
ftrace_nmi_enter(); \
|
||||
lockdep_off(); \
|
||||
rcu_nmi_enter(); \
|
||||
__irq_enter(); \
|
||||
#define nmi_enter() \
|
||||
do { \
|
||||
ftrace_nmi_enter(); \
|
||||
BUG_ON(in_nmi()); \
|
||||
add_preempt_count(NMI_OFFSET + HARDIRQ_OFFSET); \
|
||||
lockdep_off(); \
|
||||
rcu_nmi_enter(); \
|
||||
trace_hardirq_enter(); \
|
||||
} while (0)
|
||||
|
||||
#define nmi_exit() \
|
||||
do { \
|
||||
__irq_exit(); \
|
||||
rcu_nmi_exit(); \
|
||||
lockdep_on(); \
|
||||
ftrace_nmi_exit(); \
|
||||
#define nmi_exit() \
|
||||
do { \
|
||||
trace_hardirq_exit(); \
|
||||
rcu_nmi_exit(); \
|
||||
lockdep_on(); \
|
||||
BUG_ON(!in_nmi()); \
|
||||
sub_preempt_count(NMI_OFFSET + HARDIRQ_OFFSET); \
|
||||
ftrace_nmi_exit(); \
|
||||
} while (0)
|
||||
|
||||
#endif /* LINUX_HARDIRQ_H */
|
||||
|
|
|
@ -278,6 +278,11 @@ enum
|
|||
NR_SOFTIRQS
|
||||
};
|
||||
|
||||
/* map softirq index to softirq name. update 'softirq_to_name' in
|
||||
* kernel/softirq.c when adding a new softirq.
|
||||
*/
|
||||
extern char *softirq_to_name[NR_SOFTIRQS];
|
||||
|
||||
/* softirq mask and active fields moved to irq_cpustat_t in
|
||||
* asm/hardirq.h to get better cache usage. KAO
|
||||
*/
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
# define trace_softirqs_enabled(p) ((p)->softirqs_enabled)
|
||||
# define trace_hardirq_enter() do { current->hardirq_context++; } while (0)
|
||||
# define trace_hardirq_exit() do { current->hardirq_context--; } while (0)
|
||||
# define trace_softirq_enter() do { current->softirq_context++; } while (0)
|
||||
# define trace_softirq_exit() do { current->softirq_context--; } while (0)
|
||||
# define lockdep_softirq_enter() do { current->softirq_context++; } while (0)
|
||||
# define lockdep_softirq_exit() do { current->softirq_context--; } while (0)
|
||||
# define INIT_TRACE_IRQFLAGS .softirqs_enabled = 1,
|
||||
#else
|
||||
# define trace_hardirqs_on() do { } while (0)
|
||||
|
@ -38,8 +38,8 @@
|
|||
# define trace_softirqs_enabled(p) 0
|
||||
# define trace_hardirq_enter() do { } while (0)
|
||||
# define trace_hardirq_exit() do { } while (0)
|
||||
# define trace_softirq_enter() do { } while (0)
|
||||
# define trace_softirq_exit() do { } while (0)
|
||||
# define lockdep_softirq_enter() do { } while (0)
|
||||
# define lockdep_softirq_exit() do { } while (0)
|
||||
# define INIT_TRACE_IRQFLAGS
|
||||
#endif
|
||||
|
||||
|
|
|
@ -242,6 +242,19 @@ extern struct ratelimit_state printk_ratelimit_state;
|
|||
extern int printk_ratelimit(void);
|
||||
extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
|
||||
unsigned int interval_msec);
|
||||
|
||||
/*
|
||||
* Print a one-time message (analogous to WARN_ONCE() et al):
|
||||
*/
|
||||
#define printk_once(x...) ({ \
|
||||
static int __print_once = 1; \
|
||||
\
|
||||
if (__print_once) { \
|
||||
__print_once = 0; \
|
||||
printk(x); \
|
||||
} \
|
||||
})
|
||||
|
||||
#else
|
||||
static inline int vprintk(const char *s, va_list args)
|
||||
__attribute__ ((format (printf, 1, 0)));
|
||||
|
@ -253,6 +266,10 @@ static inline int printk_ratelimit(void) { return 0; }
|
|||
static inline bool printk_timed_ratelimit(unsigned long *caller_jiffies, \
|
||||
unsigned int interval_msec) \
|
||||
{ return false; }
|
||||
|
||||
/* No effect, but we still get type checking even in the !PRINTK case: */
|
||||
#define printk_once(x...) printk(x)
|
||||
|
||||
#endif
|
||||
|
||||
extern int printk_needs_cpu(int cpu);
|
||||
|
@ -370,6 +387,139 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
|
|||
({ if (0) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); 0; })
|
||||
#endif
|
||||
|
||||
/*
|
||||
* General tracing related utility functions - trace_printk(),
|
||||
* tracing_on/tracing_off and tracing_start()/tracing_stop
|
||||
*
|
||||
* Use tracing_on/tracing_off when you want to quickly turn on or off
|
||||
* tracing. It simply enables or disables the recording of the trace events.
|
||||
* This also corresponds to the user space debugfs/tracing/tracing_on
|
||||
* file, which gives a means for the kernel and userspace to interact.
|
||||
* Place a tracing_off() in the kernel where you want tracing to end.
|
||||
* From user space, examine the trace, and then echo 1 > tracing_on
|
||||
* to continue tracing.
|
||||
*
|
||||
* tracing_stop/tracing_start has slightly more overhead. It is used
|
||||
* by things like suspend to ram where disabling the recording of the
|
||||
* trace is not enough, but tracing must actually stop because things
|
||||
* like calling smp_processor_id() may crash the system.
|
||||
*
|
||||
* Most likely, you want to use tracing_on/tracing_off.
|
||||
*/
|
||||
#ifdef CONFIG_RING_BUFFER
|
||||
void tracing_on(void);
|
||||
void tracing_off(void);
|
||||
/* trace_off_permanent stops recording with no way to bring it back */
|
||||
void tracing_off_permanent(void);
|
||||
int tracing_is_on(void);
|
||||
#else
|
||||
static inline void tracing_on(void) { }
|
||||
static inline void tracing_off(void) { }
|
||||
static inline void tracing_off_permanent(void) { }
|
||||
static inline int tracing_is_on(void) { return 0; }
|
||||
#endif
|
||||
#ifdef CONFIG_TRACING
|
||||
extern void tracing_start(void);
|
||||
extern void tracing_stop(void);
|
||||
extern void ftrace_off_permanent(void);
|
||||
|
||||
extern void
|
||||
ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3);
|
||||
|
||||
static inline void __attribute__ ((format (printf, 1, 2)))
|
||||
____trace_printk_check_format(const char *fmt, ...)
|
||||
{
|
||||
}
|
||||
#define __trace_printk_check_format(fmt, args...) \
|
||||
do { \
|
||||
if (0) \
|
||||
____trace_printk_check_format(fmt, ##args); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* trace_printk - printf formatting in the ftrace buffer
|
||||
* @fmt: the printf format for printing
|
||||
*
|
||||
* Note: __trace_printk is an internal function for trace_printk and
|
||||
* the @ip is passed in via the trace_printk macro.
|
||||
*
|
||||
* This function allows a kernel developer to debug fast path sections
|
||||
* that printk is not appropriate for. By scattering in various
|
||||
* printk like tracing in the code, a developer can quickly see
|
||||
* where problems are occurring.
|
||||
*
|
||||
* This is intended as a debugging tool for the developer only.
|
||||
* Please refrain from leaving trace_printks scattered around in
|
||||
* your code.
|
||||
*/
|
||||
|
||||
#define trace_printk(fmt, args...) \
|
||||
do { \
|
||||
__trace_printk_check_format(fmt, ##args); \
|
||||
if (__builtin_constant_p(fmt)) { \
|
||||
static const char *trace_printk_fmt \
|
||||
__attribute__((section("__trace_printk_fmt"))) = \
|
||||
__builtin_constant_p(fmt) ? fmt : NULL; \
|
||||
\
|
||||
__trace_bprintk(_THIS_IP_, trace_printk_fmt, ##args); \
|
||||
} else \
|
||||
__trace_printk(_THIS_IP_, fmt, ##args); \
|
||||
} while (0)
|
||||
|
||||
extern int
|
||||
__trace_bprintk(unsigned long ip, const char *fmt, ...)
|
||||
__attribute__ ((format (printf, 2, 3)));
|
||||
|
||||
extern int
|
||||
__trace_printk(unsigned long ip, const char *fmt, ...)
|
||||
__attribute__ ((format (printf, 2, 3)));
|
||||
|
||||
/*
|
||||
* The double __builtin_constant_p is because gcc will give us an error
|
||||
* if we try to allocate the static variable to fmt if it is not a
|
||||
* constant. Even with the outer if statement.
|
||||
*/
|
||||
#define ftrace_vprintk(fmt, vargs) \
|
||||
do { \
|
||||
if (__builtin_constant_p(fmt)) { \
|
||||
static const char *trace_printk_fmt \
|
||||
__attribute__((section("__trace_printk_fmt"))) = \
|
||||
__builtin_constant_p(fmt) ? fmt : NULL; \
|
||||
\
|
||||
__ftrace_vbprintk(_THIS_IP_, trace_printk_fmt, vargs); \
|
||||
} else \
|
||||
__ftrace_vprintk(_THIS_IP_, fmt, vargs); \
|
||||
} while (0)
|
||||
|
||||
extern int
|
||||
__ftrace_vbprintk(unsigned long ip, const char *fmt, va_list ap);
|
||||
|
||||
extern int
|
||||
__ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap);
|
||||
|
||||
extern void ftrace_dump(void);
|
||||
#else
|
||||
static inline void
|
||||
ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3) { }
|
||||
static inline int
|
||||
trace_printk(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
|
||||
static inline void tracing_start(void) { }
|
||||
static inline void tracing_stop(void) { }
|
||||
static inline void ftrace_off_permanent(void) { }
|
||||
static inline int
|
||||
trace_printk(const char *fmt, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int
|
||||
ftrace_vprintk(const char *fmt, va_list ap)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void ftrace_dump(void) { }
|
||||
#endif /* CONFIG_TRACING */
|
||||
|
||||
/*
|
||||
* Display an IP address in readable format.
|
||||
*/
|
||||
|
|
|
@ -99,4 +99,10 @@ enum mem_add_context { BOOT, HOTPLUG };
|
|||
#define hotplug_memory_notifier(fn, pri) do { } while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Kernel text modification mutex, used for code patching. Users of this lock
|
||||
* can sleep.
|
||||
*/
|
||||
extern struct mutex text_mutex;
|
||||
|
||||
#endif /* _LINUX_MEMORY_H_ */
|
||||
|
|
|
@ -329,6 +329,11 @@ struct module
|
|||
unsigned int num_tracepoints;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TRACING
|
||||
const char **trace_bprintk_fmt_start;
|
||||
unsigned int num_trace_bprintk_fmt;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MODULE_UNLOAD
|
||||
/* What modules depend on me? */
|
||||
struct list_head modules_which_use_me;
|
||||
|
|
|
@ -8,7 +8,7 @@ struct ring_buffer;
|
|||
struct ring_buffer_iter;
|
||||
|
||||
/*
|
||||
* Don't reference this struct directly, use functions below.
|
||||
* Don't refer to this struct directly, use functions below.
|
||||
*/
|
||||
struct ring_buffer_event {
|
||||
u32 type:2, len:3, time_delta:27;
|
||||
|
@ -18,10 +18,13 @@ struct ring_buffer_event {
|
|||
/**
|
||||
* enum ring_buffer_type - internal ring buffer types
|
||||
*
|
||||
* @RINGBUF_TYPE_PADDING: Left over page padding
|
||||
* array is ignored
|
||||
* size is variable depending on how much
|
||||
* @RINGBUF_TYPE_PADDING: Left over page padding or discarded event
|
||||
* If time_delta is 0:
|
||||
* array is ignored
|
||||
* size is variable depending on how much
|
||||
* padding is needed
|
||||
* If time_delta is non zero:
|
||||
* everything else same as RINGBUF_TYPE_DATA
|
||||
*
|
||||
* @RINGBUF_TYPE_TIME_EXTEND: Extend the time delta
|
||||
* array[0] = time delta (28 .. 59)
|
||||
|
@ -65,6 +68,8 @@ ring_buffer_event_time_delta(struct ring_buffer_event *event)
|
|||
return event->time_delta;
|
||||
}
|
||||
|
||||
void ring_buffer_event_discard(struct ring_buffer_event *event);
|
||||
|
||||
/*
|
||||
* size is in bytes for each per CPU buffer.
|
||||
*/
|
||||
|
@ -74,13 +79,10 @@ void ring_buffer_free(struct ring_buffer *buffer);
|
|||
|
||||
int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size);
|
||||
|
||||
struct ring_buffer_event *
|
||||
ring_buffer_lock_reserve(struct ring_buffer *buffer,
|
||||
unsigned long length,
|
||||
unsigned long *flags);
|
||||
struct ring_buffer_event *ring_buffer_lock_reserve(struct ring_buffer *buffer,
|
||||
unsigned long length);
|
||||
int ring_buffer_unlock_commit(struct ring_buffer *buffer,
|
||||
struct ring_buffer_event *event,
|
||||
unsigned long flags);
|
||||
struct ring_buffer_event *event);
|
||||
int ring_buffer_write(struct ring_buffer *buffer,
|
||||
unsigned long length, void *data);
|
||||
|
||||
|
@ -121,17 +123,19 @@ 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_overrun_cpu(struct ring_buffer *buffer, int cpu);
|
||||
|
||||
u64 ring_buffer_time_stamp(int cpu);
|
||||
void ring_buffer_normalize_time_stamp(int cpu, u64 *ts);
|
||||
u64 ring_buffer_time_stamp(struct ring_buffer *buffer, int cpu);
|
||||
void ring_buffer_normalize_time_stamp(struct ring_buffer *buffer,
|
||||
int cpu, u64 *ts);
|
||||
void ring_buffer_set_clock(struct ring_buffer *buffer,
|
||||
u64 (*clock)(void));
|
||||
|
||||
size_t ring_buffer_page_len(void *page);
|
||||
|
||||
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);
|
||||
int ring_buffer_read_page(struct ring_buffer *buffer, void **data_page,
|
||||
size_t len, int cpu, int full);
|
||||
|
||||
enum ring_buffer_flags {
|
||||
RB_FL_OVERWRITE = 1 << 0,
|
||||
|
|
|
@ -137,6 +137,8 @@ extern unsigned long nr_uninterruptible(void);
|
|||
extern unsigned long nr_active(void);
|
||||
extern unsigned long nr_iowait(void);
|
||||
|
||||
extern unsigned long get_parent_ip(unsigned long addr);
|
||||
|
||||
struct seq_file;
|
||||
struct cfs_rq;
|
||||
struct task_group;
|
||||
|
@ -1421,6 +1423,8 @@ struct task_struct {
|
|||
int curr_ret_stack;
|
||||
/* Stack of return addresses for return function tracing */
|
||||
struct ftrace_ret_stack *ret_stack;
|
||||
/* time stamp for last schedule */
|
||||
unsigned long long ftrace_timestamp;
|
||||
/*
|
||||
* Number of functions that haven't been traced
|
||||
* because of depth overrun.
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <asm/page.h> /* kmalloc_sizes.h needs PAGE_SIZE */
|
||||
#include <asm/cache.h> /* kmalloc_sizes.h needs L1_CACHE_BYTES */
|
||||
#include <linux/compiler.h>
|
||||
#include <trace/kmemtrace.h>
|
||||
|
||||
/* Size description struct for general caches. */
|
||||
struct cache_sizes {
|
||||
|
@ -28,8 +29,26 @@ extern struct cache_sizes malloc_sizes[];
|
|||
void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
|
||||
void *__kmalloc(size_t size, gfp_t flags);
|
||||
|
||||
static inline void *kmalloc(size_t size, gfp_t flags)
|
||||
#ifdef CONFIG_KMEMTRACE
|
||||
extern void *kmem_cache_alloc_notrace(struct kmem_cache *cachep, gfp_t flags);
|
||||
extern size_t slab_buffer_size(struct kmem_cache *cachep);
|
||||
#else
|
||||
static __always_inline void *
|
||||
kmem_cache_alloc_notrace(struct kmem_cache *cachep, gfp_t flags)
|
||||
{
|
||||
return kmem_cache_alloc(cachep, flags);
|
||||
}
|
||||
static inline size_t slab_buffer_size(struct kmem_cache *cachep)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static __always_inline void *kmalloc(size_t size, gfp_t flags)
|
||||
{
|
||||
struct kmem_cache *cachep;
|
||||
void *ret;
|
||||
|
||||
if (__builtin_constant_p(size)) {
|
||||
int i = 0;
|
||||
|
||||
|
@ -47,10 +66,17 @@ static inline void *kmalloc(size_t size, gfp_t flags)
|
|||
found:
|
||||
#ifdef CONFIG_ZONE_DMA
|
||||
if (flags & GFP_DMA)
|
||||
return kmem_cache_alloc(malloc_sizes[i].cs_dmacachep,
|
||||
flags);
|
||||
cachep = malloc_sizes[i].cs_dmacachep;
|
||||
else
|
||||
#endif
|
||||
return kmem_cache_alloc(malloc_sizes[i].cs_cachep, flags);
|
||||
cachep = malloc_sizes[i].cs_cachep;
|
||||
|
||||
ret = kmem_cache_alloc_notrace(cachep, flags);
|
||||
|
||||
kmemtrace_mark_alloc(KMEMTRACE_TYPE_KMALLOC, _THIS_IP_, ret,
|
||||
size, slab_buffer_size(cachep), flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
return __kmalloc(size, flags);
|
||||
}
|
||||
|
@ -59,8 +85,25 @@ found:
|
|||
extern void *__kmalloc_node(size_t size, gfp_t flags, int node);
|
||||
extern void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
|
||||
|
||||
static inline void *kmalloc_node(size_t size, gfp_t flags, int node)
|
||||
#ifdef CONFIG_KMEMTRACE
|
||||
extern void *kmem_cache_alloc_node_notrace(struct kmem_cache *cachep,
|
||||
gfp_t flags,
|
||||
int nodeid);
|
||||
#else
|
||||
static __always_inline void *
|
||||
kmem_cache_alloc_node_notrace(struct kmem_cache *cachep,
|
||||
gfp_t flags,
|
||||
int nodeid)
|
||||
{
|
||||
return kmem_cache_alloc_node(cachep, flags, nodeid);
|
||||
}
|
||||
#endif
|
||||
|
||||
static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
|
||||
{
|
||||
struct kmem_cache *cachep;
|
||||
void *ret;
|
||||
|
||||
if (__builtin_constant_p(size)) {
|
||||
int i = 0;
|
||||
|
||||
|
@ -78,11 +121,18 @@ static inline void *kmalloc_node(size_t size, gfp_t flags, int node)
|
|||
found:
|
||||
#ifdef CONFIG_ZONE_DMA
|
||||
if (flags & GFP_DMA)
|
||||
return kmem_cache_alloc_node(malloc_sizes[i].cs_dmacachep,
|
||||
flags, node);
|
||||
cachep = malloc_sizes[i].cs_dmacachep;
|
||||
else
|
||||
#endif
|
||||
return kmem_cache_alloc_node(malloc_sizes[i].cs_cachep,
|
||||
flags, node);
|
||||
cachep = malloc_sizes[i].cs_cachep;
|
||||
|
||||
ret = kmem_cache_alloc_node_notrace(cachep, flags, node);
|
||||
|
||||
kmemtrace_mark_alloc_node(KMEMTRACE_TYPE_KMALLOC, _THIS_IP_,
|
||||
ret, size, slab_buffer_size(cachep),
|
||||
flags, node);
|
||||
|
||||
return ret;
|
||||
}
|
||||
return __kmalloc_node(size, flags, node);
|
||||
}
|
||||
|
|
|
@ -3,14 +3,15 @@
|
|||
|
||||
void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
|
||||
|
||||
static inline void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
|
||||
static __always_inline void *kmem_cache_alloc(struct kmem_cache *cachep,
|
||||
gfp_t flags)
|
||||
{
|
||||
return kmem_cache_alloc_node(cachep, flags, -1);
|
||||
}
|
||||
|
||||
void *__kmalloc_node(size_t size, gfp_t flags, int node);
|
||||
|
||||
static inline void *kmalloc_node(size_t size, gfp_t flags, int node)
|
||||
static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
|
||||
{
|
||||
return __kmalloc_node(size, flags, node);
|
||||
}
|
||||
|
@ -23,12 +24,12 @@ static inline void *kmalloc_node(size_t size, gfp_t flags, int node)
|
|||
* kmalloc is the normal method of allocating memory
|
||||
* in the kernel.
|
||||
*/
|
||||
static inline void *kmalloc(size_t size, gfp_t flags)
|
||||
static __always_inline void *kmalloc(size_t size, gfp_t flags)
|
||||
{
|
||||
return __kmalloc_node(size, flags, -1);
|
||||
}
|
||||
|
||||
static inline void *__kmalloc(size_t size, gfp_t flags)
|
||||
static __always_inline void *__kmalloc(size_t size, gfp_t flags)
|
||||
{
|
||||
return kmalloc(size, flags);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/gfp.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <trace/kmemtrace.h>
|
||||
|
||||
enum stat_item {
|
||||
ALLOC_FASTPATH, /* Allocation from cpu slab */
|
||||
|
@ -217,13 +218,31 @@ static __always_inline struct kmem_cache *kmalloc_slab(size_t size)
|
|||
void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
|
||||
void *__kmalloc(size_t size, gfp_t flags);
|
||||
|
||||
#ifdef CONFIG_KMEMTRACE
|
||||
extern void *kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags);
|
||||
#else
|
||||
static __always_inline void *
|
||||
kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags)
|
||||
{
|
||||
return kmem_cache_alloc(s, gfpflags);
|
||||
}
|
||||
#endif
|
||||
|
||||
static __always_inline void *kmalloc_large(size_t size, gfp_t flags)
|
||||
{
|
||||
return (void *)__get_free_pages(flags | __GFP_COMP, get_order(size));
|
||||
unsigned int order = get_order(size);
|
||||
void *ret = (void *) __get_free_pages(flags | __GFP_COMP, order);
|
||||
|
||||
kmemtrace_mark_alloc(KMEMTRACE_TYPE_KMALLOC, _THIS_IP_, ret,
|
||||
size, PAGE_SIZE << order, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __always_inline void *kmalloc(size_t size, gfp_t flags)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
if (__builtin_constant_p(size)) {
|
||||
if (size > SLUB_MAX_SIZE)
|
||||
return kmalloc_large(size, flags);
|
||||
|
@ -234,7 +253,13 @@ static __always_inline void *kmalloc(size_t size, gfp_t flags)
|
|||
if (!s)
|
||||
return ZERO_SIZE_PTR;
|
||||
|
||||
return kmem_cache_alloc(s, flags);
|
||||
ret = kmem_cache_alloc_notrace(s, flags);
|
||||
|
||||
kmemtrace_mark_alloc(KMEMTRACE_TYPE_KMALLOC,
|
||||
_THIS_IP_, ret,
|
||||
size, s->size, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return __kmalloc(size, flags);
|
||||
|
@ -244,8 +269,24 @@ static __always_inline void *kmalloc(size_t size, gfp_t flags)
|
|||
void *__kmalloc_node(size_t size, gfp_t flags, int node);
|
||||
void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
|
||||
|
||||
#ifdef CONFIG_KMEMTRACE
|
||||
extern void *kmem_cache_alloc_node_notrace(struct kmem_cache *s,
|
||||
gfp_t gfpflags,
|
||||
int node);
|
||||
#else
|
||||
static __always_inline void *
|
||||
kmem_cache_alloc_node_notrace(struct kmem_cache *s,
|
||||
gfp_t gfpflags,
|
||||
int node)
|
||||
{
|
||||
return kmem_cache_alloc_node(s, gfpflags, node);
|
||||
}
|
||||
#endif
|
||||
|
||||
static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
if (__builtin_constant_p(size) &&
|
||||
size <= SLUB_MAX_SIZE && !(flags & SLUB_DMA)) {
|
||||
struct kmem_cache *s = kmalloc_slab(size);
|
||||
|
@ -253,7 +294,13 @@ static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
|
|||
if (!s)
|
||||
return ZERO_SIZE_PTR;
|
||||
|
||||
return kmem_cache_alloc_node(s, flags, node);
|
||||
ret = kmem_cache_alloc_node_notrace(s, flags, node);
|
||||
|
||||
kmemtrace_mark_alloc_node(KMEMTRACE_TYPE_KMALLOC,
|
||||
_THIS_IP_, ret,
|
||||
size, s->size, flags, node);
|
||||
|
||||
return ret;
|
||||
}
|
||||
return __kmalloc_node(size, flags, node);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/compiler.h> /* for inline */
|
||||
#include <linux/types.h> /* for size_t */
|
||||
#include <linux/stddef.h> /* for NULL */
|
||||
#include <stdarg.h>
|
||||
|
||||
extern char *strndup_user(const char __user *, long);
|
||||
extern void *memdup_user(const void __user *, size_t);
|
||||
|
@ -112,6 +113,12 @@ extern void argv_free(char **argv);
|
|||
|
||||
extern bool sysfs_streq(const char *s1, const char *s2);
|
||||
|
||||
#ifdef CONFIG_BINARY_PRINTF
|
||||
int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args);
|
||||
int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf);
|
||||
int bprintf(u32 *bin_buf, size_t size, const char *fmt, ...) __printf(3, 4);
|
||||
#endif
|
||||
|
||||
extern ssize_t memory_read_from_buffer(void *to, size_t count, loff_t *ppos,
|
||||
const void *from, size_t available);
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ struct old_linux_dirent;
|
|||
#include <asm/signal.h>
|
||||
#include <linux/quota.h>
|
||||
#include <linux/key.h>
|
||||
#include <linux/ftrace.h>
|
||||
|
||||
#define __SC_DECL1(t1, a1) t1 a1
|
||||
#define __SC_DECL2(t2, a2, ...) t2 a2, __SC_DECL1(__VA_ARGS__)
|
||||
|
@ -95,7 +96,46 @@ struct old_linux_dirent;
|
|||
#define __SC_TEST5(t5, a5, ...) __SC_TEST(t5); __SC_TEST4(__VA_ARGS__)
|
||||
#define __SC_TEST6(t6, a6, ...) __SC_TEST(t6); __SC_TEST5(__VA_ARGS__)
|
||||
|
||||
#ifdef CONFIG_FTRACE_SYSCALLS
|
||||
#define __SC_STR_ADECL1(t, a) #a
|
||||
#define __SC_STR_ADECL2(t, a, ...) #a, __SC_STR_ADECL1(__VA_ARGS__)
|
||||
#define __SC_STR_ADECL3(t, a, ...) #a, __SC_STR_ADECL2(__VA_ARGS__)
|
||||
#define __SC_STR_ADECL4(t, a, ...) #a, __SC_STR_ADECL3(__VA_ARGS__)
|
||||
#define __SC_STR_ADECL5(t, a, ...) #a, __SC_STR_ADECL4(__VA_ARGS__)
|
||||
#define __SC_STR_ADECL6(t, a, ...) #a, __SC_STR_ADECL5(__VA_ARGS__)
|
||||
|
||||
#define __SC_STR_TDECL1(t, a) #t
|
||||
#define __SC_STR_TDECL2(t, a, ...) #t, __SC_STR_TDECL1(__VA_ARGS__)
|
||||
#define __SC_STR_TDECL3(t, a, ...) #t, __SC_STR_TDECL2(__VA_ARGS__)
|
||||
#define __SC_STR_TDECL4(t, a, ...) #t, __SC_STR_TDECL3(__VA_ARGS__)
|
||||
#define __SC_STR_TDECL5(t, a, ...) #t, __SC_STR_TDECL4(__VA_ARGS__)
|
||||
#define __SC_STR_TDECL6(t, a, ...) #t, __SC_STR_TDECL5(__VA_ARGS__)
|
||||
|
||||
#define SYSCALL_METADATA(sname, nb) \
|
||||
static const struct syscall_metadata __used \
|
||||
__attribute__((__aligned__(4))) \
|
||||
__attribute__((section("__syscalls_metadata"))) \
|
||||
__syscall_meta_##sname = { \
|
||||
.name = "sys"#sname, \
|
||||
.nb_args = nb, \
|
||||
.types = types_##sname, \
|
||||
.args = args_##sname, \
|
||||
}
|
||||
|
||||
#define SYSCALL_DEFINE0(sname) \
|
||||
static const struct syscall_metadata __used \
|
||||
__attribute__((__aligned__(4))) \
|
||||
__attribute__((section("__syscalls_metadata"))) \
|
||||
__syscall_meta_##sname = { \
|
||||
.name = "sys_"#sname, \
|
||||
.nb_args = 0, \
|
||||
}; \
|
||||
asmlinkage long sys_##sname(void)
|
||||
|
||||
#else
|
||||
#define SYSCALL_DEFINE0(name) asmlinkage long sys_##name(void)
|
||||
#endif
|
||||
|
||||
#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
|
||||
#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
|
||||
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
|
||||
|
@ -117,10 +157,26 @@ struct old_linux_dirent;
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FTRACE_SYSCALLS
|
||||
#define SYSCALL_DEFINEx(x, sname, ...) \
|
||||
static const char *types_##sname[] = { \
|
||||
__SC_STR_TDECL##x(__VA_ARGS__) \
|
||||
}; \
|
||||
static const char *args_##sname[] = { \
|
||||
__SC_STR_ADECL##x(__VA_ARGS__) \
|
||||
}; \
|
||||
SYSCALL_METADATA(sname, x); \
|
||||
__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
|
||||
#else
|
||||
#define SYSCALL_DEFINEx(x, sname, ...) \
|
||||
__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
|
||||
|
||||
#define SYSCALL_DEFINE(name) static inline long SYSC_##name
|
||||
#define SYSCALL_DEFINEx(x, name, ...) \
|
||||
|
||||
#define __SYSCALL_DEFINEx(x, name, ...) \
|
||||
asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__)); \
|
||||
static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__)); \
|
||||
asmlinkage long SyS##name(__SC_LONG##x(__VA_ARGS__)) \
|
||||
|
@ -134,7 +190,7 @@ struct old_linux_dirent;
|
|||
#else /* CONFIG_HAVE_SYSCALL_WRAPPERS */
|
||||
|
||||
#define SYSCALL_DEFINE(name) asmlinkage long sys_##name
|
||||
#define SYSCALL_DEFINEx(x, name, ...) \
|
||||
#define __SYSCALL_DEFINEx(x, name, ...) \
|
||||
asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))
|
||||
|
||||
#endif /* CONFIG_HAVE_SYSCALL_WRAPPERS */
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef _LINUX_TRACE_CLOCK_H
|
||||
#define _LINUX_TRACE_CLOCK_H
|
||||
|
||||
/*
|
||||
* 3 trace clock variants, with differing scalability/precision
|
||||
* tradeoffs:
|
||||
*
|
||||
* - local: CPU-local trace clock
|
||||
* - medium: scalable global clock with some jitter
|
||||
* - global: globally monotonic, serialized clock
|
||||
*/
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
extern u64 notrace trace_clock_local(void);
|
||||
extern u64 notrace trace_clock(void);
|
||||
extern u64 notrace trace_clock_global(void);
|
||||
|
||||
#endif /* _LINUX_TRACE_CLOCK_H */
|
|
@ -31,8 +31,8 @@ struct tracepoint {
|
|||
* Keep in sync with vmlinux.lds.h.
|
||||
*/
|
||||
|
||||
#define TPPROTO(args...) args
|
||||
#define TPARGS(args...) args
|
||||
#define TP_PROTO(args...) args
|
||||
#define TP_ARGS(args...) args
|
||||
|
||||
#ifdef CONFIG_TRACEPOINTS
|
||||
|
||||
|
@ -65,7 +65,7 @@ struct tracepoint {
|
|||
{ \
|
||||
if (unlikely(__tracepoint_##name.state)) \
|
||||
__DO_TRACE(&__tracepoint_##name, \
|
||||
TPPROTO(proto), TPARGS(args)); \
|
||||
TP_PROTO(proto), TP_ARGS(args)); \
|
||||
} \
|
||||
static inline int register_trace_##name(void (*probe)(proto)) \
|
||||
{ \
|
||||
|
@ -153,4 +153,114 @@ static inline void tracepoint_synchronize_unregister(void)
|
|||
synchronize_sched();
|
||||
}
|
||||
|
||||
#define PARAMS(args...) args
|
||||
#define TRACE_FORMAT(name, proto, args, fmt) \
|
||||
DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))
|
||||
|
||||
|
||||
/*
|
||||
* For use with the TRACE_EVENT macro:
|
||||
*
|
||||
* We define a tracepoint, its arguments, its printk format
|
||||
* and its 'fast binay record' layout.
|
||||
*
|
||||
* Firstly, name your tracepoint via TRACE_EVENT(name : the
|
||||
* 'subsystem_event' notation is fine.
|
||||
*
|
||||
* Think about this whole construct as the
|
||||
* 'trace_sched_switch() function' from now on.
|
||||
*
|
||||
*
|
||||
* TRACE_EVENT(sched_switch,
|
||||
*
|
||||
* *
|
||||
* * A function has a regular function arguments
|
||||
* * prototype, declare it via TP_PROTO():
|
||||
* *
|
||||
*
|
||||
* TP_PROTO(struct rq *rq, struct task_struct *prev,
|
||||
* struct task_struct *next),
|
||||
*
|
||||
* *
|
||||
* * Define the call signature of the 'function'.
|
||||
* * (Design sidenote: we use this instead of a
|
||||
* * TP_PROTO1/TP_PROTO2/TP_PROTO3 ugliness.)
|
||||
* *
|
||||
*
|
||||
* TP_ARGS(rq, prev, next),
|
||||
*
|
||||
* *
|
||||
* * Fast binary tracing: define the trace record via
|
||||
* * TP_STRUCT__entry(). You can think about it like a
|
||||
* * regular C structure local variable definition.
|
||||
* *
|
||||
* * This is how the trace record is structured and will
|
||||
* * be saved into the ring buffer. These are the fields
|
||||
* * that will be exposed to user-space in
|
||||
* * /debug/tracing/events/<*>/format.
|
||||
* *
|
||||
* * The declared 'local variable' is called '__entry'
|
||||
* *
|
||||
* * __field(pid_t, prev_prid) is equivalent to a standard declariton:
|
||||
* *
|
||||
* * pid_t prev_pid;
|
||||
* *
|
||||
* * __array(char, prev_comm, TASK_COMM_LEN) is equivalent to:
|
||||
* *
|
||||
* * char prev_comm[TASK_COMM_LEN];
|
||||
* *
|
||||
*
|
||||
* TP_STRUCT__entry(
|
||||
* __array( char, prev_comm, TASK_COMM_LEN )
|
||||
* __field( pid_t, prev_pid )
|
||||
* __field( int, prev_prio )
|
||||
* __array( char, next_comm, TASK_COMM_LEN )
|
||||
* __field( pid_t, next_pid )
|
||||
* __field( int, next_prio )
|
||||
* ),
|
||||
*
|
||||
* *
|
||||
* * Assign the entry into the trace record, by embedding
|
||||
* * a full C statement block into TP_fast_assign(). You
|
||||
* * can refer to the trace record as '__entry' -
|
||||
* * otherwise you can put arbitrary C code in here.
|
||||
* *
|
||||
* * Note: this C code will execute every time a trace event
|
||||
* * happens, on an active tracepoint.
|
||||
* *
|
||||
*
|
||||
* TP_fast_assign(
|
||||
* memcpy(__entry->next_comm, next->comm, TASK_COMM_LEN);
|
||||
* __entry->prev_pid = prev->pid;
|
||||
* __entry->prev_prio = prev->prio;
|
||||
* memcpy(__entry->prev_comm, prev->comm, TASK_COMM_LEN);
|
||||
* __entry->next_pid = next->pid;
|
||||
* __entry->next_prio = next->prio;
|
||||
* )
|
||||
*
|
||||
* *
|
||||
* * Formatted output of a trace record via TP_printk().
|
||||
* * This is how the tracepoint will appear under ftrace
|
||||
* * plugins that make use of this tracepoint.
|
||||
* *
|
||||
* * (raw-binary tracing wont actually perform this step.)
|
||||
* *
|
||||
*
|
||||
* TP_printk("task %s:%d [%d] ==> %s:%d [%d]",
|
||||
* __entry->prev_comm, __entry->prev_pid, __entry->prev_prio,
|
||||
* __entry->next_comm, __entry->next_pid, __entry->next_prio),
|
||||
*
|
||||
* );
|
||||
*
|
||||
* This macro construct is thus used for the regular printk format
|
||||
* tracing setup, it is used to construct a function pointer based
|
||||
* tracepoint callback (this is used by programmatic plugins and
|
||||
* can also by used by generic instrumentation like SystemTap), and
|
||||
* it is also used to expose a structured trace record in
|
||||
* /debug/tracing/events/.
|
||||
*/
|
||||
|
||||
#define TRACE_EVENT(name, proto, args, struct, assign, print) \
|
||||
DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,72 +5,72 @@
|
|||
#include <linux/tracepoint.h>
|
||||
|
||||
DECLARE_TRACE(block_rq_abort,
|
||||
TPPROTO(struct request_queue *q, struct request *rq),
|
||||
TPARGS(q, rq));
|
||||
TP_PROTO(struct request_queue *q, struct request *rq),
|
||||
TP_ARGS(q, rq));
|
||||
|
||||
DECLARE_TRACE(block_rq_insert,
|
||||
TPPROTO(struct request_queue *q, struct request *rq),
|
||||
TPARGS(q, rq));
|
||||
TP_PROTO(struct request_queue *q, struct request *rq),
|
||||
TP_ARGS(q, rq));
|
||||
|
||||
DECLARE_TRACE(block_rq_issue,
|
||||
TPPROTO(struct request_queue *q, struct request *rq),
|
||||
TPARGS(q, rq));
|
||||
TP_PROTO(struct request_queue *q, struct request *rq),
|
||||
TP_ARGS(q, rq));
|
||||
|
||||
DECLARE_TRACE(block_rq_requeue,
|
||||
TPPROTO(struct request_queue *q, struct request *rq),
|
||||
TPARGS(q, rq));
|
||||
TP_PROTO(struct request_queue *q, struct request *rq),
|
||||
TP_ARGS(q, rq));
|
||||
|
||||
DECLARE_TRACE(block_rq_complete,
|
||||
TPPROTO(struct request_queue *q, struct request *rq),
|
||||
TPARGS(q, rq));
|
||||
TP_PROTO(struct request_queue *q, struct request *rq),
|
||||
TP_ARGS(q, rq));
|
||||
|
||||
DECLARE_TRACE(block_bio_bounce,
|
||||
TPPROTO(struct request_queue *q, struct bio *bio),
|
||||
TPARGS(q, bio));
|
||||
TP_PROTO(struct request_queue *q, struct bio *bio),
|
||||
TP_ARGS(q, bio));
|
||||
|
||||
DECLARE_TRACE(block_bio_complete,
|
||||
TPPROTO(struct request_queue *q, struct bio *bio),
|
||||
TPARGS(q, bio));
|
||||
TP_PROTO(struct request_queue *q, struct bio *bio),
|
||||
TP_ARGS(q, bio));
|
||||
|
||||
DECLARE_TRACE(block_bio_backmerge,
|
||||
TPPROTO(struct request_queue *q, struct bio *bio),
|
||||
TPARGS(q, bio));
|
||||
TP_PROTO(struct request_queue *q, struct bio *bio),
|
||||
TP_ARGS(q, bio));
|
||||
|
||||
DECLARE_TRACE(block_bio_frontmerge,
|
||||
TPPROTO(struct request_queue *q, struct bio *bio),
|
||||
TPARGS(q, bio));
|
||||
TP_PROTO(struct request_queue *q, struct bio *bio),
|
||||
TP_ARGS(q, bio));
|
||||
|
||||
DECLARE_TRACE(block_bio_queue,
|
||||
TPPROTO(struct request_queue *q, struct bio *bio),
|
||||
TPARGS(q, bio));
|
||||
TP_PROTO(struct request_queue *q, struct bio *bio),
|
||||
TP_ARGS(q, bio));
|
||||
|
||||
DECLARE_TRACE(block_getrq,
|
||||
TPPROTO(struct request_queue *q, struct bio *bio, int rw),
|
||||
TPARGS(q, bio, rw));
|
||||
TP_PROTO(struct request_queue *q, struct bio *bio, int rw),
|
||||
TP_ARGS(q, bio, rw));
|
||||
|
||||
DECLARE_TRACE(block_sleeprq,
|
||||
TPPROTO(struct request_queue *q, struct bio *bio, int rw),
|
||||
TPARGS(q, bio, rw));
|
||||
TP_PROTO(struct request_queue *q, struct bio *bio, int rw),
|
||||
TP_ARGS(q, bio, rw));
|
||||
|
||||
DECLARE_TRACE(block_plug,
|
||||
TPPROTO(struct request_queue *q),
|
||||
TPARGS(q));
|
||||
TP_PROTO(struct request_queue *q),
|
||||
TP_ARGS(q));
|
||||
|
||||
DECLARE_TRACE(block_unplug_timer,
|
||||
TPPROTO(struct request_queue *q),
|
||||
TPARGS(q));
|
||||
TP_PROTO(struct request_queue *q),
|
||||
TP_ARGS(q));
|
||||
|
||||
DECLARE_TRACE(block_unplug_io,
|
||||
TPPROTO(struct request_queue *q),
|
||||
TPARGS(q));
|
||||
TP_PROTO(struct request_queue *q),
|
||||
TP_ARGS(q));
|
||||
|
||||
DECLARE_TRACE(block_split,
|
||||
TPPROTO(struct request_queue *q, struct bio *bio, unsigned int pdu),
|
||||
TPARGS(q, bio, pdu));
|
||||
TP_PROTO(struct request_queue *q, struct bio *bio, unsigned int pdu),
|
||||
TP_ARGS(q, bio, pdu));
|
||||
|
||||
DECLARE_TRACE(block_remap,
|
||||
TPPROTO(struct request_queue *q, struct bio *bio, dev_t dev,
|
||||
sector_t from, sector_t to),
|
||||
TPARGS(q, bio, dev, from, to));
|
||||
TP_PROTO(struct request_queue *q, struct bio *bio, dev_t dev,
|
||||
sector_t from, sector_t to),
|
||||
TP_ARGS(q, bio, dev, from, to));
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef _TRACE_IRQ_H
|
||||
#define _TRACE_IRQ_H
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
#include <trace/irq_event_types.h>
|
||||
|
||||
#endif
|
|
@ -0,0 +1,55 @@
|
|||
|
||||
/* use <trace/irq.h> instead */
|
||||
#ifndef TRACE_FORMAT
|
||||
# error Do not include this file directly.
|
||||
# error Unless you know what you are doing.
|
||||
#endif
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM irq
|
||||
|
||||
/*
|
||||
* Tracepoint for entry of interrupt handler:
|
||||
*/
|
||||
TRACE_FORMAT(irq_handler_entry,
|
||||
TP_PROTO(int irq, struct irqaction *action),
|
||||
TP_ARGS(irq, action),
|
||||
TP_FMT("irq=%d handler=%s", irq, action->name)
|
||||
);
|
||||
|
||||
/*
|
||||
* Tracepoint for return of an interrupt handler:
|
||||
*/
|
||||
TRACE_EVENT(irq_handler_exit,
|
||||
|
||||
TP_PROTO(int irq, struct irqaction *action, int ret),
|
||||
|
||||
TP_ARGS(irq, action, ret),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( int, irq )
|
||||
__field( int, ret )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->irq = irq;
|
||||
__entry->ret = ret;
|
||||
),
|
||||
|
||||
TP_printk("irq=%d return=%s",
|
||||
__entry->irq, __entry->ret ? "handled" : "unhandled")
|
||||
);
|
||||
|
||||
TRACE_FORMAT(softirq_entry,
|
||||
TP_PROTO(struct softirq_action *h, struct softirq_action *vec),
|
||||
TP_ARGS(h, vec),
|
||||
TP_FMT("softirq=%d action=%s", (int)(h - vec), softirq_to_name[h-vec])
|
||||
);
|
||||
|
||||
TRACE_FORMAT(softirq_exit,
|
||||
TP_PROTO(struct softirq_action *h, struct softirq_action *vec),
|
||||
TP_ARGS(h, vec),
|
||||
TP_FMT("softirq=%d action=%s", (int)(h - vec), softirq_to_name[h-vec])
|
||||
);
|
||||
|
||||
#undef TRACE_SYSTEM
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (C) 2008 Eduard - Gabriel Munteanu
|
||||
*
|
||||
* This file is released under GPL version 2.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_KMEMTRACE_H
|
||||
#define _LINUX_KMEMTRACE_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/marker.h>
|
||||
|
||||
enum kmemtrace_type_id {
|
||||
KMEMTRACE_TYPE_KMALLOC = 0, /* kmalloc() or kfree(). */
|
||||
KMEMTRACE_TYPE_CACHE, /* kmem_cache_*(). */
|
||||
KMEMTRACE_TYPE_PAGES, /* __get_free_pages() and friends. */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_KMEMTRACE
|
||||
|
||||
extern void kmemtrace_init(void);
|
||||
|
||||
extern void kmemtrace_mark_alloc_node(enum kmemtrace_type_id type_id,
|
||||
unsigned long call_site,
|
||||
const void *ptr,
|
||||
size_t bytes_req,
|
||||
size_t bytes_alloc,
|
||||
gfp_t gfp_flags,
|
||||
int node);
|
||||
|
||||
extern void kmemtrace_mark_free(enum kmemtrace_type_id type_id,
|
||||
unsigned long call_site,
|
||||
const void *ptr);
|
||||
|
||||
#else /* CONFIG_KMEMTRACE */
|
||||
|
||||
static inline void kmemtrace_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void kmemtrace_mark_alloc_node(enum kmemtrace_type_id type_id,
|
||||
unsigned long call_site,
|
||||
const void *ptr,
|
||||
size_t bytes_req,
|
||||
size_t bytes_alloc,
|
||||
gfp_t gfp_flags,
|
||||
int node)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void kmemtrace_mark_free(enum kmemtrace_type_id type_id,
|
||||
unsigned long call_site,
|
||||
const void *ptr)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_KMEMTRACE */
|
||||
|
||||
static inline void kmemtrace_mark_alloc(enum kmemtrace_type_id type_id,
|
||||
unsigned long call_site,
|
||||
const void *ptr,
|
||||
size_t bytes_req,
|
||||
size_t bytes_alloc,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
kmemtrace_mark_alloc_node(type_id, call_site, ptr,
|
||||
bytes_req, bytes_alloc, gfp_flags, -1);
|
||||
}
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* _LINUX_KMEMTRACE_H */
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef _TRACE_LOCKDEP_H
|
||||
#define _TRACE_LOCKDEP_H
|
||||
|
||||
#include <linux/lockdep.h>
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
#include <trace/lockdep_event_types.h>
|
||||
|
||||
#endif
|
|
@ -0,0 +1,44 @@
|
|||
|
||||
#ifndef TRACE_FORMAT
|
||||
# error Do not include this file directly.
|
||||
# error Unless you know what you are doing.
|
||||
#endif
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM lock
|
||||
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
|
||||
TRACE_FORMAT(lock_acquire,
|
||||
TP_PROTO(struct lockdep_map *lock, unsigned int subclass,
|
||||
int trylock, int read, int check,
|
||||
struct lockdep_map *next_lock, unsigned long ip),
|
||||
TP_ARGS(lock, subclass, trylock, read, check, next_lock, ip),
|
||||
TP_FMT("%s%s%s", trylock ? "try " : "",
|
||||
read ? "read " : "", lock->name)
|
||||
);
|
||||
|
||||
TRACE_FORMAT(lock_release,
|
||||
TP_PROTO(struct lockdep_map *lock, int nested, unsigned long ip),
|
||||
TP_ARGS(lock, nested, ip),
|
||||
TP_FMT("%s", lock->name)
|
||||
);
|
||||
|
||||
#ifdef CONFIG_LOCK_STAT
|
||||
|
||||
TRACE_FORMAT(lock_contended,
|
||||
TP_PROTO(struct lockdep_map *lock, unsigned long ip),
|
||||
TP_ARGS(lock, ip),
|
||||
TP_FMT("%s", lock->name)
|
||||
);
|
||||
|
||||
TRACE_FORMAT(lock_acquired,
|
||||
TP_PROTO(struct lockdep_map *lock, unsigned long ip),
|
||||
TP_ARGS(lock, ip),
|
||||
TP_FMT("%s", lock->name)
|
||||
);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#undef TRACE_SYSTEM
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef _TRACE_POWER_H
|
||||
#define _TRACE_POWER_H
|
||||
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
enum {
|
||||
POWER_NONE = 0,
|
||||
POWER_CSTATE = 1,
|
||||
POWER_PSTATE = 2,
|
||||
};
|
||||
|
||||
struct power_trace {
|
||||
ktime_t stamp;
|
||||
ktime_t end;
|
||||
int type;
|
||||
int state;
|
||||
};
|
||||
|
||||
DECLARE_TRACE(power_start,
|
||||
TP_PROTO(struct power_trace *it, unsigned int type, unsigned int state),
|
||||
TP_ARGS(it, type, state));
|
||||
|
||||
DECLARE_TRACE(power_mark,
|
||||
TP_PROTO(struct power_trace *it, unsigned int type, unsigned int state),
|
||||
TP_ARGS(it, type, state));
|
||||
|
||||
DECLARE_TRACE(power_end,
|
||||
TP_PROTO(struct power_trace *it),
|
||||
TP_ARGS(it));
|
||||
|
||||
#endif /* _TRACE_POWER_H */
|
|
@ -4,53 +4,6 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
DECLARE_TRACE(sched_kthread_stop,
|
||||
TPPROTO(struct task_struct *t),
|
||||
TPARGS(t));
|
||||
|
||||
DECLARE_TRACE(sched_kthread_stop_ret,
|
||||
TPPROTO(int ret),
|
||||
TPARGS(ret));
|
||||
|
||||
DECLARE_TRACE(sched_wait_task,
|
||||
TPPROTO(struct rq *rq, struct task_struct *p),
|
||||
TPARGS(rq, p));
|
||||
|
||||
DECLARE_TRACE(sched_wakeup,
|
||||
TPPROTO(struct rq *rq, struct task_struct *p, int success),
|
||||
TPARGS(rq, p, success));
|
||||
|
||||
DECLARE_TRACE(sched_wakeup_new,
|
||||
TPPROTO(struct rq *rq, struct task_struct *p, int success),
|
||||
TPARGS(rq, p, success));
|
||||
|
||||
DECLARE_TRACE(sched_switch,
|
||||
TPPROTO(struct rq *rq, struct task_struct *prev,
|
||||
struct task_struct *next),
|
||||
TPARGS(rq, prev, next));
|
||||
|
||||
DECLARE_TRACE(sched_migrate_task,
|
||||
TPPROTO(struct task_struct *p, int orig_cpu, int dest_cpu),
|
||||
TPARGS(p, orig_cpu, dest_cpu));
|
||||
|
||||
DECLARE_TRACE(sched_process_free,
|
||||
TPPROTO(struct task_struct *p),
|
||||
TPARGS(p));
|
||||
|
||||
DECLARE_TRACE(sched_process_exit,
|
||||
TPPROTO(struct task_struct *p),
|
||||
TPARGS(p));
|
||||
|
||||
DECLARE_TRACE(sched_process_wait,
|
||||
TPPROTO(struct pid *pid),
|
||||
TPARGS(pid));
|
||||
|
||||
DECLARE_TRACE(sched_process_fork,
|
||||
TPPROTO(struct task_struct *parent, struct task_struct *child),
|
||||
TPARGS(parent, child));
|
||||
|
||||
DECLARE_TRACE(sched_signal_send,
|
||||
TPPROTO(int sig, struct task_struct *p),
|
||||
TPARGS(sig, p));
|
||||
#include <trace/sched_event_types.h>
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,337 @@
|
|||
|
||||
/* use <trace/sched.h> instead */
|
||||
#ifndef TRACE_EVENT
|
||||
# error Do not include this file directly.
|
||||
# error Unless you know what you are doing.
|
||||
#endif
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM sched
|
||||
|
||||
/*
|
||||
* Tracepoint for calling kthread_stop, performed to end a kthread:
|
||||
*/
|
||||
TRACE_EVENT(sched_kthread_stop,
|
||||
|
||||
TP_PROTO(struct task_struct *t),
|
||||
|
||||
TP_ARGS(t),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array( char, comm, TASK_COMM_LEN )
|
||||
__field( pid_t, pid )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
memcpy(__entry->comm, t->comm, TASK_COMM_LEN);
|
||||
__entry->pid = t->pid;
|
||||
),
|
||||
|
||||
TP_printk("task %s:%d", __entry->comm, __entry->pid)
|
||||
);
|
||||
|
||||
/*
|
||||
* Tracepoint for the return value of the kthread stopping:
|
||||
*/
|
||||
TRACE_EVENT(sched_kthread_stop_ret,
|
||||
|
||||
TP_PROTO(int ret),
|
||||
|
||||
TP_ARGS(ret),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( int, ret )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->ret = ret;
|
||||
),
|
||||
|
||||
TP_printk("ret %d", __entry->ret)
|
||||
);
|
||||
|
||||
/*
|
||||
* Tracepoint for waiting on task to unschedule:
|
||||
*
|
||||
* (NOTE: the 'rq' argument is not used by generic trace events,
|
||||
* but used by the latency tracer plugin. )
|
||||
*/
|
||||
TRACE_EVENT(sched_wait_task,
|
||||
|
||||
TP_PROTO(struct rq *rq, struct task_struct *p),
|
||||
|
||||
TP_ARGS(rq, p),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array( char, comm, TASK_COMM_LEN )
|
||||
__field( pid_t, pid )
|
||||
__field( int, prio )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
|
||||
__entry->pid = p->pid;
|
||||
__entry->prio = p->prio;
|
||||
),
|
||||
|
||||
TP_printk("task %s:%d [%d]",
|
||||
__entry->comm, __entry->pid, __entry->prio)
|
||||
);
|
||||
|
||||
/*
|
||||
* Tracepoint for waking up a task:
|
||||
*
|
||||
* (NOTE: the 'rq' argument is not used by generic trace events,
|
||||
* but used by the latency tracer plugin. )
|
||||
*/
|
||||
TRACE_EVENT(sched_wakeup,
|
||||
|
||||
TP_PROTO(struct rq *rq, struct task_struct *p, int success),
|
||||
|
||||
TP_ARGS(rq, p, success),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array( char, comm, TASK_COMM_LEN )
|
||||
__field( pid_t, pid )
|
||||
__field( int, prio )
|
||||
__field( int, success )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
|
||||
__entry->pid = p->pid;
|
||||
__entry->prio = p->prio;
|
||||
__entry->success = success;
|
||||
),
|
||||
|
||||
TP_printk("task %s:%d [%d] success=%d",
|
||||
__entry->comm, __entry->pid, __entry->prio,
|
||||
__entry->success)
|
||||
);
|
||||
|
||||
/*
|
||||
* Tracepoint for waking up a new task:
|
||||
*
|
||||
* (NOTE: the 'rq' argument is not used by generic trace events,
|
||||
* but used by the latency tracer plugin. )
|
||||
*/
|
||||
TRACE_EVENT(sched_wakeup_new,
|
||||
|
||||
TP_PROTO(struct rq *rq, struct task_struct *p, int success),
|
||||
|
||||
TP_ARGS(rq, p, success),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array( char, comm, TASK_COMM_LEN )
|
||||
__field( pid_t, pid )
|
||||
__field( int, prio )
|
||||
__field( int, success )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
|
||||
__entry->pid = p->pid;
|
||||
__entry->prio = p->prio;
|
||||
__entry->success = success;
|
||||
),
|
||||
|
||||
TP_printk("task %s:%d [%d] success=%d",
|
||||
__entry->comm, __entry->pid, __entry->prio,
|
||||
__entry->success)
|
||||
);
|
||||
|
||||
/*
|
||||
* Tracepoint for task switches, performed by the scheduler:
|
||||
*
|
||||
* (NOTE: the 'rq' argument is not used by generic trace events,
|
||||
* but used by the latency tracer plugin. )
|
||||
*/
|
||||
TRACE_EVENT(sched_switch,
|
||||
|
||||
TP_PROTO(struct rq *rq, struct task_struct *prev,
|
||||
struct task_struct *next),
|
||||
|
||||
TP_ARGS(rq, prev, next),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array( char, prev_comm, TASK_COMM_LEN )
|
||||
__field( pid_t, prev_pid )
|
||||
__field( int, prev_prio )
|
||||
__array( char, next_comm, TASK_COMM_LEN )
|
||||
__field( pid_t, next_pid )
|
||||
__field( int, next_prio )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
memcpy(__entry->next_comm, next->comm, TASK_COMM_LEN);
|
||||
__entry->prev_pid = prev->pid;
|
||||
__entry->prev_prio = prev->prio;
|
||||
memcpy(__entry->prev_comm, prev->comm, TASK_COMM_LEN);
|
||||
__entry->next_pid = next->pid;
|
||||
__entry->next_prio = next->prio;
|
||||
),
|
||||
|
||||
TP_printk("task %s:%d [%d] ==> %s:%d [%d]",
|
||||
__entry->prev_comm, __entry->prev_pid, __entry->prev_prio,
|
||||
__entry->next_comm, __entry->next_pid, __entry->next_prio)
|
||||
);
|
||||
|
||||
/*
|
||||
* Tracepoint for a task being migrated:
|
||||
*/
|
||||
TRACE_EVENT(sched_migrate_task,
|
||||
|
||||
TP_PROTO(struct task_struct *p, int orig_cpu, int dest_cpu),
|
||||
|
||||
TP_ARGS(p, orig_cpu, dest_cpu),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array( char, comm, TASK_COMM_LEN )
|
||||
__field( pid_t, pid )
|
||||
__field( int, prio )
|
||||
__field( int, orig_cpu )
|
||||
__field( int, dest_cpu )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
|
||||
__entry->pid = p->pid;
|
||||
__entry->prio = p->prio;
|
||||
__entry->orig_cpu = orig_cpu;
|
||||
__entry->dest_cpu = dest_cpu;
|
||||
),
|
||||
|
||||
TP_printk("task %s:%d [%d] from: %d to: %d",
|
||||
__entry->comm, __entry->pid, __entry->prio,
|
||||
__entry->orig_cpu, __entry->dest_cpu)
|
||||
);
|
||||
|
||||
/*
|
||||
* Tracepoint for freeing a task:
|
||||
*/
|
||||
TRACE_EVENT(sched_process_free,
|
||||
|
||||
TP_PROTO(struct task_struct *p),
|
||||
|
||||
TP_ARGS(p),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array( char, comm, TASK_COMM_LEN )
|
||||
__field( pid_t, pid )
|
||||
__field( int, prio )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
|
||||
__entry->pid = p->pid;
|
||||
__entry->prio = p->prio;
|
||||
),
|
||||
|
||||
TP_printk("task %s:%d [%d]",
|
||||
__entry->comm, __entry->pid, __entry->prio)
|
||||
);
|
||||
|
||||
/*
|
||||
* Tracepoint for a task exiting:
|
||||
*/
|
||||
TRACE_EVENT(sched_process_exit,
|
||||
|
||||
TP_PROTO(struct task_struct *p),
|
||||
|
||||
TP_ARGS(p),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array( char, comm, TASK_COMM_LEN )
|
||||
__field( pid_t, pid )
|
||||
__field( int, prio )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
|
||||
__entry->pid = p->pid;
|
||||
__entry->prio = p->prio;
|
||||
),
|
||||
|
||||
TP_printk("task %s:%d [%d]",
|
||||
__entry->comm, __entry->pid, __entry->prio)
|
||||
);
|
||||
|
||||
/*
|
||||
* Tracepoint for a waiting task:
|
||||
*/
|
||||
TRACE_EVENT(sched_process_wait,
|
||||
|
||||
TP_PROTO(struct pid *pid),
|
||||
|
||||
TP_ARGS(pid),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array( char, comm, TASK_COMM_LEN )
|
||||
__field( pid_t, pid )
|
||||
__field( int, prio )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
|
||||
__entry->pid = pid_nr(pid);
|
||||
__entry->prio = current->prio;
|
||||
),
|
||||
|
||||
TP_printk("task %s:%d [%d]",
|
||||
__entry->comm, __entry->pid, __entry->prio)
|
||||
);
|
||||
|
||||
/*
|
||||
* Tracepoint for do_fork:
|
||||
*/
|
||||
TRACE_EVENT(sched_process_fork,
|
||||
|
||||
TP_PROTO(struct task_struct *parent, struct task_struct *child),
|
||||
|
||||
TP_ARGS(parent, child),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array( char, parent_comm, TASK_COMM_LEN )
|
||||
__field( pid_t, parent_pid )
|
||||
__array( char, child_comm, TASK_COMM_LEN )
|
||||
__field( pid_t, child_pid )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
memcpy(__entry->parent_comm, parent->comm, TASK_COMM_LEN);
|
||||
__entry->parent_pid = parent->pid;
|
||||
memcpy(__entry->child_comm, child->comm, TASK_COMM_LEN);
|
||||
__entry->child_pid = child->pid;
|
||||
),
|
||||
|
||||
TP_printk("parent %s:%d child %s:%d",
|
||||
__entry->parent_comm, __entry->parent_pid,
|
||||
__entry->child_comm, __entry->child_pid)
|
||||
);
|
||||
|
||||
/*
|
||||
* Tracepoint for sending a signal:
|
||||
*/
|
||||
TRACE_EVENT(sched_signal_send,
|
||||
|
||||
TP_PROTO(int sig, struct task_struct *p),
|
||||
|
||||
TP_ARGS(sig, p),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( int, sig )
|
||||
__array( char, comm, TASK_COMM_LEN )
|
||||
__field( pid_t, pid )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
|
||||
__entry->pid = p->pid;
|
||||
__entry->sig = sig;
|
||||
),
|
||||
|
||||
TP_printk("sig: %d task %s:%d",
|
||||
__entry->sig, __entry->comm, __entry->pid)
|
||||
);
|
||||
|
||||
#undef TRACE_SYSTEM
|
|
@ -0,0 +1,5 @@
|
|||
/* trace/<type>_event_types.h here */
|
||||
|
||||
#include <trace/sched_event_types.h>
|
||||
#include <trace/irq_event_types.h>
|
||||
#include <trace/lockdep_event_types.h>
|
|
@ -0,0 +1,5 @@
|
|||
/* trace/<type>.h here */
|
||||
|
||||
#include <trace/sched.h>
|
||||
#include <trace/irq.h>
|
||||
#include <trace/lockdep.h>
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef __TRACE_WORKQUEUE_H
|
||||
#define __TRACE_WORKQUEUE_H
|
||||
|
||||
#include <linux/tracepoint.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
DECLARE_TRACE(workqueue_insertion,
|
||||
TP_PROTO(struct task_struct *wq_thread, struct work_struct *work),
|
||||
TP_ARGS(wq_thread, work));
|
||||
|
||||
DECLARE_TRACE(workqueue_execution,
|
||||
TP_PROTO(struct task_struct *wq_thread, struct work_struct *work),
|
||||
TP_ARGS(wq_thread, work));
|
||||
|
||||
/* Trace the creation of one workqueue thread on a cpu */
|
||||
DECLARE_TRACE(workqueue_creation,
|
||||
TP_PROTO(struct task_struct *wq_thread, int cpu),
|
||||
TP_ARGS(wq_thread, cpu));
|
||||
|
||||
DECLARE_TRACE(workqueue_destruction,
|
||||
TP_PROTO(struct task_struct *wq_thread),
|
||||
TP_ARGS(wq_thread));
|
||||
|
||||
#endif /* __TRACE_WORKQUEUE_H */
|
|
@ -1005,7 +1005,7 @@ config TRACEPOINTS
|
|||
|
||||
config MARKERS
|
||||
bool "Activate markers"
|
||||
depends on TRACEPOINTS
|
||||
select TRACEPOINTS
|
||||
help
|
||||
Place an empty function call at each marker site. Can be
|
||||
dynamically changed for a probe function.
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
#include <asm/setup.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <trace/kmemtrace.h>
|
||||
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
#include <asm/smp.h>
|
||||
|
@ -648,6 +649,7 @@ asmlinkage void __init start_kernel(void)
|
|||
enable_debug_pagealloc();
|
||||
cpu_hotplug_init();
|
||||
kmem_cache_init();
|
||||
kmemtrace_init();
|
||||
debug_objects_mem_init();
|
||||
idr_init_cache();
|
||||
setup_per_cpu_pageset();
|
||||
|
@ -769,6 +771,7 @@ static void __init do_basic_setup(void)
|
|||
{
|
||||
rcu_init_sched(); /* needed by module_init stage. */
|
||||
init_workqueues();
|
||||
cpuset_init_smp();
|
||||
usermodehelper_init();
|
||||
driver_init();
|
||||
init_irq_proc();
|
||||
|
@ -863,8 +866,6 @@ static int __init kernel_init(void * unused)
|
|||
smp_init();
|
||||
sched_init_smp();
|
||||
|
||||
cpuset_init_smp();
|
||||
|
||||
do_basic_setup();
|
||||
|
||||
/*
|
||||
|
|
|
@ -15,11 +15,22 @@
|
|||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/memory.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/sections.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
/*
|
||||
* mutex protecting text section modification (dynamic code patching).
|
||||
* some users need to sleep (allocating memory...) while they hold this lock.
|
||||
*
|
||||
* NOT exported to modules - patching kernel text is a really delicate matter.
|
||||
*/
|
||||
DEFINE_MUTEX(text_mutex);
|
||||
|
||||
extern struct exception_table_entry __start___ex_table[];
|
||||
extern struct exception_table_entry __stop___ex_table[];
|
||||
|
@ -41,7 +52,7 @@ const struct exception_table_entry *search_exception_tables(unsigned long addr)
|
|||
return e;
|
||||
}
|
||||
|
||||
__notrace_funcgraph int core_kernel_text(unsigned long addr)
|
||||
int core_kernel_text(unsigned long addr)
|
||||
{
|
||||
if (addr >= (unsigned long)_stext &&
|
||||
addr <= (unsigned long)_etext)
|
||||
|
@ -54,7 +65,7 @@ __notrace_funcgraph int core_kernel_text(unsigned long addr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
__notrace_funcgraph int __kernel_text_address(unsigned long addr)
|
||||
int __kernel_text_address(unsigned long addr)
|
||||
{
|
||||
if (core_kernel_text(addr))
|
||||
return 1;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/kernel_stat.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <linux/hash.h>
|
||||
#include <trace/irq.h>
|
||||
#include <linux/bootmem.h>
|
||||
|
||||
#include "internals.h"
|
||||
|
@ -338,6 +339,9 @@ irqreturn_t no_action(int cpl, void *dev_id)
|
|||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
DEFINE_TRACE(irq_handler_entry);
|
||||
DEFINE_TRACE(irq_handler_exit);
|
||||
|
||||
/**
|
||||
* handle_IRQ_event - irq action chain handler
|
||||
* @irq: the interrupt number
|
||||
|
@ -356,7 +360,9 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
|
|||
local_irq_enable_in_hardirq();
|
||||
|
||||
do {
|
||||
trace_irq_handler_entry(irq, action);
|
||||
ret = action->handler(irq, action->dev_id);
|
||||
trace_irq_handler_exit(irq, action, ret);
|
||||
if (ret == IRQ_HANDLED)
|
||||
status |= action->flags;
|
||||
retval |= ret;
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include <linux/seq_file.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/kdebug.h>
|
||||
#include <linux/memory.h>
|
||||
|
||||
#include <asm-generic/sections.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
@ -699,9 +700,10 @@ int __kprobes register_kprobe(struct kprobe *p)
|
|||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&text_mutex);
|
||||
ret = arch_prepare_kprobe(p);
|
||||
if (ret)
|
||||
goto out;
|
||||
goto out_unlock_text;
|
||||
|
||||
INIT_HLIST_NODE(&p->hlist);
|
||||
hlist_add_head_rcu(&p->hlist,
|
||||
|
@ -710,6 +712,8 @@ int __kprobes register_kprobe(struct kprobe *p)
|
|||
if (kprobe_enabled)
|
||||
arch_arm_kprobe(p);
|
||||
|
||||
out_unlock_text:
|
||||
mutex_unlock(&text_mutex);
|
||||
out:
|
||||
mutex_unlock(&kprobe_mutex);
|
||||
|
||||
|
@ -746,8 +750,11 @@ valid_p:
|
|||
* enabled and not gone - otherwise, the breakpoint would
|
||||
* already have been removed. We save on flushing icache.
|
||||
*/
|
||||
if (kprobe_enabled && !kprobe_gone(old_p))
|
||||
if (kprobe_enabled && !kprobe_gone(old_p)) {
|
||||
mutex_lock(&text_mutex);
|
||||
arch_disarm_kprobe(p);
|
||||
mutex_unlock(&text_mutex);
|
||||
}
|
||||
hlist_del_rcu(&old_p->hlist);
|
||||
} else {
|
||||
if (p->break_handler && !kprobe_gone(p))
|
||||
|
@ -912,10 +919,8 @@ static int __kprobes pre_handler_kretprobe(struct kprobe *p,
|
|||
ri->rp = rp;
|
||||
ri->task = current;
|
||||
|
||||
if (rp->entry_handler && rp->entry_handler(ri, regs)) {
|
||||
spin_unlock_irqrestore(&rp->lock, flags);
|
||||
if (rp->entry_handler && rp->entry_handler(ri, regs))
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_prepare_kretprobe(ri, regs);
|
||||
|
||||
|
@ -1280,12 +1285,14 @@ static void __kprobes enable_all_kprobes(void)
|
|||
if (kprobe_enabled)
|
||||
goto already_enabled;
|
||||
|
||||
mutex_lock(&text_mutex);
|
||||
for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
|
||||
head = &kprobe_table[i];
|
||||
hlist_for_each_entry_rcu(p, node, head, hlist)
|
||||
if (!kprobe_gone(p))
|
||||
arch_arm_kprobe(p);
|
||||
}
|
||||
mutex_unlock(&text_mutex);
|
||||
|
||||
kprobe_enabled = true;
|
||||
printk(KERN_INFO "Kprobes globally enabled\n");
|
||||
|
@ -1310,6 +1317,7 @@ static void __kprobes disable_all_kprobes(void)
|
|||
|
||||
kprobe_enabled = false;
|
||||
printk(KERN_INFO "Kprobes globally disabled\n");
|
||||
mutex_lock(&text_mutex);
|
||||
for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
|
||||
head = &kprobe_table[i];
|
||||
hlist_for_each_entry_rcu(p, node, head, hlist) {
|
||||
|
@ -1318,6 +1326,7 @@ static void __kprobes disable_all_kprobes(void)
|
|||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&text_mutex);
|
||||
mutex_unlock(&kprobe_mutex);
|
||||
/* Allow all currently running kprobes to complete */
|
||||
synchronize_sched();
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include <linux/hash.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/stringify.h>
|
||||
#include <trace/lockdep.h>
|
||||
|
||||
#include <asm/sections.h>
|
||||
|
||||
|
@ -433,13 +434,6 @@ atomic_t nr_find_usage_forwards_checks;
|
|||
atomic_t nr_find_usage_forwards_recursions;
|
||||
atomic_t nr_find_usage_backwards_checks;
|
||||
atomic_t nr_find_usage_backwards_recursions;
|
||||
# define debug_atomic_inc(ptr) atomic_inc(ptr)
|
||||
# define debug_atomic_dec(ptr) atomic_dec(ptr)
|
||||
# define debug_atomic_read(ptr) atomic_read(ptr)
|
||||
#else
|
||||
# define debug_atomic_inc(ptr) do { } while (0)
|
||||
# define debug_atomic_dec(ptr) do { } while (0)
|
||||
# define debug_atomic_read(ptr) 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -1900,9 +1894,9 @@ print_irq_inversion_bug(struct task_struct *curr, struct lock_class *other,
|
|||
curr->comm, task_pid_nr(curr));
|
||||
print_lock(this);
|
||||
if (forwards)
|
||||
printk("but this lock took another, %s-irq-unsafe lock in the past:\n", irqclass);
|
||||
printk("but this lock took another, %s-unsafe lock in the past:\n", irqclass);
|
||||
else
|
||||
printk("but this lock was taken by another, %s-irq-safe lock in the past:\n", irqclass);
|
||||
printk("but this lock was taken by another, %s-safe lock in the past:\n", irqclass);
|
||||
print_lock_name(other);
|
||||
printk("\n\nand interrupts could create inverse lock ordering between them.\n\n");
|
||||
|
||||
|
@ -2015,7 +2009,8 @@ typedef int (*check_usage_f)(struct task_struct *, struct held_lock *,
|
|||
enum lock_usage_bit bit, const char *name);
|
||||
|
||||
static int
|
||||
mark_lock_irq(struct task_struct *curr, struct held_lock *this, int new_bit)
|
||||
mark_lock_irq(struct task_struct *curr, struct held_lock *this,
|
||||
enum lock_usage_bit new_bit)
|
||||
{
|
||||
int excl_bit = exclusive_bit(new_bit);
|
||||
int read = new_bit & 1;
|
||||
|
@ -2043,7 +2038,7 @@ mark_lock_irq(struct task_struct *curr, struct held_lock *this, int new_bit)
|
|||
* states.
|
||||
*/
|
||||
if ((!read || !dir || STRICT_READ_CHECKS) &&
|
||||
!usage(curr, this, excl_bit, state_name(new_bit)))
|
||||
!usage(curr, this, excl_bit, state_name(new_bit & ~1)))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
|
@ -2929,6 +2924,8 @@ void lock_set_class(struct lockdep_map *lock, const char *name,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(lock_set_class);
|
||||
|
||||
DEFINE_TRACE(lock_acquire);
|
||||
|
||||
/*
|
||||
* We are not always called with irqs disabled - do that here,
|
||||
* and also avoid lockdep recursion:
|
||||
|
@ -2939,6 +2936,8 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
|
|||
{
|
||||
unsigned long flags;
|
||||
|
||||
trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip);
|
||||
|
||||
if (unlikely(current->lockdep_recursion))
|
||||
return;
|
||||
|
||||
|
@ -2953,11 +2952,15 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(lock_acquire);
|
||||
|
||||
DEFINE_TRACE(lock_release);
|
||||
|
||||
void lock_release(struct lockdep_map *lock, int nested,
|
||||
unsigned long ip)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
trace_lock_release(lock, nested, ip);
|
||||
|
||||
if (unlikely(current->lockdep_recursion))
|
||||
return;
|
||||
|
||||
|
@ -3106,10 +3109,14 @@ found_it:
|
|||
lock->ip = ip;
|
||||
}
|
||||
|
||||
DEFINE_TRACE(lock_contended);
|
||||
|
||||
void lock_contended(struct lockdep_map *lock, unsigned long ip)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
trace_lock_contended(lock, ip);
|
||||
|
||||
if (unlikely(!lock_stat))
|
||||
return;
|
||||
|
||||
|
@ -3125,10 +3132,14 @@ void lock_contended(struct lockdep_map *lock, unsigned long ip)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(lock_contended);
|
||||
|
||||
DEFINE_TRACE(lock_acquired);
|
||||
|
||||
void lock_acquired(struct lockdep_map *lock, unsigned long ip)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
trace_lock_acquired(lock, ip);
|
||||
|
||||
if (unlikely(!lock_stat))
|
||||
return;
|
||||
|
||||
|
|
|
@ -2766,7 +2766,7 @@ int is_module_address(unsigned long addr)
|
|||
|
||||
|
||||
/* Is this a valid kernel address? */
|
||||
__notrace_funcgraph struct module *__module_text_address(unsigned long addr)
|
||||
struct module *__module_text_address(unsigned long addr)
|
||||
{
|
||||
struct module *mod;
|
||||
|
||||
|
|
|
@ -677,9 +677,7 @@ int relay_late_setup_files(struct rchan *chan,
|
|||
*/
|
||||
for_each_online_cpu(i) {
|
||||
if (unlikely(!chan->buf[i])) {
|
||||
printk(KERN_ERR "relay_late_setup_files: CPU %u "
|
||||
"has no buffer, it must have!\n", i);
|
||||
BUG();
|
||||
WARN_ONCE(1, KERN_ERR "CPU has no buffer!\n");
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -4781,10 +4781,7 @@ void scheduler_tick(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
#if defined(CONFIG_PREEMPT) && (defined(CONFIG_DEBUG_PREEMPT) || \
|
||||
defined(CONFIG_PREEMPT_TRACER))
|
||||
|
||||
static inline unsigned long get_parent_ip(unsigned long addr)
|
||||
unsigned long get_parent_ip(unsigned long addr)
|
||||
{
|
||||
if (in_lock_functions(addr)) {
|
||||
addr = CALLER_ADDR2;
|
||||
|
@ -4794,6 +4791,9 @@ static inline unsigned long get_parent_ip(unsigned long addr)
|
|||
return addr;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_PREEMPT) && (defined(CONFIG_DEBUG_PREEMPT) || \
|
||||
defined(CONFIG_PREEMPT_TRACER))
|
||||
|
||||
void __kprobes add_preempt_count(int val)
|
||||
{
|
||||
#ifdef CONFIG_DEBUG_PREEMPT
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
* consistent between cpus (never more than 2 jiffies difference).
|
||||
*/
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/hardirq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/ktime.h>
|
||||
|
@ -154,6 +155,17 @@ u64 sched_clock_cpu(int cpu)
|
|||
return sched_clock();
|
||||
|
||||
scd = cpu_sdc(cpu);
|
||||
|
||||
/*
|
||||
* Normally this is not called in NMI context - but if it is,
|
||||
* trying to do any locking here is totally lethal.
|
||||
*/
|
||||
if (unlikely(in_nmi()))
|
||||
return scd->clock;
|
||||
|
||||
if (unlikely(!sched_clock_running))
|
||||
return 0ull;
|
||||
|
||||
WARN_ON_ONCE(!irqs_disabled());
|
||||
now = sched_clock();
|
||||
|
||||
|
|
|
@ -21,8 +21,10 @@
|
|||
#include <linux/freezer.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/tick.h>
|
||||
#include <trace/irq.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
/*
|
||||
|
@ -52,6 +54,11 @@ static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp
|
|||
|
||||
static DEFINE_PER_CPU(struct task_struct *, ksoftirqd);
|
||||
|
||||
char *softirq_to_name[NR_SOFTIRQS] = {
|
||||
"HI", "TIMER", "NET_TX", "NET_RX", "BLOCK",
|
||||
"TASKLET", "SCHED", "HRTIMER", "RCU"
|
||||
};
|
||||
|
||||
/*
|
||||
* we cannot loop indefinitely here to avoid userspace starvation,
|
||||
* but we also don't want to introduce a worst case 1/HZ latency
|
||||
|
@ -79,13 +86,23 @@ static void __local_bh_disable(unsigned long ip)
|
|||
WARN_ON_ONCE(in_irq());
|
||||
|
||||
raw_local_irq_save(flags);
|
||||
add_preempt_count(SOFTIRQ_OFFSET);
|
||||
/*
|
||||
* The preempt tracer hooks into add_preempt_count and will break
|
||||
* lockdep because it calls back into lockdep after SOFTIRQ_OFFSET
|
||||
* is set and before current->softirq_enabled is cleared.
|
||||
* We must manually increment preempt_count here and manually
|
||||
* call the trace_preempt_off later.
|
||||
*/
|
||||
preempt_count() += SOFTIRQ_OFFSET;
|
||||
/*
|
||||
* Were softirqs turned off above:
|
||||
*/
|
||||
if (softirq_count() == SOFTIRQ_OFFSET)
|
||||
trace_softirqs_off(ip);
|
||||
raw_local_irq_restore(flags);
|
||||
|
||||
if (preempt_count() == SOFTIRQ_OFFSET)
|
||||
trace_preempt_off(CALLER_ADDR0, get_parent_ip(CALLER_ADDR1));
|
||||
}
|
||||
#else /* !CONFIG_TRACE_IRQFLAGS */
|
||||
static inline void __local_bh_disable(unsigned long ip)
|
||||
|
@ -169,6 +186,9 @@ EXPORT_SYMBOL(local_bh_enable_ip);
|
|||
*/
|
||||
#define MAX_SOFTIRQ_RESTART 10
|
||||
|
||||
DEFINE_TRACE(softirq_entry);
|
||||
DEFINE_TRACE(softirq_exit);
|
||||
|
||||
asmlinkage void __do_softirq(void)
|
||||
{
|
||||
struct softirq_action *h;
|
||||
|
@ -180,7 +200,7 @@ asmlinkage void __do_softirq(void)
|
|||
account_system_vtime(current);
|
||||
|
||||
__local_bh_disable((unsigned long)__builtin_return_address(0));
|
||||
trace_softirq_enter();
|
||||
lockdep_softirq_enter();
|
||||
|
||||
cpu = smp_processor_id();
|
||||
restart:
|
||||
|
@ -195,12 +215,14 @@ restart:
|
|||
if (pending & 1) {
|
||||
int prev_count = preempt_count();
|
||||
|
||||
trace_softirq_entry(h, softirq_vec);
|
||||
h->action(h);
|
||||
|
||||
trace_softirq_exit(h, softirq_vec);
|
||||
if (unlikely(prev_count != preempt_count())) {
|
||||
printk(KERN_ERR "huh, entered softirq %td %p"
|
||||
printk(KERN_ERR "huh, entered softirq %td %s %p"
|
||||
"with preempt_count %08x,"
|
||||
" exited with %08x?\n", h - softirq_vec,
|
||||
softirq_to_name[h - softirq_vec],
|
||||
h->action, prev_count, preempt_count());
|
||||
preempt_count() = prev_count;
|
||||
}
|
||||
|
@ -220,7 +242,7 @@ restart:
|
|||
if (pending)
|
||||
wakeup_softirqd();
|
||||
|
||||
trace_softirq_exit();
|
||||
lockdep_softirq_exit();
|
||||
|
||||
account_system_vtime(current);
|
||||
_local_bh_enable();
|
||||
|
|
|
@ -9,6 +9,9 @@ config USER_STACKTRACE_SUPPORT
|
|||
config NOP_TRACER
|
||||
bool
|
||||
|
||||
config HAVE_FTRACE_NMI_ENTER
|
||||
bool
|
||||
|
||||
config HAVE_FUNCTION_TRACER
|
||||
bool
|
||||
|
||||
|
@ -31,12 +34,20 @@ config HAVE_FTRACE_MCOUNT_RECORD
|
|||
config HAVE_HW_BRANCH_TRACER
|
||||
bool
|
||||
|
||||
config HAVE_FTRACE_SYSCALLS
|
||||
bool
|
||||
|
||||
config TRACER_MAX_TRACE
|
||||
bool
|
||||
|
||||
config RING_BUFFER
|
||||
bool
|
||||
|
||||
config FTRACE_NMI_ENTER
|
||||
bool
|
||||
depends on HAVE_FTRACE_NMI_ENTER
|
||||
default y
|
||||
|
||||
config TRACING
|
||||
bool
|
||||
select DEBUG_FS
|
||||
|
@ -44,13 +55,29 @@ config TRACING
|
|||
select STACKTRACE if STACKTRACE_SUPPORT
|
||||
select TRACEPOINTS
|
||||
select NOP_TRACER
|
||||
select BINARY_PRINTF
|
||||
|
||||
#
|
||||
# Minimum requirements an architecture has to meet for us to
|
||||
# be able to offer generic tracing facilities:
|
||||
#
|
||||
config TRACING_SUPPORT
|
||||
bool
|
||||
# PPC32 has no irqflags tracing support, but it can use most of the
|
||||
# tracers anyway, they were tested to build and work. Note that new
|
||||
# exceptions to this list aren't welcomed, better implement the
|
||||
# irqflags tracing for your architecture.
|
||||
depends on TRACE_IRQFLAGS_SUPPORT || PPC32
|
||||
depends on STACKTRACE_SUPPORT
|
||||
default y
|
||||
|
||||
if TRACING_SUPPORT
|
||||
|
||||
menu "Tracers"
|
||||
|
||||
config FUNCTION_TRACER
|
||||
bool "Kernel Function Tracer"
|
||||
depends on HAVE_FUNCTION_TRACER
|
||||
depends on DEBUG_KERNEL
|
||||
select FRAME_POINTER
|
||||
select KALLSYMS
|
||||
select TRACING
|
||||
|
@ -83,7 +110,6 @@ config IRQSOFF_TRACER
|
|||
default n
|
||||
depends on TRACE_IRQFLAGS_SUPPORT
|
||||
depends on GENERIC_TIME
|
||||
depends on DEBUG_KERNEL
|
||||
select TRACE_IRQFLAGS
|
||||
select TRACING
|
||||
select TRACER_MAX_TRACE
|
||||
|
@ -106,7 +132,6 @@ config PREEMPT_TRACER
|
|||
default n
|
||||
depends on GENERIC_TIME
|
||||
depends on PREEMPT
|
||||
depends on DEBUG_KERNEL
|
||||
select TRACING
|
||||
select TRACER_MAX_TRACE
|
||||
help
|
||||
|
@ -127,13 +152,13 @@ config SYSPROF_TRACER
|
|||
bool "Sysprof Tracer"
|
||||
depends on X86
|
||||
select TRACING
|
||||
select CONTEXT_SWITCH_TRACER
|
||||
help
|
||||
This tracer provides the trace needed by the 'Sysprof' userspace
|
||||
tool.
|
||||
|
||||
config SCHED_TRACER
|
||||
bool "Scheduling Latency Tracer"
|
||||
depends on DEBUG_KERNEL
|
||||
select TRACING
|
||||
select CONTEXT_SWITCH_TRACER
|
||||
select TRACER_MAX_TRACE
|
||||
|
@ -143,16 +168,30 @@ config SCHED_TRACER
|
|||
|
||||
config CONTEXT_SWITCH_TRACER
|
||||
bool "Trace process context switches"
|
||||
depends on DEBUG_KERNEL
|
||||
select TRACING
|
||||
select MARKERS
|
||||
help
|
||||
This tracer gets called from the context switch and records
|
||||
all switching of tasks.
|
||||
|
||||
config EVENT_TRACER
|
||||
bool "Trace various events in the kernel"
|
||||
select TRACING
|
||||
help
|
||||
This tracer hooks to various trace points in the kernel
|
||||
allowing the user to pick and choose which trace point they
|
||||
want to trace.
|
||||
|
||||
config FTRACE_SYSCALLS
|
||||
bool "Trace syscalls"
|
||||
depends on HAVE_FTRACE_SYSCALLS
|
||||
select TRACING
|
||||
select KALLSYMS
|
||||
help
|
||||
Basic tracer to catch the syscall entry and exit events.
|
||||
|
||||
config BOOT_TRACER
|
||||
bool "Trace boot initcalls"
|
||||
depends on DEBUG_KERNEL
|
||||
select TRACING
|
||||
select CONTEXT_SWITCH_TRACER
|
||||
help
|
||||
|
@ -165,13 +204,11 @@ config BOOT_TRACER
|
|||
representation of the delays during initcalls - but the raw
|
||||
/debug/tracing/trace text output is readable too.
|
||||
|
||||
( Note that tracing self tests can't be enabled if this tracer is
|
||||
selected, because the self-tests are an initcall as well and that
|
||||
would invalidate the boot trace. )
|
||||
You must pass in ftrace=initcall to the kernel command line
|
||||
to enable this on bootup.
|
||||
|
||||
config TRACE_BRANCH_PROFILING
|
||||
bool "Trace likely/unlikely profiler"
|
||||
depends on DEBUG_KERNEL
|
||||
select TRACING
|
||||
help
|
||||
This tracer profiles all the the likely and unlikely macros
|
||||
|
@ -224,7 +261,6 @@ config BRANCH_TRACER
|
|||
|
||||
config POWER_TRACER
|
||||
bool "Trace power consumption behavior"
|
||||
depends on DEBUG_KERNEL
|
||||
depends on X86
|
||||
select TRACING
|
||||
help
|
||||
|
@ -236,7 +272,6 @@ config POWER_TRACER
|
|||
config STACK_TRACER
|
||||
bool "Trace max stack"
|
||||
depends on HAVE_FUNCTION_TRACER
|
||||
depends on DEBUG_KERNEL
|
||||
select FUNCTION_TRACER
|
||||
select STACKTRACE
|
||||
select KALLSYMS
|
||||
|
@ -266,11 +301,66 @@ config HW_BRANCH_TRACER
|
|||
This tracer records all branches on the system in a circular
|
||||
buffer giving access to the last N branches for each cpu.
|
||||
|
||||
config KMEMTRACE
|
||||
bool "Trace SLAB allocations"
|
||||
select TRACING
|
||||
help
|
||||
kmemtrace provides tracing for slab allocator functions, such as
|
||||
kmalloc, kfree, kmem_cache_alloc, kmem_cache_free etc.. Collected
|
||||
data is then fed to the userspace application in order to analyse
|
||||
allocation hotspots, internal fragmentation and so on, making it
|
||||
possible to see how well an allocator performs, as well as debug
|
||||
and profile kernel code.
|
||||
|
||||
This requires an userspace application to use. See
|
||||
Documentation/vm/kmemtrace.txt for more information.
|
||||
|
||||
Saying Y will make the kernel somewhat larger and slower. However,
|
||||
if you disable kmemtrace at run-time or boot-time, the performance
|
||||
impact is minimal (depending on the arch the kernel is built for).
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config WORKQUEUE_TRACER
|
||||
bool "Trace workqueues"
|
||||
select TRACING
|
||||
help
|
||||
The workqueue tracer provides some statistical informations
|
||||
about each cpu workqueue thread such as the number of the
|
||||
works inserted and executed since their creation. It can help
|
||||
to evaluate the amount of work each of them have to perform.
|
||||
For example it can help a developer to decide whether he should
|
||||
choose a per cpu workqueue instead of a singlethreaded one.
|
||||
|
||||
config BLK_DEV_IO_TRACE
|
||||
bool "Support for tracing block io actions"
|
||||
depends on SYSFS
|
||||
depends on BLOCK
|
||||
select RELAY
|
||||
select DEBUG_FS
|
||||
select TRACEPOINTS
|
||||
select TRACING
|
||||
select STACKTRACE
|
||||
help
|
||||
Say Y here if you want to be able to trace the block layer actions
|
||||
on a given queue. Tracing allows you to see any traffic happening
|
||||
on a block device queue. For more information (and the userspace
|
||||
support tools needed), fetch the blktrace tools from:
|
||||
|
||||
git://git.kernel.dk/blktrace.git
|
||||
|
||||
Tracing also is possible using the ftrace interface, e.g.:
|
||||
|
||||
echo 1 > /sys/block/sda/sda1/trace/enable
|
||||
echo blk > /sys/kernel/debug/tracing/current_tracer
|
||||
cat /sys/kernel/debug/tracing/trace_pipe
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config DYNAMIC_FTRACE
|
||||
bool "enable/disable ftrace tracepoints dynamically"
|
||||
depends on FUNCTION_TRACER
|
||||
depends on HAVE_DYNAMIC_FTRACE
|
||||
depends on DEBUG_KERNEL
|
||||
default y
|
||||
help
|
||||
This option will modify all the calls to ftrace dynamically
|
||||
|
@ -296,7 +386,7 @@ config FTRACE_SELFTEST
|
|||
|
||||
config FTRACE_STARTUP_TEST
|
||||
bool "Perform a startup test on ftrace"
|
||||
depends on TRACING && DEBUG_KERNEL && !BOOT_TRACER
|
||||
depends on TRACING
|
||||
select FTRACE_SELFTEST
|
||||
help
|
||||
This option performs a series of startup tests on ftrace. On bootup
|
||||
|
@ -306,7 +396,7 @@ config FTRACE_STARTUP_TEST
|
|||
|
||||
config MMIOTRACE
|
||||
bool "Memory mapped IO tracing"
|
||||
depends on HAVE_MMIOTRACE_SUPPORT && DEBUG_KERNEL && PCI
|
||||
depends on HAVE_MMIOTRACE_SUPPORT && PCI
|
||||
select TRACING
|
||||
help
|
||||
Mmiotrace traces Memory Mapped I/O access and is meant for
|
||||
|
@ -328,3 +418,6 @@ config MMIOTRACE_TEST
|
|||
Say N, unless you absolutely know what you are doing.
|
||||
|
||||
endmenu
|
||||
|
||||
endif # TRACING_SUPPORT
|
||||
|
||||
|
|
|
@ -19,6 +19,10 @@ obj-$(CONFIG_FUNCTION_TRACER) += libftrace.o
|
|||
obj-$(CONFIG_RING_BUFFER) += ring_buffer.o
|
||||
|
||||
obj-$(CONFIG_TRACING) += trace.o
|
||||
obj-$(CONFIG_TRACING) += trace_clock.o
|
||||
obj-$(CONFIG_TRACING) += trace_output.o
|
||||
obj-$(CONFIG_TRACING) += trace_stat.o
|
||||
obj-$(CONFIG_TRACING) += trace_printk.o
|
||||
obj-$(CONFIG_CONTEXT_SWITCH_TRACER) += trace_sched_switch.o
|
||||
obj-$(CONFIG_SYSPROF_TRACER) += trace_sysprof.o
|
||||
obj-$(CONFIG_FUNCTION_TRACER) += trace_functions.o
|
||||
|
@ -33,5 +37,14 @@ obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += trace_functions_graph.o
|
|||
obj-$(CONFIG_TRACE_BRANCH_PROFILING) += trace_branch.o
|
||||
obj-$(CONFIG_HW_BRANCH_TRACER) += trace_hw_branches.o
|
||||
obj-$(CONFIG_POWER_TRACER) += trace_power.o
|
||||
obj-$(CONFIG_KMEMTRACE) += kmemtrace.o
|
||||
obj-$(CONFIG_WORKQUEUE_TRACER) += trace_workqueue.o
|
||||
obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o
|
||||
obj-$(CONFIG_EVENT_TRACER) += trace_events.o
|
||||
obj-$(CONFIG_EVENT_TRACER) += events.o
|
||||
obj-$(CONFIG_EVENT_TRACER) += trace_export.o
|
||||
obj-$(CONFIG_FTRACE_SYSCALLS) += trace_syscalls.o
|
||||
obj-$(CONFIG_EVENT_PROFILE) += trace_event_profile.o
|
||||
obj-$(CONFIG_EVENT_TRACER) += trace_events_filter.o
|
||||
|
||||
libftrace-y := ftrace.o
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue