diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-11-28 15:25:02 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-11-28 15:25:02 -0500 |
commit | a9e40a2493d805224f900d839b06188639b7ccd6 (patch) | |
tree | b33c9477a0728f6299a00a3e817aa26872019576 /kernel | |
parent | 75f5d2c9bd36047364d1fb35c0720ab37df3be02 (diff) | |
parent | ee6dcfa40a50fe12a3ae0fb4d2653c66c3ed6556 (diff) |
Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
perf: Fix the software context switch counter
perf, x86: Fixup Kconfig deps
x86, perf, nmi: Disable perf if counters are not accessible
perf: Fix inherit vs. context rotation bug
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/perf_event.c | 24 |
1 files changed, 20 insertions, 4 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 671f6c8c8a32..eac7e3364335 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
@@ -1287,8 +1287,6 @@ void __perf_event_task_sched_out(struct task_struct *task, | |||
1287 | { | 1287 | { |
1288 | int ctxn; | 1288 | int ctxn; |
1289 | 1289 | ||
1290 | perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 1, NULL, 0); | ||
1291 | |||
1292 | for_each_task_context_nr(ctxn) | 1290 | for_each_task_context_nr(ctxn) |
1293 | perf_event_context_sched_out(task, ctxn, next); | 1291 | perf_event_context_sched_out(task, ctxn, next); |
1294 | } | 1292 | } |
@@ -1622,8 +1620,12 @@ static void rotate_ctx(struct perf_event_context *ctx) | |||
1622 | { | 1620 | { |
1623 | raw_spin_lock(&ctx->lock); | 1621 | raw_spin_lock(&ctx->lock); |
1624 | 1622 | ||
1625 | /* Rotate the first entry last of non-pinned groups */ | 1623 | /* |
1626 | list_rotate_left(&ctx->flexible_groups); | 1624 | * Rotate the first entry last of non-pinned groups. Rotation might be |
1625 | * disabled by the inheritance code. | ||
1626 | */ | ||
1627 | if (!ctx->rotate_disable) | ||
1628 | list_rotate_left(&ctx->flexible_groups); | ||
1627 | 1629 | ||
1628 | raw_spin_unlock(&ctx->lock); | 1630 | raw_spin_unlock(&ctx->lock); |
1629 | } | 1631 | } |
@@ -6162,6 +6164,7 @@ int perf_event_init_context(struct task_struct *child, int ctxn) | |||
6162 | struct perf_event *event; | 6164 | struct perf_event *event; |
6163 | struct task_struct *parent = current; | 6165 | struct task_struct *parent = current; |
6164 | int inherited_all = 1; | 6166 | int inherited_all = 1; |
6167 | unsigned long flags; | ||
6165 | int ret = 0; | 6168 | int ret = 0; |
6166 | 6169 | ||
6167 | child->perf_event_ctxp[ctxn] = NULL; | 6170 | child->perf_event_ctxp[ctxn] = NULL; |
@@ -6202,6 +6205,15 @@ int perf_event_init_context(struct task_struct *child, int ctxn) | |||
6202 | break; | 6205 | break; |
6203 | } | 6206 | } |
6204 | 6207 | ||
6208 | /* | ||
6209 | * We can't hold ctx->lock when iterating the ->flexible_group list due | ||
6210 | * to allocations, but we need to prevent rotation because | ||
6211 | * rotate_ctx() will change the list from interrupt context. | ||
6212 | */ | ||
6213 | raw_spin_lock_irqsave(&parent_ctx->lock, flags); | ||
6214 | parent_ctx->rotate_disable = 1; | ||
6215 | raw_spin_unlock_irqrestore(&parent_ctx->lock, flags); | ||
6216 | |||
6205 | list_for_each_entry(event, &parent_ctx->flexible_groups, group_entry) { | 6217 | list_for_each_entry(event, &parent_ctx->flexible_groups, group_entry) { |
6206 | ret = inherit_task_group(event, parent, parent_ctx, | 6218 | ret = inherit_task_group(event, parent, parent_ctx, |
6207 | child, ctxn, &inherited_all); | 6219 | child, ctxn, &inherited_all); |
@@ -6209,6 +6221,10 @@ int perf_event_init_context(struct task_struct *child, int ctxn) | |||
6209 | break; | 6221 | break; |
6210 | } | 6222 | } |
6211 | 6223 | ||
6224 | raw_spin_lock_irqsave(&parent_ctx->lock, flags); | ||
6225 | parent_ctx->rotate_disable = 0; | ||
6226 | raw_spin_unlock_irqrestore(&parent_ctx->lock, flags); | ||
6227 | |||
6212 | child_ctx = child->perf_event_ctxp[ctxn]; | 6228 | child_ctx = child->perf_event_ctxp[ctxn]; |
6213 | 6229 | ||
6214 | if (child_ctx && inherited_all) { | 6230 | if (child_ctx && inherited_all) { |