Skip to content

Commit

Permalink
Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/l…
Browse files Browse the repository at this point in the history
…inux/kernel/git/tip/linux-2.6-tip

* 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (57 commits)
  x86, perf events: Check if we have APIC enabled
  perf_event: Fix variable initialization in other codepaths
  perf kmem: Fix unused argument build warning
  perf symbols: perf_header__read_build_ids() offset'n'size should be u64
  perf symbols: dsos__read_build_ids() should read both user and kernel buildids
  perf tools: Align long options which have no short forms
  perf kmem: Show usage if no option is specified
  sched: Mark sched_clock() as notrace
  perf sched: Add max delay time snapshot
  perf tools: Correct size given to memset
  perf_event: Fix perf_swevent_hrtimer() variable initialization
  perf sched: Fix for getting task's execution time
  tracing/kprobes: Fix field creation's bad error handling
  perf_event: Cleanup for cpu_clock_perf_event_update()
  perf_event: Allocate children's perf_event_ctxp at the right time
  perf_event: Clean up __perf_event_init_context()
  hw-breakpoints: Modify breakpoints without unregistering them
  perf probe: Update perf-probe document
  perf probe: Support --del option
  trace-kprobe: Support delete probe syntax
  ...
  • Loading branch information
torvalds committed Dec 12, 2009
2 parents c4e194e + 1255803 commit 6f696eb
Show file tree
Hide file tree
Showing 40 changed files with 877 additions and 564 deletions.
4 changes: 2 additions & 2 deletions arch/x86/Kconfig.debug
Expand Up @@ -187,8 +187,8 @@ config HAVE_MMIOTRACE_SUPPORT
def_bool y

config X86_DECODER_SELFTEST
bool "x86 instruction decoder selftest"
depends on DEBUG_KERNEL
bool "x86 instruction decoder selftest"
depends on DEBUG_KERNEL && KPROBES
---help---
Perform x86 instruction decoder selftests at build time.
This option is useful for checking the sanity of x86 instruction
Expand Down
31 changes: 21 additions & 10 deletions arch/x86/kernel/cpu/perf_event.c
Expand Up @@ -1632,6 +1632,7 @@ static void intel_pmu_drain_bts_buffer(struct cpu_hw_events *cpuc)

data.period = event->hw.last_period;
data.addr = 0;
data.raw = NULL;
regs.ip = 0;

/*
Expand Down Expand Up @@ -1749,6 +1750,7 @@ static int p6_pmu_handle_irq(struct pt_regs *regs)
u64 val;

data.addr = 0;
data.raw = NULL;

cpuc = &__get_cpu_var(cpu_hw_events);

Expand Down Expand Up @@ -1794,6 +1796,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)
u64 ack, status;

data.addr = 0;
data.raw = NULL;

cpuc = &__get_cpu_var(cpu_hw_events);

Expand Down Expand Up @@ -1857,6 +1860,7 @@ static int amd_pmu_handle_irq(struct pt_regs *regs)
u64 val;

data.addr = 0;
data.raw = NULL;

cpuc = &__get_cpu_var(cpu_hw_events);

Expand Down Expand Up @@ -2062,12 +2066,6 @@ static __init int p6_pmu_init(void)

x86_pmu = p6_pmu;

if (!cpu_has_apic) {
pr_info("no APIC, boot with the \"lapic\" boot parameter to force-enable it.\n");
pr_info("no hardware sampling interrupt available.\n");
x86_pmu.apic = 0;
}

return 0;
}

Expand Down Expand Up @@ -2159,6 +2157,16 @@ static __init int amd_pmu_init(void)
return 0;
}

static void __init pmu_check_apic(void)
{
if (cpu_has_apic)
return;

x86_pmu.apic = 0;
pr_info("no APIC, boot with the \"lapic\" boot parameter to force-enable it.\n");
pr_info("no hardware sampling interrupt available.\n");
}

void __init init_hw_perf_events(void)
{
int err;
Expand All @@ -2180,6 +2188,8 @@ void __init init_hw_perf_events(void)
return;
}

pmu_check_apic();

pr_cont("%s PMU driver.\n", x86_pmu.name);

if (x86_pmu.num_events > X86_PMC_MAX_GENERIC) {
Expand Down Expand Up @@ -2287,7 +2297,7 @@ void callchain_store(struct perf_callchain_entry *entry, u64 ip)

static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_irq_entry);
static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_nmi_entry);
static DEFINE_PER_CPU(int, in_nmi_frame);
static DEFINE_PER_CPU(int, in_ignored_frame);


static void
Expand All @@ -2303,8 +2313,9 @@ static void backtrace_warning(void *data, char *msg)

static int backtrace_stack(void *data, char *name)
{
per_cpu(in_nmi_frame, smp_processor_id()) =
x86_is_stack_id(NMI_STACK, name);
per_cpu(in_ignored_frame, smp_processor_id()) =
x86_is_stack_id(NMI_STACK, name) ||
x86_is_stack_id(DEBUG_STACK, name);

return 0;
}
Expand All @@ -2313,7 +2324,7 @@ static void backtrace_address(void *data, unsigned long addr, int reliable)
{
struct perf_callchain_entry *entry = data;

if (per_cpu(in_nmi_frame, smp_processor_id()))
if (per_cpu(in_ignored_frame, smp_processor_id()))
return;

if (reliable)
Expand Down
33 changes: 32 additions & 1 deletion arch/x86/kernel/dumpstack_64.c
Expand Up @@ -103,6 +103,35 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
return NULL;
}

static inline int
in_irq_stack(unsigned long *stack, unsigned long *irq_stack,
unsigned long *irq_stack_end)
{
return (stack >= irq_stack && stack < irq_stack_end);
}

/*
* We are returning from the irq stack and go to the previous one.
* If the previous stack is also in the irq stack, then bp in the first
* frame of the irq stack points to the previous, interrupted one.
* Otherwise we have another level of indirection: We first save
* the bp of the previous stack, then we switch the stack to the irq one
* and save a new bp that links to the previous one.
* (See save_args())
*/
static inline unsigned long
fixup_bp_irq_link(unsigned long bp, unsigned long *stack,
unsigned long *irq_stack, unsigned long *irq_stack_end)
{
#ifdef CONFIG_FRAME_POINTER
struct stack_frame *frame = (struct stack_frame *)bp;

if (!in_irq_stack(stack, irq_stack, irq_stack_end))
return (unsigned long)frame->next_frame;
#endif
return bp;
}

/*
* x86-64 can have up to three kernel stacks:
* process stack
Expand Down Expand Up @@ -175,7 +204,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
irq_stack = irq_stack_end -
(IRQ_STACK_SIZE - 64) / sizeof(*irq_stack);

if (stack >= irq_stack && stack < irq_stack_end) {
if (in_irq_stack(stack, irq_stack, irq_stack_end)) {
if (ops->stack(data, "IRQ") < 0)
break;
bp = print_context_stack(tinfo, stack, bp,
Expand All @@ -186,6 +215,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
* pointer (index -1 to end) in the IRQ stack:
*/
stack = (unsigned long *) (irq_stack_end[-1]);
bp = fixup_bp_irq_link(bp, stack, irq_stack,
irq_stack_end);
irq_stack_end = NULL;
ops->stack(data, "EOI");
continue;
Expand Down
6 changes: 3 additions & 3 deletions arch/x86/kernel/entry_64.S
Expand Up @@ -1076,10 +1076,10 @@ ENTRY(\sym)
TRACE_IRQS_OFF
movq %rsp,%rdi /* pt_regs pointer */
xorl %esi,%esi /* no error code */
PER_CPU(init_tss, %rbp)
subq $EXCEPTION_STKSZ, TSS_ist + (\ist - 1) * 8(%rbp)
PER_CPU(init_tss, %r12)
subq $EXCEPTION_STKSZ, TSS_ist + (\ist - 1) * 8(%r12)
call \do_sym
addq $EXCEPTION_STKSZ, TSS_ist + (\ist - 1) * 8(%rbp)
addq $EXCEPTION_STKSZ, TSS_ist + (\ist - 1) * 8(%r12)
jmp paranoid_exit /* %ebx: no swapgs flag */
CFI_ENDPROC
END(\sym)
Expand Down
5 changes: 2 additions & 3 deletions arch/x86/kernel/hw_breakpoint.c
Expand Up @@ -362,8 +362,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp,
return ret;
}

if (bp->callback)
ret = arch_store_info(bp);
ret = arch_store_info(bp);

if (ret < 0)
return ret;
Expand Down Expand Up @@ -519,7 +518,7 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args)
break;
}

(bp->callback)(bp, args->regs);
perf_bp_event(bp, args->regs);

rcu_read_unlock();
}
Expand Down
68 changes: 33 additions & 35 deletions arch/x86/kernel/ptrace.c
Expand Up @@ -555,7 +555,9 @@ static int genregs_set(struct task_struct *target,
return ret;
}

static void ptrace_triggered(struct perf_event *bp, void *data)
static void ptrace_triggered(struct perf_event *bp, int nmi,
struct perf_sample_data *data,
struct pt_regs *regs)
{
int i;
struct thread_struct *thread = &(current->thread);
Expand Down Expand Up @@ -593,32 +595,32 @@ static unsigned long ptrace_get_dr7(struct perf_event *bp[])
return dr7;
}

static struct perf_event *
static int
ptrace_modify_breakpoint(struct perf_event *bp, int len, int type,
struct task_struct *tsk, int disabled)
{
int err;
int gen_len, gen_type;
DEFINE_BREAKPOINT_ATTR(attr);
struct perf_event_attr attr;

/*
* We shoud have at least an inactive breakpoint at this
* slot. It means the user is writing dr7 without having
* written the address register first
*/
if (!bp)
return ERR_PTR(-EINVAL);
return -EINVAL;

err = arch_bp_generic_fields(len, type, &gen_len, &gen_type);
if (err)
return ERR_PTR(err);
return err;

attr = bp->attr;
attr.bp_len = gen_len;
attr.bp_type = gen_type;
attr.disabled = disabled;

return modify_user_hw_breakpoint(bp, &attr, bp->callback, tsk);
return modify_user_hw_breakpoint(bp, &attr);
}

/*
Expand Down Expand Up @@ -656,28 +658,17 @@ static int ptrace_write_dr7(struct task_struct *tsk, unsigned long data)
if (!second_pass)
continue;

thread->ptrace_bps[i] = NULL;
bp = ptrace_modify_breakpoint(bp, len, type,
rc = ptrace_modify_breakpoint(bp, len, type,
tsk, 1);
if (IS_ERR(bp)) {
rc = PTR_ERR(bp);
thread->ptrace_bps[i] = NULL;
if (rc)
break;
}
thread->ptrace_bps[i] = bp;
}
continue;
}

bp = ptrace_modify_breakpoint(bp, len, type, tsk, 0);

/* Incorrect bp, or we have a bug in bp API */
if (IS_ERR(bp)) {
rc = PTR_ERR(bp);
thread->ptrace_bps[i] = NULL;
rc = ptrace_modify_breakpoint(bp, len, type, tsk, 0);
if (rc)
break;
}
thread->ptrace_bps[i] = bp;
}
/*
* Make a second pass to free the remaining unused breakpoints
Expand Down Expand Up @@ -721,9 +712,10 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr,
{
struct perf_event *bp;
struct thread_struct *t = &tsk->thread;
DEFINE_BREAKPOINT_ATTR(attr);
struct perf_event_attr attr;

if (!t->ptrace_bps[nr]) {
hw_breakpoint_init(&attr);
/*
* Put stub len and type to register (reserve) an inactive but
* correct bp
Expand All @@ -734,26 +726,32 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr,
attr.disabled = 1;

bp = register_user_hw_breakpoint(&attr, ptrace_triggered, tsk);

/*
* CHECKME: the previous code returned -EIO if the addr wasn't
* a valid task virtual addr. The new one will return -EINVAL in
* this case.
* -EINVAL may be what we want for in-kernel breakpoints users,
* but -EIO looks better for ptrace, since we refuse a register
* writing for the user. And anyway this is the previous
* behaviour.
*/
if (IS_ERR(bp))
return PTR_ERR(bp);

t->ptrace_bps[nr] = bp;
} else {
int err;

bp = t->ptrace_bps[nr];
t->ptrace_bps[nr] = NULL;

attr = bp->attr;
attr.bp_addr = addr;
bp = modify_user_hw_breakpoint(bp, &attr, bp->callback, tsk);
err = modify_user_hw_breakpoint(bp, &attr);
if (err)
return err;
}
/*
* CHECKME: the previous code returned -EIO if the addr wasn't a
* valid task virtual addr. The new one will return -EINVAL in this
* case.
* -EINVAL may be what we want for in-kernel breakpoints users, but
* -EIO looks better for ptrace, since we refuse a register writing
* for the user. And anyway this is the previous behaviour.
*/
if (IS_ERR(bp))
return PTR_ERR(bp);

t->ptrace_bps[nr] = bp;

return 0;
}
Expand Down
4 changes: 2 additions & 2 deletions arch/x86/lib/Makefile
Expand Up @@ -5,7 +5,7 @@
inat_tables_script = $(srctree)/arch/x86/tools/gen-insn-attr-x86.awk
inat_tables_maps = $(srctree)/arch/x86/lib/x86-opcode-map.txt
quiet_cmd_inat_tables = GEN $@
cmd_inat_tables = $(AWK) -f $(inat_tables_script) $(inat_tables_maps) > $@
cmd_inat_tables = $(AWK) -f $(inat_tables_script) $(inat_tables_maps) > $@ || rm -f $@

$(obj)/inat-tables.c: $(inat_tables_script) $(inat_tables_maps)
$(call cmd,inat_tables)
Expand All @@ -20,7 +20,7 @@ lib-y := delay.o
lib-y += thunk_$(BITS).o
lib-y += usercopy_$(BITS).o getuser.o putuser.o
lib-y += memcpy_$(BITS).o
lib-y += insn.o inat.o
lib-$(CONFIG_KPROBES) += insn.o inat.o

obj-y += msr-reg.o msr-reg-export.o

Expand Down
2 changes: 1 addition & 1 deletion arch/x86/tools/test_get_len.c
Expand Up @@ -113,7 +113,7 @@ int main(int argc, char **argv)
char line[BUFSIZE], sym[BUFSIZE] = "<unknown>";
unsigned char insn_buf[16];
struct insn insn;
int insns = 0, c;
int insns = 0;
int warnings = 0;

parse_args(argc, argv);
Expand Down

0 comments on commit 6f696eb

Please sign in to comment.