summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2010-08-29 20:52:00 +0200
committerRobert Richter <robert.richter@amd.com>2010-08-31 11:49:07 +0200
commitc7fd239a647ead1c336a051012d6bb96465ea8c6 (patch)
tree0ea0d2f251c1979a05d5e10bae1a0296187b95ac
parentoprofile: don't call arch exit code from init code on failure (diff)
downloadlinux-c7fd239a647ead1c336a051012d6bb96465ea8c6.tar.xz
linux-c7fd239a647ead1c336a051012d6bb96465ea8c6.zip
ARM: oprofile: fix and simplify init/exit functions
Now that oprofile_arch_exit is only called when the OProfile module is unloaded, it can assume that init completed successfully and not have to worry about double frees or releasing NULL perf events. This patch ensures that oprofile_arch_init fails gracefully on ARM and simplifies the exit code based on the above. Cc: Robert Richter <robert.richter@amd.com> Cc: Matt Fleming <matt@console-pimps.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Ingo Molnar <mingo@elte.hu> Signed-off-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Robert Richter <robert.richter@amd.com>
-rw-r--r--arch/arm/oprofile/common.c47
1 files changed, 25 insertions, 22 deletions
diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c
index 0691176899ff..c3652f73fed4 100644
--- a/arch/arm/oprofile/common.c
+++ b/arch/arm/oprofile/common.c
@@ -275,7 +275,7 @@ out:
return ret;
}
-static void exit_driverfs(void)
+static void __exit exit_driverfs(void)
{
platform_device_unregister(oprofile_pdev);
platform_driver_unregister(&oprofile_driver);
@@ -359,14 +359,13 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
if (!counter_config) {
pr_info("oprofile: failed to allocate %d "
"counters\n", perf_num_counters);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out;
}
ret = init_driverfs();
- if (ret) {
- kfree(counter_config);
- return ret;
- }
+ if (ret)
+ goto out;
for_each_possible_cpu(cpu) {
perf_events[cpu] = kcalloc(perf_num_counters,
@@ -374,9 +373,8 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
if (!perf_events[cpu]) {
pr_info("oprofile: failed to allocate %d perf events "
"for cpu %d\n", perf_num_counters, cpu);
- while (--cpu >= 0)
- kfree(perf_events[cpu]);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out;
}
}
@@ -393,28 +391,33 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
else
pr_info("oprofile: using %s\n", ops->cpu_type);
+out:
+ if (ret) {
+ for_each_possible_cpu(cpu)
+ kfree(perf_events[cpu]);
+ kfree(counter_config);
+ }
+
return ret;
}
-void oprofile_arch_exit(void)
+void __exit oprofile_arch_exit(void)
{
int cpu, id;
struct perf_event *event;
- if (*perf_events) {
- exit_driverfs();
- for_each_possible_cpu(cpu) {
- for (id = 0; id < perf_num_counters; ++id) {
- event = perf_events[cpu][id];
- if (event != NULL)
- perf_event_release_kernel(event);
- }
- kfree(perf_events[cpu]);
+ for_each_possible_cpu(cpu) {
+ for (id = 0; id < perf_num_counters; ++id) {
+ event = perf_events[cpu][id];
+ if (event)
+ perf_event_release_kernel(event);
}
+
+ kfree(perf_events[cpu]);
}
- if (counter_config)
- kfree(counter_config);
+ kfree(counter_config);
+ exit_driverfs();
}
#else
int __init oprofile_arch_init(struct oprofile_operations *ops)
@@ -422,5 +425,5 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
pr_info("oprofile: hardware counters not available\n");
return -ENODEV;
}
-void oprofile_arch_exit(void) {}
+void __exit oprofile_arch_exit(void) {}
#endif /* CONFIG_HW_PERF_EVENTS */