]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - kernel/events/core.c
Merge tag 'cpumask-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty...
[karo-tx-linux.git] / kernel / events / core.c
index d7d71d6ec97278cf60fa5b13e79a80bff27b6af2..f1cf0edeb39afa1a3f6543a2f383ac8c4828127b 100644 (file)
@@ -1645,6 +1645,8 @@ perf_install_in_context(struct perf_event_context *ctx,
        lockdep_assert_held(&ctx->mutex);
 
        event->ctx = ctx;
+       if (event->cpu != -1)
+               event->cpu = cpu;
 
        if (!task) {
                /*
@@ -6252,6 +6254,8 @@ SYSCALL_DEFINE5(perf_event_open,
                }
        }
 
+       get_online_cpus();
+
        event = perf_event_alloc(&attr, cpu, task, group_leader, NULL,
                                 NULL, NULL);
        if (IS_ERR(event)) {
@@ -6304,7 +6308,7 @@ SYSCALL_DEFINE5(perf_event_open,
        /*
         * Get the target context (task or percpu):
         */
-       ctx = find_get_context(pmu, task, cpu);
+       ctx = find_get_context(pmu, task, event->cpu);
        if (IS_ERR(ctx)) {
                err = PTR_ERR(ctx);
                goto err_alloc;
@@ -6377,20 +6381,23 @@ SYSCALL_DEFINE5(perf_event_open,
        mutex_lock(&ctx->mutex);
 
        if (move_group) {
-               perf_install_in_context(ctx, group_leader, cpu);
+               synchronize_rcu();
+               perf_install_in_context(ctx, group_leader, event->cpu);
                get_ctx(ctx);
                list_for_each_entry(sibling, &group_leader->sibling_list,
                                    group_entry) {
-                       perf_install_in_context(ctx, sibling, cpu);
+                       perf_install_in_context(ctx, sibling, event->cpu);
                        get_ctx(ctx);
                }
        }
 
-       perf_install_in_context(ctx, event, cpu);
+       perf_install_in_context(ctx, event, event->cpu);
        ++ctx->generation;
        perf_unpin_context(ctx);
        mutex_unlock(&ctx->mutex);
 
+       put_online_cpus();
+
        event->owner = current;
 
        mutex_lock(&current->perf_event_mutex);
@@ -6419,6 +6426,7 @@ err_context:
 err_alloc:
        free_event(event);
 err_task:
+       put_online_cpus();
        if (task)
                put_task_struct(task);
 err_group_fd:
@@ -6479,6 +6487,39 @@ err:
 }
 EXPORT_SYMBOL_GPL(perf_event_create_kernel_counter);
 
+void perf_pmu_migrate_context(struct pmu *pmu, int src_cpu, int dst_cpu)
+{
+       struct perf_event_context *src_ctx;
+       struct perf_event_context *dst_ctx;
+       struct perf_event *event, *tmp;
+       LIST_HEAD(events);
+
+       src_ctx = &per_cpu_ptr(pmu->pmu_cpu_context, src_cpu)->ctx;
+       dst_ctx = &per_cpu_ptr(pmu->pmu_cpu_context, dst_cpu)->ctx;
+
+       mutex_lock(&src_ctx->mutex);
+       list_for_each_entry_safe(event, tmp, &src_ctx->event_list,
+                                event_entry) {
+               perf_remove_from_context(event);
+               put_ctx(src_ctx);
+               list_add(&event->event_entry, &events);
+       }
+       mutex_unlock(&src_ctx->mutex);
+
+       synchronize_rcu();
+
+       mutex_lock(&dst_ctx->mutex);
+       list_for_each_entry_safe(event, tmp, &events, event_entry) {
+               list_del(&event->event_entry);
+               if (event->state >= PERF_EVENT_STATE_OFF)
+                       event->state = PERF_EVENT_STATE_INACTIVE;
+               perf_install_in_context(dst_ctx, event, dst_cpu);
+               get_ctx(dst_ctx);
+       }
+       mutex_unlock(&dst_ctx->mutex);
+}
+EXPORT_SYMBOL_GPL(perf_pmu_migrate_context);
+
 static void sync_child_event(struct perf_event *child_event,
                               struct task_struct *child)
 {