Actually a nice symetric startup/teardown pair which fits proper in the state machine concept. In the long run we should be able to invoke the startup callback for the boot cpu via the state machine and get rid of the init function which invokes it on the boot cpu. Signed-off-by: Thomas Gleixner --- include/linux/cpuhotplug.h | 11 +++++++++++ kernel/cpu.c | 8 ++++++++ kernel/events/core.c | 36 +++++++----------------------------- 3 files changed, 26 insertions(+), 29 deletions(-) Index: linux-2.6/include/linux/cpuhotplug.h =================================================================== --- linux-2.6.orig/include/linux/cpuhotplug.h +++ linux-2.6/include/linux/cpuhotplug.h @@ -5,6 +5,7 @@ enum cpuhp_states { CPUHP_OFFLINE, CPUHP_CREATE_THREADS, CPUHP_PERF_X86_UNCORE_PREP, + CPUHP_PERF_PREPARE, CPUHP_NOTIFY_PREPARE, CPUHP_NOTIFY_DEAD, CPUHP_SCHED_DEAD, @@ -18,6 +19,7 @@ enum cpuhp_states { CPUHP_TEARDOWN_CPU, CPUHP_PERCPU_THREADS, CPUHP_SCHED_ONLINE, + CPUHP_PERF_ONLINE, CPUHP_NOTIFY_ONLINE, CPUHP_NOTIFY_DOWN_PREPARE, CPUHP_PERF_X86_UNCORE_ONLINE, @@ -96,4 +98,13 @@ static inline void cpuhp_remove_state_no /* Compiled in scheduler hotplug functions */ int sched_starting_cpu(unsigned int cpu); + /* Performance counter hotplug functions */ +#ifdef CONFIG_PERF_EVENTS +int perf_event_init_cpu(unsigned int cpu); +int perf_event_exit_cpu(unsigned int cpu); +#else +#define perf_event_init_cpu NULL +#define perf_event_exit_cpu NULL +#endif + #endif Index: linux-2.6/kernel/cpu.c =================================================================== --- linux-2.6.orig/kernel/cpu.c +++ linux-2.6/kernel/cpu.c @@ -750,6 +750,10 @@ static struct cpuhp_step cpuhp_bp_states .startup = smpboot_create_threads, .teardown = NULL, }, + [CPUHP_PERF_PREPARE] = { + .startup = perf_event_init_cpu, + .teardown = perf_event_exit_cpu, + }, [CPUHP_NOTIFY_PREPARE] = { .startup = notify_prepare, .teardown = NULL, @@ -770,6 +774,10 @@ static struct cpuhp_step cpuhp_bp_states .startup = smpboot_unpark_threads, .teardown = smpboot_park_threads, }, + [CPUHP_PERF_ONLINE] = { + .startup = perf_event_init_cpu, + .teardown = perf_event_exit_cpu, + }, [CPUHP_NOTIFY_ONLINE] = { .startup = notify_online, .teardown = NULL, Index: linux-2.6/kernel/events/core.c =================================================================== --- linux-2.6.orig/kernel/events/core.c +++ linux-2.6/kernel/events/core.c @@ -5261,7 +5261,7 @@ static int swevent_hlist_get_cpu(struct if (!swevent_hlist_deref(swhash) && cpu_online(cpu)) { struct swevent_hlist *hlist; - hlist = kzalloc(sizeof(*hlist), GFP_KERNEL); + hlist = kzalloc_node(sizeof(*hlist), GFP_KERNEL, cpu_to_node(cpu)); if (!hlist) { err = -ENOMEM; goto exit; @@ -7263,12 +7263,12 @@ static void __init perf_event_init_all_c } } -static void __cpuinit perf_event_init_cpu(int cpu) +int __cpuinit perf_event_init_cpu(unsigned int cpu) { struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu); mutex_lock(&swhash->hlist_mutex); - if (swhash->hlist_refcount > 0) { + if (swhash->hlist_refcount > 0 && !swevent_hlist_deref(swhash)) { struct swevent_hlist *hlist; hlist = kzalloc_node(sizeof(*hlist), GFP_KERNEL, cpu_to_node(cpu)); @@ -7276,6 +7276,7 @@ static void __cpuinit perf_event_init_cp rcu_assign_pointer(swhash->swevent_hlist, hlist); } mutex_unlock(&swhash->hlist_mutex); + return 0; } #if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC @@ -7318,7 +7319,7 @@ static void perf_event_exit_cpu_context( srcu_read_unlock(&pmus_srcu, idx); } -static void perf_event_exit_cpu(int cpu) +int perf_event_exit_cpu(unsigned int cpu) { struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu); @@ -7327,6 +7328,7 @@ static void perf_event_exit_cpu(int cpu) mutex_unlock(&swhash->hlist_mutex); perf_event_exit_cpu_context(cpu); + return 0; } #else static inline void perf_event_exit_cpu(int cpu) { } @@ -7352,30 +7354,6 @@ static struct notifier_block perf_reboot .priority = INT_MIN, }; -static int __cpuinit -perf_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) -{ - unsigned int cpu = (long)hcpu; - - switch (action & ~CPU_TASKS_FROZEN) { - - case CPU_UP_PREPARE: - case CPU_DOWN_FAILED: - perf_event_init_cpu(cpu); - break; - - case CPU_UP_CANCELED: - case CPU_DOWN_PREPARE: - perf_event_exit_cpu(cpu); - break; - - default: - break; - } - - return NOTIFY_OK; -} - void __init perf_event_init(void) { int ret; @@ -7388,7 +7366,7 @@ void __init perf_event_init(void) perf_pmu_register(&perf_cpu_clock, NULL, -1); perf_pmu_register(&perf_task_clock, NULL, -1); perf_tp_register(); - perf_cpu_notifier(perf_cpu_notify); + perf_event_init_cpu(smp_processor_id()); register_reboot_notifier(&perf_reboot_notifier); ret = init_hw_breakpoint();