From: Ingo Molnar Date: Wed, 7 May 2014 11:39:22 +0000 (+0200) Subject: Merge branch 'perf/urgent' into perf/core, to avoid conflicts X-Git-Tag: firefly_0821_release~176^2~3763^2~28 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=37b16beaa92860c378273ccdcc2ccb22c6cee047;hp=-c;p=firefly-linux-kernel-4.4.55.git Merge branch 'perf/urgent' into perf/core, to avoid conflicts Signed-off-by: Ingo Molnar --- 37b16beaa92860c378273ccdcc2ccb22c6cee047 diff --combined kernel/events/core.c index 5129b1201050,71232844f235..09866a330af8 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@@ -39,7 -39,6 +39,7 @@@ #include #include #include +#include #include "internal.h" @@@ -1444,6 -1443,11 +1444,11 @@@ group_sched_out(struct perf_event *grou cpuctx->exclusive = 0; } + struct remove_event { + struct perf_event *event; + bool detach_group; + }; + /* * Cross CPU call to remove a performance event * @@@ -1452,12 -1456,15 +1457,15 @@@ */ static int __perf_remove_from_context(void *info) { - struct perf_event *event = info; + struct remove_event *re = info; + struct perf_event *event = re->event; struct perf_event_context *ctx = event->ctx; struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); raw_spin_lock(&ctx->lock); event_sched_out(event, cpuctx, ctx); + if (re->detach_group) + perf_group_detach(event); list_del_event(event, ctx); if (!ctx->nr_events && cpuctx->task_ctx == ctx) { ctx->is_active = 0; @@@ -1482,10 -1489,14 +1490,14 @@@ * When called from perf_event_exit_task, it's OK because the * context has been detached from its task. */ - static void perf_remove_from_context(struct perf_event *event) + static void perf_remove_from_context(struct perf_event *event, bool detach_group) { struct perf_event_context *ctx = event->ctx; struct task_struct *task = ctx->task; + struct remove_event re = { + .event = event, + .detach_group = detach_group, + }; lockdep_assert_held(&ctx->mutex); @@@ -1494,12 -1505,12 +1506,12 @@@ * Per cpu events are removed via an smp call and * the removal is always successful. */ - cpu_function_call(event->cpu, __perf_remove_from_context, event); + cpu_function_call(event->cpu, __perf_remove_from_context, &re); return; } retry: - if (!task_function_call(task, __perf_remove_from_context, event)) + if (!task_function_call(task, __perf_remove_from_context, &re)) return; raw_spin_lock_irq(&ctx->lock); @@@ -1516,6 -1527,8 +1528,8 @@@ * Since the task isn't running, its safe to remove the event, us * holding the ctx->lock ensures the task won't get scheduled in. */ + if (detach_group) + perf_group_detach(event); list_del_event(event, ctx); raw_spin_unlock_irq(&ctx->lock); } @@@ -3230,9 -3243,6 +3244,9 @@@ static void __free_event(struct perf_ev if (event->ctx) put_ctx(event->ctx); + if (event->pmu) + module_put(event->pmu->module); + call_rcu(&event->rcu_head, free_event_rcu); } static void free_event(struct perf_event *event) @@@ -3285,10 -3295,7 +3299,7 @@@ int perf_event_release_kernel(struct pe * to trigger the AB-BA case. */ mutex_lock_nested(&ctx->mutex, SINGLE_DEPTH_NESTING); - raw_spin_lock_irq(&ctx->lock); - perf_group_detach(event); - raw_spin_unlock_irq(&ctx->lock); - perf_remove_from_context(event); + perf_remove_from_context(event, true); mutex_unlock(&ctx->mutex); free_event(event); @@@ -6555,7 -6562,6 +6566,7 @@@ free_pdc free_percpu(pmu->pmu_disable_count); goto unlock; } +EXPORT_SYMBOL_GPL(perf_pmu_register); void perf_pmu_unregister(struct pmu *pmu) { @@@ -6577,7 -6583,6 +6588,7 @@@ put_device(pmu->dev); free_pmu_context(pmu); } +EXPORT_SYMBOL_GPL(perf_pmu_unregister); struct pmu *perf_init_event(struct perf_event *event) { @@@ -6591,10 -6596,6 +6602,10 @@@ pmu = idr_find(&pmu_idr, event->attr.type); rcu_read_unlock(); if (pmu) { + if (!try_module_get(pmu->module)) { + pmu = ERR_PTR(-ENODEV); + goto unlock; + } event->pmu = pmu; ret = pmu->event_init(event); if (ret) @@@ -6603,10 -6604,6 +6614,10 @@@ } list_for_each_entry_rcu(pmu, &pmus, entry) { + if (!try_module_get(pmu->module)) { + pmu = ERR_PTR(-ENODEV); + goto unlock; + } event->pmu = pmu; ret = pmu->event_init(event); if (!ret) @@@ -6785,7 -6782,6 +6796,7 @@@ perf_event_alloc(struct perf_event_att err_pmu: if (event->destroy) event->destroy(event); + module_put(pmu->module); err_ns: if (event->ns) put_pid_ns(event->ns); @@@ -7180,7 -7176,7 +7191,7 @@@ SYSCALL_DEFINE5(perf_event_open struct perf_event_context *gctx = group_leader->ctx; mutex_lock(&gctx->mutex); - perf_remove_from_context(group_leader); + perf_remove_from_context(group_leader, false); /* * Removing from the context ends up with disabled @@@ -7190,7 -7186,7 +7201,7 @@@ perf_event__state_init(group_leader); list_for_each_entry(sibling, &group_leader->sibling_list, group_entry) { - perf_remove_from_context(sibling); + perf_remove_from_context(sibling, false); perf_event__state_init(sibling); put_ctx(gctx); } @@@ -7320,7 -7316,7 +7331,7 @@@ void perf_pmu_migrate_context(struct pm mutex_lock(&src_ctx->mutex); list_for_each_entry_safe(event, tmp, &src_ctx->event_list, event_entry) { - perf_remove_from_context(event); + perf_remove_from_context(event, false); unaccount_event_cpu(event, src_cpu); put_ctx(src_ctx); list_add(&event->migrate_entry, &events); @@@ -7382,13 -7378,7 +7393,7 @@@ __perf_event_exit_task(struct perf_even struct perf_event_context *child_ctx, struct task_struct *child) { - if (child_event->parent) { - raw_spin_lock_irq(&child_ctx->lock); - perf_group_detach(child_event); - raw_spin_unlock_irq(&child_ctx->lock); - } - - perf_remove_from_context(child_event); + perf_remove_from_context(child_event, !!child_event->parent); /* * It can happen that the parent exits first, and has events @@@ -7739,6 -7729,8 +7744,8 @@@ int perf_event_init_context(struct task * swapped under us. */ parent_ctx = perf_pin_task_context(parent, ctxn); + if (!parent_ctx) + return 0; /* * No need to check if parent_ctx != NULL here; since we saw @@@ -7872,14 -7864,14 +7879,14 @@@ static void perf_pmu_rotate_stop(struc static void __perf_event_exit_context(void *__info) { + struct remove_event re = { .detach_group = false }; struct perf_event_context *ctx = __info; - struct perf_event *event; perf_pmu_rotate_stop(ctx->pmu); rcu_read_lock(); - list_for_each_entry_rcu(event, &ctx->event_list, event_entry) - __perf_remove_from_context(event); + list_for_each_entry_rcu(re.event, &ctx->event_list, event_entry) + __perf_remove_from_context(&re); rcu_read_unlock(); } diff --combined kernel/hrtimer.c index 53d26829cd4d,6b715c0af1b1..d10eba8089d1 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@@ -234,6 -234,11 +234,11 @@@ again goto again; } timer->base = new_base; + } else { + if (cpu != this_cpu && hrtimer_check_target(timer, new_base)) { + cpu = this_cpu; + goto again; + } } return new_base; } @@@ -569,6 -574,23 +574,23 @@@ hrtimer_force_reprogram(struct hrtimer_ cpu_base->expires_next.tv64 = expires_next.tv64; + /* + * If a hang was detected in the last timer interrupt then we + * leave the hang delay active in the hardware. We want the + * system to make progress. That also prevents the following + * scenario: + * T1 expires 50ms from now + * T2 expires 5s from now + * + * T1 is removed, so this code is called and would reprogram + * the hardware to 5s from now. Any hrtimer_start after that + * will not reprogram the hardware due to hang_detected being + * set. So we'd effectivly block all timers until the T2 event + * fires. + */ + if (cpu_base->hang_detected) + return; + if (cpu_base->expires_next.tv64 != KTIME_MAX) tick_program_event(cpu_base->expires_next, 1); } @@@ -1017,7 -1039,6 +1039,7 @@@ int __hrtimer_start_range_ns(struct hrt return ret; } +EXPORT_SYMBOL_GPL(__hrtimer_start_range_ns); /** * hrtimer_start_range_ns - (re)start an hrtimer on the current CPU