|
@@ -1287,8 +1287,6 @@ void __perf_event_task_sched_out(struct task_struct *task,
|
|
|
{
|
|
|
int ctxn;
|
|
|
|
|
|
- perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 1, NULL, 0);
|
|
|
-
|
|
|
for_each_task_context_nr(ctxn)
|
|
|
perf_event_context_sched_out(task, ctxn, next);
|
|
|
}
|
|
@@ -1622,8 +1620,12 @@ static void rotate_ctx(struct perf_event_context *ctx)
|
|
|
{
|
|
|
raw_spin_lock(&ctx->lock);
|
|
|
|
|
|
- /* Rotate the first entry last of non-pinned groups */
|
|
|
- list_rotate_left(&ctx->flexible_groups);
|
|
|
+ /*
|
|
|
+ * Rotate the first entry last of non-pinned groups. Rotation might be
|
|
|
+ * disabled by the inheritance code.
|
|
|
+ */
|
|
|
+ if (!ctx->rotate_disable)
|
|
|
+ list_rotate_left(&ctx->flexible_groups);
|
|
|
|
|
|
raw_spin_unlock(&ctx->lock);
|
|
|
}
|
|
@@ -6162,6 +6164,7 @@ int perf_event_init_context(struct task_struct *child, int ctxn)
|
|
|
struct perf_event *event;
|
|
|
struct task_struct *parent = current;
|
|
|
int inherited_all = 1;
|
|
|
+ unsigned long flags;
|
|
|
int ret = 0;
|
|
|
|
|
|
child->perf_event_ctxp[ctxn] = NULL;
|
|
@@ -6202,6 +6205,15 @@ int perf_event_init_context(struct task_struct *child, int ctxn)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * We can't hold ctx->lock when iterating the ->flexible_group list due
|
|
|
+ * to allocations, but we need to prevent rotation because
|
|
|
+ * rotate_ctx() will change the list from interrupt context.
|
|
|
+ */
|
|
|
+ raw_spin_lock_irqsave(&parent_ctx->lock, flags);
|
|
|
+ parent_ctx->rotate_disable = 1;
|
|
|
+ raw_spin_unlock_irqrestore(&parent_ctx->lock, flags);
|
|
|
+
|
|
|
list_for_each_entry(event, &parent_ctx->flexible_groups, group_entry) {
|
|
|
ret = inherit_task_group(event, parent, parent_ctx,
|
|
|
child, ctxn, &inherited_all);
|
|
@@ -6209,6 +6221,10 @@ int perf_event_init_context(struct task_struct *child, int ctxn)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
+ raw_spin_lock_irqsave(&parent_ctx->lock, flags);
|
|
|
+ parent_ctx->rotate_disable = 0;
|
|
|
+ raw_spin_unlock_irqrestore(&parent_ctx->lock, flags);
|
|
|
+
|
|
|
child_ctx = child->perf_event_ctxp[ctxn];
|
|
|
|
|
|
if (child_ctx && inherited_all) {
|