diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2010-03-03 09:55:04 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-03-10 07:22:23 -0500 |
commit | dc1d628a67a8f042e711ea5accc0beedc3ef0092 (patch) | |
tree | 728f72a5f9a8368b225890a95ea947c1c8cda301 | |
parent | 548b84166917d6f5e2296123b85ad24aecd3801d (diff) |
perf: Provide generic perf_sample_data initialization
This makes it easier to extend perf_sample_data and fixes a bug on arm
and sparc, which failed to set ->raw to NULL, which can cause crashes
when combined with PERF_SAMPLE_RAW.
It also optimizes PowerPC and tracepoint, because the struct
initialization is forced to zero out the whole structure.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Acked-by: Jean Pihet <jpihet@mvista.com>
Reviewed-by: Frederic Weisbecker <fweisbec@gmail.com>
Acked-by: David S. Miller <davem@davemloft.net>
Cc: Jamie Iles <jamie.iles@picochip.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: stable@kernel.org
LKML-Reference: <20100304140100.315416040@chello.nl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/arm/kernel/perf_event.c | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/perf_event.c | 8 | ||||
-rw-r--r-- | arch/sparc/kernel/perf_event.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event.c | 3 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel.c | 6 | ||||
-rw-r--r-- | include/linux/perf_event.h | 7 | ||||
-rw-r--r-- | kernel/perf_event.c | 21 |
7 files changed, 25 insertions, 26 deletions
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index c54ceb3d1f97..3875d99cc40f 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c | |||
@@ -965,7 +965,7 @@ armv6pmu_handle_irq(int irq_num, | |||
965 | */ | 965 | */ |
966 | armv6_pmcr_write(pmcr); | 966 | armv6_pmcr_write(pmcr); |
967 | 967 | ||
968 | data.addr = 0; | 968 | perf_sample_data_init(&data, 0); |
969 | 969 | ||
970 | cpuc = &__get_cpu_var(cpu_hw_events); | 970 | cpuc = &__get_cpu_var(cpu_hw_events); |
971 | for (idx = 0; idx <= armpmu->num_events; ++idx) { | 971 | for (idx = 0; idx <= armpmu->num_events; ++idx) { |
@@ -1945,7 +1945,7 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) | |||
1945 | */ | 1945 | */ |
1946 | regs = get_irq_regs(); | 1946 | regs = get_irq_regs(); |
1947 | 1947 | ||
1948 | data.addr = 0; | 1948 | perf_sample_data_init(&data, 0); |
1949 | 1949 | ||
1950 | cpuc = &__get_cpu_var(cpu_hw_events); | 1950 | cpuc = &__get_cpu_var(cpu_hw_events); |
1951 | for (idx = 0; idx <= armpmu->num_events; ++idx) { | 1951 | for (idx = 0; idx <= armpmu->num_events; ++idx) { |
diff --git a/arch/powerpc/kernel/perf_event.c b/arch/powerpc/kernel/perf_event.c index b6cf8f1f4d35..5120bd44f69a 100644 --- a/arch/powerpc/kernel/perf_event.c +++ b/arch/powerpc/kernel/perf_event.c | |||
@@ -1164,10 +1164,10 @@ static void record_and_restart(struct perf_event *event, unsigned long val, | |||
1164 | * Finally record data if requested. | 1164 | * Finally record data if requested. |
1165 | */ | 1165 | */ |
1166 | if (record) { | 1166 | if (record) { |
1167 | struct perf_sample_data data = { | 1167 | struct perf_sample_data data; |
1168 | .addr = ~0ULL, | 1168 | |
1169 | .period = event->hw.last_period, | 1169 | perf_sample_data_init(&data, ~0ULL); |
1170 | }; | 1170 | data.period = event->hw.last_period; |
1171 | 1171 | ||
1172 | if (event->attr.sample_type & PERF_SAMPLE_ADDR) | 1172 | if (event->attr.sample_type & PERF_SAMPLE_ADDR) |
1173 | perf_get_data_addr(regs, &data.addr); | 1173 | perf_get_data_addr(regs, &data.addr); |
diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index 9f2b2bac8b2b..6504208f375f 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c | |||
@@ -1189,7 +1189,7 @@ static int __kprobes perf_event_nmi_handler(struct notifier_block *self, | |||
1189 | 1189 | ||
1190 | regs = args->regs; | 1190 | regs = args->regs; |
1191 | 1191 | ||
1192 | data.addr = 0; | 1192 | perf_sample_data_init(&data, 0); |
1193 | 1193 | ||
1194 | cpuc = &__get_cpu_var(cpu_hw_events); | 1194 | cpuc = &__get_cpu_var(cpu_hw_events); |
1195 | 1195 | ||
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 97cddbf32936..42aafd11e170 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c | |||
@@ -1097,8 +1097,7 @@ static int x86_pmu_handle_irq(struct pt_regs *regs) | |||
1097 | int idx, handled = 0; | 1097 | int idx, handled = 0; |
1098 | u64 val; | 1098 | u64 val; |
1099 | 1099 | ||
1100 | data.addr = 0; | 1100 | perf_sample_data_init(&data, 0); |
1101 | data.raw = NULL; | ||
1102 | 1101 | ||
1103 | cpuc = &__get_cpu_var(cpu_hw_events); | 1102 | cpuc = &__get_cpu_var(cpu_hw_events); |
1104 | 1103 | ||
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 73102df8bfc1..44b60c852107 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c | |||
@@ -590,10 +590,9 @@ static void intel_pmu_drain_bts_buffer(void) | |||
590 | 590 | ||
591 | ds->bts_index = ds->bts_buffer_base; | 591 | ds->bts_index = ds->bts_buffer_base; |
592 | 592 | ||
593 | perf_sample_data_init(&data, 0); | ||
593 | 594 | ||
594 | data.period = event->hw.last_period; | 595 | data.period = event->hw.last_period; |
595 | data.addr = 0; | ||
596 | data.raw = NULL; | ||
597 | regs.ip = 0; | 596 | regs.ip = 0; |
598 | 597 | ||
599 | /* | 598 | /* |
@@ -742,8 +741,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) | |||
742 | int bit, loops; | 741 | int bit, loops; |
743 | u64 ack, status; | 742 | u64 ack, status; |
744 | 743 | ||
745 | data.addr = 0; | 744 | perf_sample_data_init(&data, 0); |
746 | data.raw = NULL; | ||
747 | 745 | ||
748 | cpuc = &__get_cpu_var(cpu_hw_events); | 746 | cpuc = &__get_cpu_var(cpu_hw_events); |
749 | 747 | ||
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 90e0521b1690..6f8cd7da1a01 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
@@ -801,6 +801,13 @@ struct perf_sample_data { | |||
801 | struct perf_raw_record *raw; | 801 | struct perf_raw_record *raw; |
802 | }; | 802 | }; |
803 | 803 | ||
804 | static inline | ||
805 | void perf_sample_data_init(struct perf_sample_data *data, u64 addr) | ||
806 | { | ||
807 | data->addr = addr; | ||
808 | data->raw = NULL; | ||
809 | } | ||
810 | |||
804 | extern void perf_output_sample(struct perf_output_handle *handle, | 811 | extern void perf_output_sample(struct perf_output_handle *handle, |
805 | struct perf_event_header *header, | 812 | struct perf_event_header *header, |
806 | struct perf_sample_data *data, | 813 | struct perf_sample_data *data, |
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index e68745053013..4393b9e73740 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
@@ -4108,8 +4108,7 @@ void __perf_sw_event(u32 event_id, u64 nr, int nmi, | |||
4108 | if (rctx < 0) | 4108 | if (rctx < 0) |
4109 | return; | 4109 | return; |
4110 | 4110 | ||
4111 | data.addr = addr; | 4111 | perf_sample_data_init(&data, addr); |
4112 | data.raw = NULL; | ||
4113 | 4112 | ||
4114 | do_perf_sw_event(PERF_TYPE_SOFTWARE, event_id, nr, nmi, &data, regs); | 4113 | do_perf_sw_event(PERF_TYPE_SOFTWARE, event_id, nr, nmi, &data, regs); |
4115 | 4114 | ||
@@ -4154,11 +4153,10 @@ static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer) | |||
4154 | struct perf_event *event; | 4153 | struct perf_event *event; |
4155 | u64 period; | 4154 | u64 period; |
4156 | 4155 | ||
4157 | event = container_of(hrtimer, struct perf_event, hw.hrtimer); | 4156 | event = container_of(hrtimer, struct perf_event, hw.hrtimer); |
4158 | event->pmu->read(event); | 4157 | event->pmu->read(event); |
4159 | 4158 | ||
4160 | data.addr = 0; | 4159 | perf_sample_data_init(&data, 0); |
4161 | data.raw = NULL; | ||
4162 | data.period = event->hw.last_period; | 4160 | data.period = event->hw.last_period; |
4163 | regs = get_irq_regs(); | 4161 | regs = get_irq_regs(); |
4164 | /* | 4162 | /* |
@@ -4322,17 +4320,15 @@ static const struct pmu perf_ops_task_clock = { | |||
4322 | void perf_tp_event(int event_id, u64 addr, u64 count, void *record, | 4320 | void perf_tp_event(int event_id, u64 addr, u64 count, void *record, |
4323 | int entry_size) | 4321 | int entry_size) |
4324 | { | 4322 | { |
4323 | struct pt_regs *regs = get_irq_regs(); | ||
4324 | struct perf_sample_data data; | ||
4325 | struct perf_raw_record raw = { | 4325 | struct perf_raw_record raw = { |
4326 | .size = entry_size, | 4326 | .size = entry_size, |
4327 | .data = record, | 4327 | .data = record, |
4328 | }; | 4328 | }; |
4329 | 4329 | ||
4330 | struct perf_sample_data data = { | 4330 | perf_sample_data_init(&data, addr); |
4331 | .addr = addr, | 4331 | data.raw = &raw; |
4332 | .raw = &raw, | ||
4333 | }; | ||
4334 | |||
4335 | struct pt_regs *regs = get_irq_regs(); | ||
4336 | 4332 | ||
4337 | if (!regs) | 4333 | if (!regs) |
4338 | regs = task_pt_regs(current); | 4334 | regs = task_pt_regs(current); |
@@ -4448,8 +4444,7 @@ void perf_bp_event(struct perf_event *bp, void *data) | |||
4448 | struct perf_sample_data sample; | 4444 | struct perf_sample_data sample; |
4449 | struct pt_regs *regs = data; | 4445 | struct pt_regs *regs = data; |
4450 | 4446 | ||
4451 | sample.raw = NULL; | 4447 | perf_sample_data_init(&sample, bp->attr.bp_addr); |
4452 | sample.addr = bp->attr.bp_addr; | ||
4453 | 4448 | ||
4454 | if (!perf_exclude_event(bp, regs)) | 4449 | if (!perf_exclude_event(bp, regs)) |
4455 | perf_swevent_add(bp, 1, 1, &sample, regs); | 4450 | perf_swevent_add(bp, 1, 1, &sample, regs); |