Commit a5a2bad5 authored by Ingo Molnar's avatar Ingo Molnar

Merge branch 'tip/perf/core' of...

Merge branch 'tip/perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-trace into perf/core
parents d0303d71 46eb3b64
...@@ -591,6 +591,11 @@ KBUILD_CFLAGS += $(call cc-option,-fno-strict-overflow) ...@@ -591,6 +591,11 @@ KBUILD_CFLAGS += $(call cc-option,-fno-strict-overflow)
# conserve stack if available # conserve stack if available
KBUILD_CFLAGS += $(call cc-option,-fconserve-stack) KBUILD_CFLAGS += $(call cc-option,-fconserve-stack)
# check for 'asm goto'
ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC)), y)
KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO
endif
# Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments # Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments
# But warn user when we do so # But warn user when we do so
warn-assign = \ warn-assign = \
......
...@@ -158,4 +158,7 @@ config HAVE_PERF_EVENTS_NMI ...@@ -158,4 +158,7 @@ config HAVE_PERF_EVENTS_NMI
subsystem. Also has support for calculating CPU cycle events subsystem. Also has support for calculating CPU cycle events
to determine how many clock cycles in a given period. to determine how many clock cycles in a given period.
config HAVE_ARCH_JUMP_LABEL
bool
source "kernel/gcov/Kconfig" source "kernel/gcov/Kconfig"
...@@ -30,6 +30,7 @@ config SPARC ...@@ -30,6 +30,7 @@ config SPARC
select PERF_USE_VMALLOC select PERF_USE_VMALLOC
select HAVE_DMA_ATTRS select HAVE_DMA_ATTRS
select HAVE_DMA_API_DEBUG select HAVE_DMA_API_DEBUG
select HAVE_ARCH_JUMP_LABEL
config SPARC32 config SPARC32
def_bool !64BIT def_bool !64BIT
......
#ifndef _ASM_SPARC_JUMP_LABEL_H
#define _ASM_SPARC_JUMP_LABEL_H
#ifdef __KERNEL__
#include <linux/types.h>
#include <asm/system.h>
#define JUMP_LABEL_NOP_SIZE 4
#define JUMP_LABEL(key, label) \
do { \
asm goto("1:\n\t" \
"nop\n\t" \
"nop\n\t" \
".pushsection __jump_table, \"a\"\n\t"\
".word 1b, %l[" #label "], %c0\n\t" \
".popsection \n\t" \
: : "i" (key) : : label);\
} while (0)
#endif /* __KERNEL__ */
typedef u32 jump_label_t;
struct jump_entry {
jump_label_t code;
jump_label_t target;
jump_label_t key;
};
#endif
...@@ -119,3 +119,5 @@ obj-$(CONFIG_COMPAT) += $(audit--y) ...@@ -119,3 +119,5 @@ obj-$(CONFIG_COMPAT) += $(audit--y)
pc--$(CONFIG_PERF_EVENTS) := perf_event.o pc--$(CONFIG_PERF_EVENTS) := perf_event.o
obj-$(CONFIG_SPARC64) += $(pc--y) obj-$(CONFIG_SPARC64) += $(pc--y)
obj-$(CONFIG_SPARC64) += jump_label.o
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/cpu.h>
#include <linux/jump_label.h>
#include <linux/memory.h>
#ifdef HAVE_JUMP_LABEL
void arch_jump_label_transform(struct jump_entry *entry,
enum jump_label_type type)
{
u32 val;
u32 *insn = (u32 *) (unsigned long) entry->code;
if (type == JUMP_LABEL_ENABLE) {
s32 off = (s32)entry->target - (s32)entry->code;
#ifdef CONFIG_SPARC64
/* ba,pt %xcc, . + (off << 2) */
val = 0x10680000 | ((u32) off >> 2);
#else
/* ba . + (off << 2) */
val = 0x10800000 | ((u32) off >> 2);
#endif
} else {
val = 0x01000000;
}
get_online_cpus();
mutex_lock(&text_mutex);
*insn = val;
flushi(insn);
mutex_unlock(&text_mutex);
put_online_cpus();
}
void arch_jump_label_text_poke_early(jump_label_t addr)
{
u32 *insn_p = (u32 *) (unsigned long) addr;
*insn_p = 0x01000000;
flushi(insn_p);
}
#endif
...@@ -18,6 +18,9 @@ ...@@ -18,6 +18,9 @@
#include <asm/spitfire.h> #include <asm/spitfire.h>
#ifdef CONFIG_SPARC64 #ifdef CONFIG_SPARC64
#include <linux/jump_label.h>
static void *module_map(unsigned long size) static void *module_map(unsigned long size)
{ {
struct vm_struct *area; struct vm_struct *area;
...@@ -227,6 +230,9 @@ int module_finalize(const Elf_Ehdr *hdr, ...@@ -227,6 +230,9 @@ int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs, const Elf_Shdr *sechdrs,
struct module *me) struct module *me)
{ {
/* make jump label nops */
jump_label_apply_nops(me);
/* Cheetah's I-cache is fully coherent. */ /* Cheetah's I-cache is fully coherent. */
if (tlb_type == spitfire) { if (tlb_type == spitfire) {
unsigned long va; unsigned long va;
......
...@@ -59,6 +59,7 @@ config X86 ...@@ -59,6 +59,7 @@ config X86
select ANON_INODES select ANON_INODES
select HAVE_ARCH_KMEMCHECK select HAVE_ARCH_KMEMCHECK
select HAVE_USER_RETURN_NOTIFIER select HAVE_USER_RETURN_NOTIFIER
select HAVE_ARCH_JUMP_LABEL
config INSTRUCTION_DECODER config INSTRUCTION_DECODER
def_bool (KPROBES || PERF_EVENTS) def_bool (KPROBES || PERF_EVENTS)
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/stringify.h> #include <linux/stringify.h>
#include <linux/jump_label.h>
#include <asm/asm.h> #include <asm/asm.h>
/* /*
...@@ -160,6 +161,8 @@ static inline void apply_paravirt(struct paravirt_patch_site *start, ...@@ -160,6 +161,8 @@ static inline void apply_paravirt(struct paravirt_patch_site *start,
#define __parainstructions_end NULL #define __parainstructions_end NULL
#endif #endif
extern void *text_poke_early(void *addr, const void *opcode, size_t len);
/* /*
* Clear and restore the kernel write-protection flag on the local CPU. * Clear and restore the kernel write-protection flag on the local CPU.
* Allows the kernel to edit read-only pages. * Allows the kernel to edit read-only pages.
...@@ -180,4 +183,12 @@ static inline void apply_paravirt(struct paravirt_patch_site *start, ...@@ -180,4 +183,12 @@ static inline void apply_paravirt(struct paravirt_patch_site *start,
extern void *text_poke(void *addr, const void *opcode, size_t len); extern void *text_poke(void *addr, const void *opcode, size_t len);
extern void *text_poke_smp(void *addr, const void *opcode, size_t len); extern void *text_poke_smp(void *addr, const void *opcode, size_t len);
#if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL)
#define IDEAL_NOP_SIZE_5 5
extern unsigned char ideal_nop5[IDEAL_NOP_SIZE_5];
extern void arch_init_ideal_nop5(void);
#else
static inline void arch_init_ideal_nop5(void) {}
#endif
#endif /* _ASM_X86_ALTERNATIVE_H */ #endif /* _ASM_X86_ALTERNATIVE_H */
#ifndef _ASM_X86_JUMP_LABEL_H
#define _ASM_X86_JUMP_LABEL_H
#ifdef __KERNEL__
#include <linux/types.h>
#include <asm/nops.h>
#define JUMP_LABEL_NOP_SIZE 5
# define JUMP_LABEL_INITIAL_NOP ".byte 0xe9 \n\t .long 0\n\t"
# define JUMP_LABEL(key, label) \
do { \
asm goto("1:" \
JUMP_LABEL_INITIAL_NOP \
".pushsection __jump_table, \"a\" \n\t"\
_ASM_PTR "1b, %l[" #label "], %c0 \n\t" \
".popsection \n\t" \
: : "i" (key) : : label); \
} while (0)
#endif /* __KERNEL__ */
#ifdef CONFIG_X86_64
typedef u64 jump_label_t;
#else
typedef u32 jump_label_t;
#endif
struct jump_entry {
jump_label_t code;
jump_label_t target;
jump_label_t key;
};
#endif
...@@ -32,7 +32,7 @@ GCOV_PROFILE_paravirt.o := n ...@@ -32,7 +32,7 @@ GCOV_PROFILE_paravirt.o := n
obj-y := process_$(BITS).o signal.o entry_$(BITS).o obj-y := process_$(BITS).o signal.o entry_$(BITS).o
obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
obj-y += time.o ioport.o ldt.o dumpstack.o obj-y += time.o ioport.o ldt.o dumpstack.o
obj-y += setup.o x86_init.o i8259.o irqinit.o obj-y += setup.o x86_init.o i8259.o irqinit.o jump_label.o
obj-$(CONFIG_X86_VISWS) += visws_quirks.o obj-$(CONFIG_X86_VISWS) += visws_quirks.o
obj-$(CONFIG_X86_32) += probe_roms_32.o obj-$(CONFIG_X86_32) += probe_roms_32.o
obj-$(CONFIG_X86_32) += sys_i386_32.o i386_ksyms_32.o obj-$(CONFIG_X86_32) += sys_i386_32.o i386_ksyms_32.o
......
...@@ -195,7 +195,7 @@ static void __init_or_module add_nops(void *insns, unsigned int len) ...@@ -195,7 +195,7 @@ static void __init_or_module add_nops(void *insns, unsigned int len)
extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
extern s32 __smp_locks[], __smp_locks_end[]; extern s32 __smp_locks[], __smp_locks_end[];
static void *text_poke_early(void *addr, const void *opcode, size_t len); void *text_poke_early(void *addr, const void *opcode, size_t len);
/* Replace instructions with better alternatives for this CPU type. /* Replace instructions with better alternatives for this CPU type.
This runs before SMP is initialized to avoid SMP problems with This runs before SMP is initialized to avoid SMP problems with
...@@ -522,7 +522,7 @@ void __init alternative_instructions(void) ...@@ -522,7 +522,7 @@ void __init alternative_instructions(void)
* instructions. And on the local CPU you need to be protected again NMI or MCE * instructions. And on the local CPU you need to be protected again NMI or MCE
* handlers seeing an inconsistent instruction while you patch. * handlers seeing an inconsistent instruction while you patch.
*/ */
static void *__init_or_module text_poke_early(void *addr, const void *opcode, void *__init_or_module text_poke_early(void *addr, const void *opcode,
size_t len) size_t len)
{ {
unsigned long flags; unsigned long flags;
...@@ -641,3 +641,67 @@ void *__kprobes text_poke_smp(void *addr, const void *opcode, size_t len) ...@@ -641,3 +641,67 @@ void *__kprobes text_poke_smp(void *addr, const void *opcode, size_t len)
return addr; return addr;
} }
#if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL)
unsigned char ideal_nop5[IDEAL_NOP_SIZE_5];
void __init arch_init_ideal_nop5(void)
{
extern const unsigned char ftrace_test_p6nop[];
extern const unsigned char ftrace_test_nop5[];
extern const unsigned char ftrace_test_jmp[];
int faulted = 0;
/*
* There is no good nop for all x86 archs.
* We will default to using the P6_NOP5, but first we
* will test to make sure that the nop will actually
* work on this CPU. If it faults, we will then
* go to a lesser efficient 5 byte nop. If that fails
* we then just use a jmp as our nop. This isn't the most
* efficient nop, but we can not use a multi part nop
* since we would then risk being preempted in the middle
* of that nop, and if we enabled tracing then, it might
* cause a system crash.
*
* TODO: check the cpuid to determine the best nop.
*/
asm volatile (
"ftrace_test_jmp:"
"jmp ftrace_test_p6nop\n"
"nop\n"
"nop\n"
"nop\n" /* 2 byte jmp + 3 bytes */
"ftrace_test_p6nop:"
P6_NOP5
"jmp 1f\n"
"ftrace_test_nop5:"
".byte 0x66,0x66,0x66,0x66,0x90\n"
"1:"
".section .fixup, \"ax\"\n"
"2: movl $1, %0\n"
" jmp ftrace_test_nop5\n"
"3: movl $2, %0\n"
" jmp 1b\n"
".previous\n"
_ASM_EXTABLE(ftrace_test_p6nop, 2b)
_ASM_EXTABLE(ftrace_test_nop5, 3b)
: "=r"(faulted) : "0" (faulted));
switch (faulted) {
case 0:
pr_info("converting mcount calls to 0f 1f 44 00 00\n");
memcpy(ideal_nop5, ftrace_test_p6nop, IDEAL_NOP_SIZE_5);
break;
case 1:
pr_info("converting mcount calls to 66 66 66 66 90\n");
memcpy(ideal_nop5, ftrace_test_nop5, IDEAL_NOP_SIZE_5);
break;
case 2:
pr_info("converting mcount calls to jmp . + 5\n");
memcpy(ideal_nop5, ftrace_test_jmp, IDEAL_NOP_SIZE_5);
break;
}
}
#endif
...@@ -257,14 +257,9 @@ do_ftrace_mod_code(unsigned long ip, void *new_code) ...@@ -257,14 +257,9 @@ do_ftrace_mod_code(unsigned long ip, void *new_code)
return mod_code_status; return mod_code_status;
} }
static unsigned char ftrace_nop[MCOUNT_INSN_SIZE];
static unsigned char *ftrace_nop_replace(void) static unsigned char *ftrace_nop_replace(void)
{ {
return ftrace_nop; return ideal_nop5;
} }
static int static int
...@@ -338,62 +333,6 @@ int ftrace_update_ftrace_func(ftrace_func_t func) ...@@ -338,62 +333,6 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
int __init ftrace_dyn_arch_init(void *data) int __init ftrace_dyn_arch_init(void *data)
{ {
extern const unsigned char ftrace_test_p6nop[];
extern const unsigned char ftrace_test_nop5[];
extern const unsigned char ftrace_test_jmp[];
int faulted = 0;
/*
* There is no good nop for all x86 archs.
* We will default to using the P6_NOP5, but first we
* will test to make sure that the nop will actually
* work on this CPU. If it faults, we will then
* go to a lesser efficient 5 byte nop. If that fails
* we then just use a jmp as our nop. This isn't the most
* efficient nop, but we can not use a multi part nop
* since we would then risk being preempted in the middle
* of that nop, and if we enabled tracing then, it might
* cause a system crash.
*
* TODO: check the cpuid to determine the best nop.
*/
asm volatile (
"ftrace_test_jmp:"
"jmp ftrace_test_p6nop\n"
"nop\n"
"nop\n"
"nop\n" /* 2 byte jmp + 3 bytes */
"ftrace_test_p6nop:"
P6_NOP5
"jmp 1f\n"
"ftrace_test_nop5:"
".byte 0x66,0x66,0x66,0x66,0x90\n"
"1:"
".section .fixup, \"ax\"\n"
"2: movl $1, %0\n"
" jmp ftrace_test_nop5\n"
"3: movl $2, %0\n"
" jmp 1b\n"
".previous\n"
_ASM_EXTABLE(ftrace_test_p6nop, 2b)
_ASM_EXTABLE(ftrace_test_nop5, 3b)
: "=r"(faulted) : "0" (faulted));
switch (faulted) {
case 0:
pr_info("converting mcount calls to 0f 1f 44 00 00\n");
memcpy(ftrace_nop, ftrace_test_p6nop, MCOUNT_INSN_SIZE);
break;
case 1:
pr_info("converting mcount calls to 66 66 66 66 90\n");
memcpy(ftrace_nop, ftrace_test_nop5, MCOUNT_INSN_SIZE);
break;
case 2:
pr_info("converting mcount calls to jmp . + 5\n");
memcpy(ftrace_nop, ftrace_test_jmp, MCOUNT_INSN_SIZE);
break;
}
/* The return code is retured via data */ /* The return code is retured via data */
*(unsigned long *)data = 0; *(unsigned long *)data = 0;
......
/*
* jump label x86 support
*
* Copyright (C) 2009 Jason Baron <jbaron@redhat.com>
*
*/
#include <linux/jump_label.h>
#include <linux/memory.h>
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/jhash.h>
#include <linux/cpu.h>
#include <asm/kprobes.h>
#include <asm/alternative.h>
#ifdef HAVE_JUMP_LABEL
union jump_code_union {
char code[JUMP_LABEL_NOP_SIZE];
struct {
char jump;
int offset;
} __attribute__((packed));
};
void arch_jump_label_transform(struct jump_entry *entry,
enum jump_label_type type)
{
union jump_code_union code;
if (type == JUMP_LABEL_ENABLE) {
code.jump = 0xe9;
code.offset = entry->target -
(entry->code + JUMP_LABEL_NOP_SIZE);
} else
memcpy(&code, ideal_nop5, JUMP_LABEL_NOP_SIZE);
get_online_cpus();
mutex_lock(&text_mutex);
text_poke_smp((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE);
mutex_unlock(&text_mutex);
put_online_cpus();
}
void arch_jump_label_text_poke_early(jump_label_t addr)
{
text_poke_early((void *)addr, ideal_nop5, JUMP_LABEL_NOP_SIZE);
}
#endif
...@@ -1218,7 +1218,8 @@ static int __kprobes copy_optimized_instructions(u8 *dest, u8 *src) ...@@ -1218,7 +1218,8 @@ static int __kprobes copy_optimized_instructions(u8 *dest, u8 *src)
} }
/* Check whether the address range is reserved */ /* Check whether the address range is reserved */
if (ftrace_text_reserved(src, src + len - 1) || if (ftrace_text_reserved(src, src + len - 1) ||
alternatives_text_reserved(src, src + len - 1)) alternatives_text_reserved(src, src + len - 1) ||
jump_label_text_reserved(src, src + len - 1))
return -EBUSY; return -EBUSY;
return len; return len;
......
...@@ -239,6 +239,9 @@ int module_finalize(const Elf_Ehdr *hdr, ...@@ -239,6 +239,9 @@ int module_finalize(const Elf_Ehdr *hdr,
apply_paravirt(pseg, pseg + para->sh_size); apply_paravirt(pseg, pseg + para->sh_size);
} }
/* make jump label nops */
jump_label_apply_nops(me);
return module_bug_finalize(hdr, sechdrs, me); return module_bug_finalize(hdr, sechdrs, me);
} }
......
...@@ -112,6 +112,7 @@ ...@@ -112,6 +112,7 @@
#include <asm/numa_64.h> #include <asm/numa_64.h>
#endif #endif
#include <asm/mce.h> #include <asm/mce.h>
#include <asm/alternative.h>
/* /*
* end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries. * end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries.
...@@ -726,6 +727,7 @@ void __init setup_arch(char **cmdline_p) ...@@ -726,6 +727,7 @@ void __init setup_arch(char **cmdline_p)
{ {
int acpi = 0; int acpi = 0;
int k8 = 0; int k8 = 0;
unsigned long flags;
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data)); memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
...@@ -1071,6 +1073,10 @@ void __init setup_arch(char **cmdline_p) ...@@ -1071,6 +1073,10 @@ void __init setup_arch(char **cmdline_p)
x86_init.oem.banner(); x86_init.oem.banner();
mcheck_init(); mcheck_init();
local_irq_save(flags);
arch_init_ideal_nop5();
local_irq_restore(flags);
} }
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
......
...@@ -220,6 +220,8 @@ ...@@ -220,6 +220,8 @@
\ \
BUG_TABLE \ BUG_TABLE \
\ \
JUMP_TABLE \
\
/* PCI quirks */ \ /* PCI quirks */ \
.pci_fixup : AT(ADDR(.pci_fixup) - LOAD_OFFSET) { \ .pci_fixup : AT(ADDR(.pci_fixup) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start_pci_fixups_early) = .; \ VMLINUX_SYMBOL(__start_pci_fixups_early) = .; \
...@@ -563,6 +565,14 @@ ...@@ -563,6 +565,14 @@
#define BUG_TABLE #define BUG_TABLE
#endif #endif
#define JUMP_TABLE \
. = ALIGN(8); \
__jump_table : AT(ADDR(__jump_table) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___jump_table) = .; \
*(__jump_table) \
VMLINUX_SYMBOL(__stop___jump_table) = .; \
}
#ifdef CONFIG_PM_TRACE #ifdef CONFIG_PM_TRACE
#define TRACEDATA \ #define TRACEDATA \
. = ALIGN(4); \ . = ALIGN(4); \
......
#ifndef _DYNAMIC_DEBUG_H #ifndef _DYNAMIC_DEBUG_H
#define _DYNAMIC_DEBUG_H #define _DYNAMIC_DEBUG_H
#include <linux/jump_label.h>
/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which /* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which
* bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
* use independent hash functions, to reduce the chance of false positives. * use independent hash functions, to reduce the chance of false positives.
...@@ -22,8 +24,6 @@ struct _ddebug { ...@@ -22,8 +24,6 @@ struct _ddebug {
const char *function; const char *function;
const char *filename; const char *filename;
const char *format; const char *format;
char primary_hash;
char secondary_hash;
unsigned int lineno:24; unsigned int lineno:24;
/* /*
* The flags field controls the behaviour at the callsite. * The flags field controls the behaviour at the callsite.
...@@ -33,6 +33,7 @@ struct _ddebug { ...@@ -33,6 +33,7 @@ struct _ddebug {
#define _DPRINTK_FLAGS_PRINT (1<<0) /* printk() a message using the format */ #define _DPRINTK_FLAGS_PRINT (1<<0) /* printk() a message using the format */
#define _DPRINTK_FLAGS_DEFAULT 0 #define _DPRINTK_FLAGS_DEFAULT 0
unsigned int flags:8; unsigned int flags:8;
char enabled;
} __attribute__((aligned(8))); } __attribute__((aligned(8)));
...@@ -42,33 +43,35 @@ int ddebug_add_module(struct _ddebug *tab, unsigned int n, ...@@ -42,33 +43,35 @@ int ddebug_add_module(struct _ddebug *tab, unsigned int n,
#if defined(CONFIG_DYNAMIC_DEBUG) #if defined(CONFIG_DYNAMIC_DEBUG)
extern int ddebug_remove_module(const char *mod_name); extern int ddebug_remove_module(const char *mod_name);
#define __dynamic_dbg_enabled(dd) ({ \
int __ret = 0; \
if (unlikely((dynamic_debug_enabled & (1LL << DEBUG_HASH)) && \
(dynamic_debug_enabled2 & (1LL << DEBUG_HASH2)))) \
if (unlikely(dd.flags)) \
__ret = 1; \
__ret; })
#define dynamic_pr_debug(fmt, ...) do { \ #define dynamic_pr_debug(fmt, ...) do { \
__label__ do_printk; \
__label__ out; \
static struct _ddebug descriptor \ static struct _ddebug descriptor \
__used \ __used \
__attribute__((section("__verbose"), aligned(8))) = \ __attribute__((section("__verbose"), aligned(8))) = \
{ KBUILD_MODNAME, __func__, __FILE__, fmt, DEBUG_HASH, \ { KBUILD_MODNAME, __func__, __FILE__, fmt, __LINE__, \
DEBUG_HASH2, __LINE__, _DPRINTK_FLAGS_DEFAULT }; \ _DPRINTK_FLAGS_DEFAULT }; \
if (__dynamic_dbg_enabled(descriptor)) \ JUMP_LABEL(&descriptor.enabled, do_printk); \
printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \ goto out; \
do_printk: \
printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \
out: ; \
} while (0) } while (0)
#define dynamic_dev_dbg(dev, fmt, ...) do { \ #define dynamic_dev_dbg(dev, fmt, ...) do { \
__label__ do_printk; \
__label__ out; \
static struct _ddebug descriptor \ static struct _ddebug descriptor \
__used \ __used \
__attribute__((section("__verbose"), aligned(8))) = \ __attribute__((section("__verbose"), aligned(8))) = \
{ KBUILD_MODNAME, __func__, __FILE__, fmt, DEBUG_HASH, \ { KBUILD_MODNAME, __func__, __FILE__, fmt, __LINE__, \
DEBUG_HASH2, __LINE__, _DPRINTK_FLAGS_DEFAULT }; \ _DPRINTK_FLAGS_DEFAULT }; \
if (__dynamic_dbg_enabled(descriptor)) \ JUMP_LABEL(&descriptor.enabled, do_printk); \
dev_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__); \ goto out; \
do_printk: \
dev_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__); \
out: ; \
} while (0) } while (0)
#else #else
......
#ifndef _LINUX_JUMP_LABEL_H
#define _LINUX_JUMP_LABEL_H
#if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_HAVE_ARCH_JUMP_LABEL)
# include <asm/jump_label.h>
# define HAVE_JUMP_LABEL
#endif
enum jump_label_type {
JUMP_LABEL_ENABLE,
JUMP_LABEL_DISABLE
};
struct module;
#ifdef HAVE_JUMP_LABEL
extern struct jump_entry __start___jump_table[];
extern struct jump_entry __stop___jump_table[];
extern void arch_jump_label_transform(struct jump_entry *entry,
enum jump_label_type type);
extern void arch_jump_label_text_poke_early(jump_label_t addr);
extern void jump_label_update(unsigned long key, enum jump_label_type type);
extern void jump_label_apply_nops(struct module *mod);
extern int jump_label_text_reserved(void *start, void *end);
#define enable_jump_label(key) \
jump_label_update((unsigned long)key, JUMP_LABEL_ENABLE);
#define disable_jump_label(key) \
jump_label_update((unsigned long)key, JUMP_LABEL_DISABLE);
#else
#define JUMP_LABEL(key, label) \
do { \
if (unlikely(*key)) \
goto label; \
} while (0)
#define enable_jump_label(cond_var) \
do { \
*(cond_var) = 1; \
} while (0)
#define disable_jump_label(cond_var) \
do { \
*(cond_var) = 0; \
} while (0)
static inline int jump_label_apply_nops(struct module *mod)
{
return 0;
}
static inline int jump_label_text_reserved(void *start, void *end)
{
return 0;
}
#endif
#endif
...@@ -350,7 +350,10 @@ struct module ...@@ -350,7 +350,10 @@ struct module
struct tracepoint *tracepoints; struct tracepoint *tracepoints;
unsigned int num_tracepoints; unsigned int num_tracepoints;
#endif #endif
#ifdef HAVE_JUMP_LABEL
struct jump_entry *jump_entries;
unsigned int num_jump_entries;
#endif
#ifdef CONFIG_TRACING #ifdef CONFIG_TRACING
const char **trace_bprintk_fmt_start; const char **trace_bprintk_fmt_start;
unsigned int num_trace_bprintk_fmt; unsigned int num_trace_bprintk_fmt;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/jump_label.h>
struct module; struct module;
struct tracepoint; struct tracepoint;
...@@ -145,7 +146,9 @@ static inline void tracepoint_update_probe_range(struct tracepoint *begin, ...@@ -145,7 +146,9 @@ static inline void tracepoint_update_probe_range(struct tracepoint *begin,
extern struct tracepoint __tracepoint_##name; \ extern struct tracepoint __tracepoint_##name; \
static inline void trace_##name(proto) \ static inline void trace_##name(proto) \
{ \ { \
if (unlikely(__tracepoint_##name.state)) \ JUMP_LABEL(&__tracepoint_##name.state, do_trace); \
return; \
do_trace: \
__DO_TRACE(&__tracepoint_##name, \ __DO_TRACE(&__tracepoint_##name, \
TP_PROTO(data_proto), \ TP_PROTO(data_proto), \
TP_ARGS(data_args)); \ TP_ARGS(data_args)); \
......
...@@ -10,7 +10,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o \ ...@@ -10,7 +10,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o \
kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \ hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
notifier.o ksysfs.o pm_qos_params.o sched_clock.o cred.o \ notifier.o ksysfs.o pm_qos_params.o sched_clock.o cred.o \
async.o range.o async.o range.o jump_label.o
obj-$(CONFIG_HAVE_EARLY_RES) += early_res.o obj-$(CONFIG_HAVE_EARLY_RES) += early_res.o
obj-y += groups.o obj-y += groups.o
......
This diff is collapsed.
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include <linux/memory.h> #include <linux/memory.h>
#include <linux/ftrace.h> #include <linux/ftrace.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/jump_label.h>
#include <asm-generic/sections.h> #include <asm-generic/sections.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
...@@ -1146,7 +1147,8 @@ int __kprobes register_kprobe(struct kprobe *p) ...@@ -1146,7 +1147,8 @@ int __kprobes register_kprobe(struct kprobe *p)
preempt_disable(); preempt_disable();
if (!kernel_text_address((unsigned long) p->addr) || if (!kernel_text_address((unsigned long) p->addr) ||
in_kprobes_functions((unsigned long) p->addr) || in_kprobes_functions((unsigned long) p->addr) ||
ftrace_text_reserved(p->addr, p->addr)) { ftrace_text_reserved(p->addr, p->addr) ||
jump_label_text_reserved(p->addr, p->addr)) {
preempt_enable(); preempt_enable();
return -EINVAL; return -EINVAL;
} }
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
#include <linux/async.h> #include <linux/async.h>
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/kmemleak.h> #include <linux/kmemleak.h>
#include <linux/jump_label.h>
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include <trace/events/module.h> #include <trace/events/module.h>
...@@ -2308,6 +2309,11 @@ static void find_module_sections(struct module *mod, struct load_info *info) ...@@ -2308,6 +2309,11 @@ static void find_module_sections(struct module *mod, struct load_info *info)
sizeof(*mod->tracepoints), sizeof(*mod->tracepoints),
&mod->num_tracepoints); &mod->num_tracepoints);
#endif #endif
#ifdef HAVE_JUMP_LABEL
mod->jump_entries = section_objs(info, "__jump_table",
sizeof(*mod->jump_entries),
&mod->num_jump_entries);
#endif
#ifdef CONFIG_EVENT_TRACING #ifdef CONFIG_EVENT_TRACING
mod->trace_events = section_objs(info, "_ftrace_events", mod->trace_events = section_objs(info, "_ftrace_events",
sizeof(*mod->trace_events), sizeof(*mod->trace_events),
......
...@@ -263,6 +263,11 @@ int __init trace_workqueue_early_init(void) ...@@ -263,6 +263,11 @@ int __init trace_workqueue_early_init(void)
{ {
int ret, cpu; int ret, cpu;
for_each_possible_cpu(cpu) {
spin_lock_init(&workqueue_cpu_stat(cpu)->lock);
INIT_LIST_HEAD(&workqueue_cpu_stat(cpu)->list);
}
ret = register_trace_workqueue_insertion(probe_workqueue_insertion, NULL); ret = register_trace_workqueue_insertion(probe_workqueue_insertion, NULL);
if (ret) if (ret)
goto out; goto out;
...@@ -279,11 +284,6 @@ int __init trace_workqueue_early_init(void) ...@@ -279,11 +284,6 @@ int __init trace_workqueue_early_init(void)
if (ret) if (ret)
goto no_creation; goto no_creation;
for_each_possible_cpu(cpu) {
spin_lock_init(&workqueue_cpu_stat(cpu)->lock);
INIT_LIST_HEAD(&workqueue_cpu_stat(cpu)->list);
}
return 0; return 0;
no_creation: no_creation:
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/jump_label.h>
extern struct tracepoint __start___tracepoints[]; extern struct tracepoint __start___tracepoints[];
extern struct tracepoint __stop___tracepoints[]; extern struct tracepoint __stop___tracepoints[];
...@@ -263,7 +264,13 @@ static void set_tracepoint(struct tracepoint_entry **entry, ...@@ -263,7 +264,13 @@ static void set_tracepoint(struct tracepoint_entry **entry,
* is used. * is used.
*/ */
rcu_assign_pointer(elem->funcs, (*entry)->funcs); rcu_assign_pointer(elem->funcs, (*entry)->funcs);
elem->state = active; if (!elem->state && active) {
enable_jump_label(&elem->state);
elem->state = active;
} else if (elem->state && !active) {
disable_jump_label(&elem->state);
elem->state = active;
}
} }
/* /*
...@@ -277,7 +284,10 @@ static void disable_tracepoint(struct tracepoint *elem) ...@@ -277,7 +284,10 @@ static void disable_tracepoint(struct tracepoint *elem)
if (elem->unregfunc && elem->state) if (elem->unregfunc && elem->state)
elem->unregfunc(); elem->unregfunc();
elem->state = 0; if (elem->state) {
disable_jump_label(&elem->state);
elem->state = 0;
}
rcu_assign_pointer(elem->funcs, NULL); rcu_assign_pointer(elem->funcs, NULL);
} }
......
...@@ -26,19 +26,11 @@ ...@@ -26,19 +26,11 @@
#include <linux/dynamic_debug.h> #include <linux/dynamic_debug.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/jump_label.h>
extern struct _ddebug __start___verbose[]; extern struct _ddebug __start___verbose[];
extern struct _ddebug __stop___verbose[]; extern struct _ddebug __stop___verbose[];
/* dynamic_debug_enabled, and dynamic_debug_enabled2 are bitmasks in which
* bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
* use independent hash functions, to reduce the chance of false positives.
*/
long long dynamic_debug_enabled;
EXPORT_SYMBOL_GPL(dynamic_debug_enabled);
long long dynamic_debug_enabled2;
EXPORT_SYMBOL_GPL(dynamic_debug_enabled2);
struct ddebug_table { struct ddebug_table {
struct list_head link; struct list_head link;
char *mod_name; char *mod_name;
...@@ -87,26 +79,6 @@ static char *ddebug_describe_flags(struct _ddebug *dp, char *buf, ...@@ -87,26 +79,6 @@ static char *ddebug_describe_flags(struct _ddebug *dp, char *buf,
return buf; return buf;
} }
/*
* must be called with ddebug_lock held
*/
static int disabled_hash(char hash, bool first_table)
{
struct ddebug_table *dt;
char table_hash_value;
list_for_each_entry(dt, &ddebug_tables, link) {
if (first_table)
table_hash_value = dt->ddebugs->primary_hash;
else
table_hash_value = dt->ddebugs->secondary_hash;
if (dt->num_enabled && (hash == table_hash_value))
return 0;
}
return 1;
}
/* /*
* Search the tables for _ddebug's which match the given * Search the tables for _ddebug's which match the given
* `query' and apply the `flags' and `mask' to them. Tells * `query' and apply the `flags' and `mask' to them. Tells
...@@ -170,17 +142,9 @@ static void ddebug_change(const struct ddebug_query *query, ...@@ -170,17 +142,9 @@ static void ddebug_change(const struct ddebug_query *query,
dt->num_enabled++; dt->num_enabled++;
dp->flags = newflags; dp->flags = newflags;
if (newflags) { if (newflags) {
dynamic_debug_enabled |= enable_jump_label(&dp->enabled);
(1LL << dp->primary_hash);
dynamic_debug_enabled2 |=
(1LL << dp->secondary_hash);
} else { } else {
if (disabled_hash(dp->primary_hash, true)) disable_jump_label(&dp->enabled);
dynamic_debug_enabled &=
~(1LL << dp->primary_hash);
if (disabled_hash(dp->secondary_hash, false))
dynamic_debug_enabled2 &=
~(1LL << dp->secondary_hash);
} }
if (verbose) if (verbose)
printk(KERN_INFO printk(KERN_INFO
......
...@@ -101,14 +101,6 @@ basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))" ...@@ -101,14 +101,6 @@ basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
modname_flags = $(if $(filter 1,$(words $(modname))),\ modname_flags = $(if $(filter 1,$(words $(modname))),\
-D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))") -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
#hash values
ifdef CONFIG_DYNAMIC_DEBUG
debug_flags = -D"DEBUG_HASH=$(shell ./scripts/basic/hash djb2 $(@D)$(modname))"\
-D"DEBUG_HASH2=$(shell ./scripts/basic/hash r5 $(@D)$(modname))"
else
debug_flags =
endif
orig_c_flags = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(KBUILD_SUBDIR_CCFLAGS) \ orig_c_flags = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(KBUILD_SUBDIR_CCFLAGS) \
$(ccflags-y) $(CFLAGS_$(basetarget).o) $(ccflags-y) $(CFLAGS_$(basetarget).o)
_c_flags = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags)) _c_flags = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags))
...@@ -152,8 +144,7 @@ endif ...@@ -152,8 +144,7 @@ endif
c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \
$(__c_flags) $(modkern_cflags) \ $(__c_flags) $(modkern_cflags) \
-D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) \ -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
$(debug_flags)
a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \
$(__a_flags) $(modkern_aflags) $(__a_flags) $(modkern_aflags)
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
# fixdep: Used to generate dependency information during build process # fixdep: Used to generate dependency information during build process
# docproc: Used in Documentation/DocBook # docproc: Used in Documentation/DocBook
hostprogs-y := fixdep docproc hash hostprogs-y := fixdep docproc
always := $(hostprogs-y) always := $(hostprogs-y)
# fixdep is needed to compile other host programs # fixdep is needed to compile other host programs
......
/*
* Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com>
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DYNAMIC_DEBUG_HASH_BITS 6
static const char *program;
static void usage(void)
{
printf("Usage: %s <djb2|r5> <modname>\n", program);
exit(1);
}
/* djb2 hashing algorithm by Dan Bernstein. From:
* http://www.cse.yorku.ca/~oz/hash.html
*/
static unsigned int djb2_hash(char *str)
{
unsigned long hash = 5381;
int c;
c = *str;
while (c) {
hash = ((hash << 5) + hash) + c;
c = *++str;
}
return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1));
}
static unsigned int r5_hash(char *str)
{
unsigned long hash = 0;
int c;
c = *str;
while (c) {
hash = (hash + (c << 4) + (c >> 4)) * 11;
c = *++str;
}
return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1));
}
int main(int argc, char *argv[])
{
program = argv[0];
if (argc != 3)
usage();
if (!strcmp(argv[1], "djb2"))
printf("%d\n", djb2_hash(argv[2]));
else if (!strcmp(argv[1], "r5"))
printf("%d\n", r5_hash(argv[2]));
else
usage();
exit(0);
}
#!/bin/sh
# Test for gcc 'asm goto' suport
# Copyright (C) 2010, Jason Baron <jbaron@redhat.com>
echo "int main(void) { entry: asm goto (\"\"::::entry); return 0; }" | $1 -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment