]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 12 Dec 2009 04:47:30 +0000 (20:47 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 12 Dec 2009 04:47:30 +0000 (20:47 -0800)
* '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
  ...

1  2 
arch/x86/Kconfig.debug
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/dumpstack_64.c
arch/x86/kernel/entry_64.S
include/linux/sched.h
kernel/perf_event.c

diff --combined arch/x86/Kconfig.debug
index 731318e5ac1d44e011f29aa42ced5225904fd924,0e90929da40f74dcee7683183742f4021d84fda9..bc01e3ebfeb29bfbfe6d60b42276bc6565cf2e66
@@@ -187,8 -187,8 +187,8 @@@ config HAVE_MMIOTRACE_SUPPOR
        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
@@@ -296,18 -296,4 +296,18 @@@ config OPTIMIZE_INLININ
  
          If unsure, say N.
  
 +config DEBUG_STRICT_USER_COPY_CHECKS
 +      bool "Strict copy size checks"
 +      depends on DEBUG_KERNEL && !TRACE_BRANCH_PROFILING
 +      ---help---
 +        Enabling this option turns a certain set of sanity checks for user
 +        copy operations into compile time failures.
 +
 +        The copy_from_user() etc checks are there to help test if there
 +        are sufficient security checks on the length argument of
 +        the copy operation, by having gcc prove that the argument is
 +        within bounds.
 +
 +        If unsure, or if you run an older (pre 4.4) gcc, say N.
 +
  endmenu
index ab1a8a89b984ef0e9c7ea31ff791ef272fa8103f,18f05eccbb62b79359a04753d016bb9f77b0b923..45506d5dd8df7e06f0e35ae8c0db18927ffc00e6
@@@ -1286,7 -1286,7 +1286,7 @@@ x86_perf_event_set_period(struct perf_e
                return 0;
  
        /*
 -       * If we are way outside a reasoable range then just skip forward:
 +       * If we are way outside a reasonable range then just skip forward:
         */
        if (unlikely(left <= -period)) {
                left = period;
@@@ -1632,6 -1632,7 +1632,7 @@@ static void intel_pmu_drain_bts_buffer(
  
        data.period     = event->hw.last_period;
        data.addr       = 0;
+       data.raw        = NULL;
        regs.ip         = 0;
  
        /*
@@@ -1749,6 -1750,7 +1750,7 @@@ static int p6_pmu_handle_irq(struct pt_
        u64 val;
  
        data.addr = 0;
+       data.raw = NULL;
  
        cpuc = &__get_cpu_var(cpu_hw_events);
  
@@@ -1794,6 -1796,7 +1796,7 @@@ static int intel_pmu_handle_irq(struct 
        u64 ack, status;
  
        data.addr = 0;
+       data.raw = NULL;
  
        cpuc = &__get_cpu_var(cpu_hw_events);
  
@@@ -1857,6 -1860,7 +1860,7 @@@ static int amd_pmu_handle_irq(struct pt
        u64 val;
  
        data.addr = 0;
+       data.raw = NULL;
  
        cpuc = &__get_cpu_var(cpu_hw_events);
  
@@@ -2062,12 -2066,6 +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;
  }
  
@@@ -2159,6 -2157,16 +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;
                return;
        }
  
+       pmu_check_apic();
        pr_cont("%s PMU driver.\n", x86_pmu.name);
  
        if (x86_pmu.num_events > X86_PMC_MAX_GENERIC) {
@@@ -2287,7 -2297,7 +2297,7 @@@ void callchain_store(struct perf_callch
  
  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
@@@ -2303,8 -2313,9 +2313,9 @@@ static void backtrace_warning(void *dat
  
  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;
  }
@@@ -2313,7 -2324,7 +2324,7 @@@ static void backtrace_address(void *dat
  {
        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)
index 8e740934bd1f56307b1cc8b7c318bdaeeda5b9d5,004b8aa6a35f01e8ac3696cf39794328b7669beb..b13af53883aabe04504b402739a280bacf087424
  #include <linux/module.h>
  #include <linux/ptrace.h>
  #include <linux/kexec.h>
 +#include <linux/sysfs.h>
  #include <linux/bug.h>
  #include <linux/nmi.h>
 -#include <linux/sysfs.h>
  
  #include <asm/stacktrace.h>
  
  #include "dumpstack.h"
  
 +#define N_EXCEPTION_STACKS_END \
 +              (N_EXCEPTION_STACKS + DEBUG_STKSZ/EXCEPTION_STKSZ - 2)
  
  static char x86_stack_ids[][8] = {
 -              [DEBUG_STACK - 1] = "#DB",
 -              [NMI_STACK - 1] = "NMI",
 -              [DOUBLEFAULT_STACK - 1] = "#DF",
 -              [STACKFAULT_STACK - 1] = "#SS",
 -              [MCE_STACK - 1] = "#MC",
 +              [ DEBUG_STACK-1                 ]       = "#DB",
 +              [ NMI_STACK-1                   ]       = "NMI",
 +              [ DOUBLEFAULT_STACK-1           ]       = "#DF",
 +              [ STACKFAULT_STACK-1            ]       = "#SS",
 +              [ MCE_STACK-1                   ]       = "#MC",
  #if DEBUG_STKSZ > EXCEPTION_STKSZ
 -              [N_EXCEPTION_STACKS ...
 -                      N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]"
 +              [ N_EXCEPTION_STACKS ...
 +                N_EXCEPTION_STACKS_END        ]       = "#DB[?]"
  #endif
 -      };
 +};
  
  int x86_is_stack_id(int id, char *name)
  {
@@@ -39,7 -37,7 +39,7 @@@
  }
  
  static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
 -                                      unsigned *usedp, char **idp)
 +                                       unsigned *usedp, char **idp)
  {
        unsigned k;
  
        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
@@@ -175,7 -202,7 +204,7 @@@ void dump_trace(struct task_struct *tas
                        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,
                                 * 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;
@@@ -204,24 -233,21 +235,24 @@@ EXPORT_SYMBOL(dump_trace)
  
  void
  show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
 -              unsigned long *sp, unsigned long bp, char *log_lvl)
 +                 unsigned long *sp, unsigned long bp, char *log_lvl)
  {
 +      unsigned long *irq_stack_end;
 +      unsigned long *irq_stack;
        unsigned long *stack;
 +      int cpu;
        int i;
 -      const int cpu = smp_processor_id();
 -      unsigned long *irq_stack_end =
 -              (unsigned long *)(per_cpu(irq_stack_ptr, cpu));
 -      unsigned long *irq_stack =
 -              (unsigned long *)(per_cpu(irq_stack_ptr, cpu) - IRQ_STACK_SIZE);
 +
 +      preempt_disable();
 +      cpu = smp_processor_id();
 +
 +      irq_stack_end   = (unsigned long *)(per_cpu(irq_stack_ptr, cpu));
 +      irq_stack       = (unsigned long *)(per_cpu(irq_stack_ptr, cpu) - IRQ_STACK_SIZE);
  
        /*
 -       * debugging aid: "show_stack(NULL, NULL);" prints the
 -       * back trace for this cpu.
 +       * Debugging aid: "show_stack(NULL, NULL);" prints the
 +       * back trace for this cpu:
         */
 -
        if (sp == NULL) {
                if (task)
                        sp = (unsigned long *)task->thread.sp;
                printk(" %016lx", *stack++);
                touch_nmi_watchdog();
        }
 +      preempt_enable();
 +
        printk("\n");
        show_trace_log_lvl(task, regs, sp, bp, log_lvl);
  }
@@@ -310,3 -334,4 +341,3 @@@ int is_valid_bugaddr(unsigned long ip
  
        return ud2 == 0x0b0f;
  }
 -
index 63bca794c8f99c0f95aeecf858cacf288ad2d44a,0f08a0cea3e0026cc578a8f67d947b772f8cfeb2..673f693fb45131aec07012fb71233b5459e3788f
@@@ -977,8 -977,8 +977,8 @@@ apicinterrupt UV_BAU_MESSAGE 
  #endif
  apicinterrupt LOCAL_TIMER_VECTOR \
        apic_timer_interrupt smp_apic_timer_interrupt
 -apicinterrupt GENERIC_INTERRUPT_VECTOR \
 -      generic_interrupt smp_generic_interrupt
 +apicinterrupt X86_PLATFORM_IPI_VECTOR \
 +      x86_platform_ipi smp_x86_platform_ipi
  
  #ifdef CONFIG_SMP
  apicinterrupt INVALIDATE_TLB_VECTOR_START+0 \
@@@ -1076,10 -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)
@@@ -1499,17 -1499,12 +1499,17 @@@ error_kernelspace
        leaq irq_return(%rip),%rcx
        cmpq %rcx,RIP+8(%rsp)
        je error_swapgs
 -      movl %ecx,%ecx  /* zero extend */
 -      cmpq %rcx,RIP+8(%rsp)
 -      je error_swapgs
 +      movl %ecx,%eax  /* zero extend */
 +      cmpq %rax,RIP+8(%rsp)
 +      je bstep_iret
        cmpq $gs_change,RIP+8(%rsp)
        je error_swapgs
        jmp error_sti
 +
 +bstep_iret:
 +      /* Fix truncated RIP */
 +      movq %rcx,RIP+8(%rsp)
 +      jmp error_swapgs
  END(error_entry)
  
  
diff --combined include/linux/sched.h
index 89115ec7d43f2bfe0bcd5c581052615e733fc029,576d838adf68695fcbf8c238b59f29ca486e4715..3f4fa73b512a0e48408e701bc1de985590d7f39c
@@@ -145,6 -145,7 +145,6 @@@ extern unsigned long this_cpu_load(void
  
  
  extern void calc_global_load(void);
 -extern u64 cpu_nr_migrations(int cpu);
  
  extern unsigned long get_parent_ip(unsigned long addr);
  
@@@ -170,6 -171,8 +170,6 @@@ print_cfs_rq(struct seq_file *m, int cp
  }
  #endif
  
 -extern unsigned long long time_sync_thresh;
 -
  /*
   * Task state bitmask. NOTE! These bits are also
   * encoded in fs/proc/array.c: get_task_state().
@@@ -346,6 -349,7 +346,6 @@@ extern signed long schedule_timeout(sig
  extern signed long schedule_timeout_interruptible(signed long timeout);
  extern signed long schedule_timeout_killable(signed long timeout);
  extern signed long schedule_timeout_uninterruptible(signed long timeout);
 -asmlinkage void __schedule(void);
  asmlinkage void schedule(void);
  extern int mutex_spin_on_owner(struct mutex *lock, struct thread_info *owner);
  
@@@ -624,9 -628,6 +624,9 @@@ struct signal_struct 
        cputime_t utime, stime, cutime, cstime;
        cputime_t gtime;
        cputime_t cgtime;
 +#ifndef CONFIG_VIRT_CPU_ACCOUNTING
 +      cputime_t prev_utime, prev_stime;
 +#endif
        unsigned long nvcsw, nivcsw, cnvcsw, cnivcsw;
        unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt;
        unsigned long inblock, oublock, cinblock, coublock;
@@@ -1012,13 -1013,9 +1012,13 @@@ static inline struct cpumask *sched_dom
        return to_cpumask(sd->span);
  }
  
 -extern void partition_sched_domains(int ndoms_new, struct cpumask *doms_new,
 +extern void partition_sched_domains(int ndoms_new, cpumask_var_t doms_new[],
                                    struct sched_domain_attr *dattr_new);
  
 +/* Allocate an array of sched domains, for partition_sched_domains(). */
 +cpumask_var_t *alloc_sched_domains(unsigned int ndoms);
 +void free_sched_domains(cpumask_var_t doms[], unsigned int ndoms);
 +
  /* Test a flag in parent sched domain */
  static inline int test_sd_parent(struct sched_domain *sd, int flag)
  {
@@@ -1036,7 -1033,7 +1036,7 @@@ unsigned long default_scale_smt_power(s
  struct sched_domain_attr;
  
  static inline void
 -partition_sched_domains(int ndoms_new, struct cpumask *doms_new,
 +partition_sched_domains(int ndoms_new, cpumask_var_t doms_new[],
                        struct sched_domain_attr *dattr_new)
  {
  }
@@@ -1334,9 -1331,7 +1334,9 @@@ struct task_struct 
  
        cputime_t utime, stime, utimescaled, stimescaled;
        cputime_t gtime;
 +#ifndef CONFIG_VIRT_CPU_ACCOUNTING
        cputime_t prev_utime, prev_stime;
 +#endif
        unsigned long nvcsw, nivcsw; /* context switch counts */
        struct timespec start_time;             /* monotonic time */
        struct timespec real_start_time;        /* boot based time */
  #endif
  #ifdef CONFIG_TRACE_IRQFLAGS
        unsigned int irq_events;
 -      int hardirqs_enabled;
        unsigned long hardirq_enable_ip;
 -      unsigned int hardirq_enable_event;
        unsigned long hardirq_disable_ip;
 +      unsigned int hardirq_enable_event;
        unsigned int hardirq_disable_event;
 -      int softirqs_enabled;
 +      int hardirqs_enabled;
 +      int hardirq_context;
        unsigned long softirq_disable_ip;
 -      unsigned int softirq_disable_event;
        unsigned long softirq_enable_ip;
 +      unsigned int softirq_disable_event;
        unsigned int softirq_enable_event;
 -      int hardirq_context;
 +      int softirqs_enabled;
        int softirq_context;
  #endif
  #ifdef CONFIG_LOCKDEP
@@@ -1725,8 -1720,9 +1725,8 @@@ static inline void put_task_struct(stru
                __put_task_struct(t);
  }
  
 -extern cputime_t task_utime(struct task_struct *p);
 -extern cputime_t task_stime(struct task_struct *p);
 -extern cputime_t task_gtime(struct task_struct *p);
 +extern void task_times(struct task_struct *p, cputime_t *ut, cputime_t *st);
 +extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st);
  
  /*
   * Per process flags
@@@ -1840,7 -1836,8 +1840,8 @@@ static inline int set_cpus_allowed(stru
  extern int sched_clock_stable;
  #endif
  
- extern unsigned long long sched_clock(void);
+ /* ftrace calls sched_clock() directly */
+ extern unsigned long long notrace sched_clock(void);
  
  extern void sched_clock_init(void);
  extern u64 sched_clock_cpu(int cpu);
@@@ -2090,18 -2087,11 +2091,18 @@@ static inline int is_si_special(const s
        return info <= SEND_SIG_FORCED;
  }
  
 -/* True if we are on the alternate signal stack.  */
 -
 +/*
 + * True if we are on the alternate signal stack.
 + */
  static inline int on_sig_stack(unsigned long sp)
  {
 -      return (sp - current->sas_ss_sp < current->sas_ss_size);
 +#ifdef CONFIG_STACK_GROWSUP
 +      return sp >= current->sas_ss_sp &&
 +              sp - current->sas_ss_sp < current->sas_ss_size;
 +#else
 +      return sp > current->sas_ss_sp &&
 +              sp - current->sas_ss_sp <= current->sas_ss_size;
 +#endif
  }
  
  static inline int sas_ss_flags(unsigned long sp)
diff --combined kernel/perf_event.c
index 40a996ec39faed91dea95a28661a98e7ed86878b,d891ec4a810074b4ce1d6fbf76421f21ae3e40dd..e73e53c7582f9a3d872622b277187e31de3db206
@@@ -36,7 -36,7 +36,7 @@@
  /*
   * Each CPU has a list of per CPU events:
   */
- DEFINE_PER_CPU(struct perf_cpu_context, perf_cpu_context);
static DEFINE_PER_CPU(struct perf_cpu_context, perf_cpu_context);
  
  int perf_max_events __read_mostly = 1;
  static int perf_reserved_percpu __read_mostly;
@@@ -476,7 -476,7 +476,7 @@@ static void perf_event_remove_from_cont
        if (!task) {
                /*
                 * Per cpu events are removed via an smp call and
 -               * the removal is always sucessful.
 +               * the removal is always successful.
                 */
                smp_call_function_single(event->cpu,
                                         __perf_event_remove_from_context,
@@@ -567,7 -567,7 +567,7 @@@ static void __perf_event_disable(void *
   * is the current context on this CPU and preemption is disabled,
   * hence we can't get into perf_event_task_sched_out for this context.
   */
static void perf_event_disable(struct perf_event *event)
+ void perf_event_disable(struct perf_event *event)
  {
        struct perf_event_context *ctx = event->ctx;
        struct task_struct *task = ctx->task;
@@@ -845,7 -845,7 +845,7 @@@ perf_install_in_context(struct perf_eve
        if (!task) {
                /*
                 * Per cpu events are installed via an smp call and
 -               * the install is always sucessful.
 +               * the install is always successful.
                 */
                smp_call_function_single(cpu, __perf_install_in_context,
                                         event, 1);
@@@ -971,7 -971,7 +971,7 @@@ static void __perf_event_enable(void *i
   * perf_event_for_each_child or perf_event_for_each as described
   * for perf_event_disable.
   */
static void perf_event_enable(struct perf_event *event)
+ void perf_event_enable(struct perf_event *event)
  {
        struct perf_event_context *ctx = event->ctx;
        struct task_struct *task = ctx->task;
@@@ -1579,7 -1579,6 +1579,6 @@@ static voi
  __perf_event_init_context(struct perf_event_context *ctx,
                            struct task_struct *task)
  {
-       memset(ctx, 0, sizeof(*ctx));
        spin_lock_init(&ctx->lock);
        mutex_init(&ctx->mutex);
        INIT_LIST_HEAD(&ctx->group_list);
@@@ -1654,7 -1653,7 +1653,7 @@@ static struct perf_event_context *find_
        }
  
        if (!ctx) {
-               ctx = kmalloc(sizeof(struct perf_event_context), GFP_KERNEL);
+               ctx = kzalloc(sizeof(struct perf_event_context), GFP_KERNEL);
                err = -ENOMEM;
                if (!ctx)
                        goto errout;
@@@ -4011,6 -4010,7 +4010,7 @@@ static enum hrtimer_restart perf_sweven
        event->pmu->read(event);
  
        data.addr = 0;
+       data.raw = NULL;
        data.period = event->hw.last_period;
        regs = get_irq_regs();
        /*
@@@ -4080,8 -4080,7 +4080,7 @@@ static void cpu_clock_perf_event_update
        u64 now;
  
        now = cpu_clock(cpu);
-       prev = atomic64_read(&event->hw.prev_count);
-       atomic64_set(&event->hw.prev_count, now);
+       prev = atomic64_xchg(&event->hw.prev_count, now);
        atomic64_add(now - prev, &event->count);
  }
  
@@@ -4286,15 -4285,8 +4285,8 @@@ static void bp_perf_event_destroy(struc
  static const struct pmu *bp_perf_event_init(struct perf_event *bp)
  {
        int err;
-       /*
-        * The breakpoint is already filled if we haven't created the counter
-        * through perf syscall
-        * FIXME: manage to get trigerred to NULL if it comes from syscalls
-        */
-       if (!bp->callback)
-               err = register_perf_hw_breakpoint(bp);
-       else
-               err = __register_perf_hw_breakpoint(bp);
+       err = register_perf_hw_breakpoint(bp);
        if (err)
                return ERR_PTR(err);
  
@@@ -4308,6 -4300,7 +4300,7 @@@ void perf_bp_event(struct perf_event *b
        struct perf_sample_data sample;
        struct pt_regs *regs = data;
  
+       sample.raw = NULL;
        sample.addr = bp->attr.bp_addr;
  
        if (!perf_exclude_event(bp, regs))
@@@ -4390,7 -4383,7 +4383,7 @@@ perf_event_alloc(struct perf_event_att
                   struct perf_event_context *ctx,
                   struct perf_event *group_leader,
                   struct perf_event *parent_event,
-                  perf_callback_t callback,
+                  perf_overflow_handler_t overflow_handler,
                   gfp_t gfpflags)
  {
        const struct pmu *pmu;
  
        event->state            = PERF_EVENT_STATE_INACTIVE;
  
-       if (!callback && parent_event)
-               callback = parent_event->callback;
+       if (!overflow_handler && parent_event)
+               overflow_handler = parent_event->overflow_handler;
        
-       event->callback = callback;
+       event->overflow_handler = overflow_handler;
  
        if (attr->disabled)
                event->state = PERF_EVENT_STATE_OFF;
@@@ -4776,7 -4769,8 +4769,8 @@@ err_put_context
   */
  struct perf_event *
  perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
-                                pid_t pid, perf_callback_t callback)
+                                pid_t pid,
+                                perf_overflow_handler_t overflow_handler)
  {
        struct perf_event *event;
        struct perf_event_context *ctx;
        }
  
        event = perf_event_alloc(attr, cpu, ctx, NULL,
-                                    NULL, callback, GFP_KERNEL);
+                                NULL, overflow_handler, GFP_KERNEL);
        if (IS_ERR(event)) {
                err = PTR_ERR(event);
                goto err_put_context;
@@@ -5090,7 -5084,7 +5084,7 @@@ again
   */
  int perf_event_init_task(struct task_struct *child)
  {
-       struct perf_event_context *child_ctx, *parent_ctx;
+       struct perf_event_context *child_ctx = NULL, *parent_ctx;
        struct perf_event_context *cloned_ctx;
        struct perf_event *event;
        struct task_struct *parent = current;
        if (likely(!parent->perf_event_ctxp))
                return 0;
  
-       /*
-        * This is executed from the parent task context, so inherit
-        * events that have been marked for cloning.
-        * First allocate and initialize a context for the child.
-        */
-       child_ctx = kmalloc(sizeof(struct perf_event_context), GFP_KERNEL);
-       if (!child_ctx)
-               return -ENOMEM;
-       __perf_event_init_context(child_ctx, child);
-       child->perf_event_ctxp = child_ctx;
-       get_task_struct(child);
        /*
         * If the parent's context is a clone, pin it so it won't get
         * swapped under us.
                        continue;
                }
  
+               if (!child->perf_event_ctxp) {
+                       /*
+                        * This is executed from the parent task context, so
+                        * inherit events that have been marked for cloning.
+                        * First allocate and initialize a context for the
+                        * child.
+                        */
+                       child_ctx = kzalloc(sizeof(struct perf_event_context),
+                                           GFP_KERNEL);
+                       if (!child_ctx) {
+                               ret = -ENOMEM;
+                               goto exit;
+                       }
+                       __perf_event_init_context(child_ctx, child);
+                       child->perf_event_ctxp = child_ctx;
+                       get_task_struct(child);
+               }
                ret = inherit_group(event, parent, parent_ctx,
                                             child, child_ctx);
                if (ret) {
                get_ctx(child_ctx->parent_ctx);
        }
  
+ exit:
        mutex_unlock(&parent_ctx->mutex);
  
        perf_unpin_context(parent_ctx);