forked from Minki/linux
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>
This commit is contained in:
parent
979048e1f2
commit
c7fd239a64
@ -275,7 +275,7 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exit_driverfs(void)
|
static void __exit exit_driverfs(void)
|
||||||
{
|
{
|
||||||
platform_device_unregister(oprofile_pdev);
|
platform_device_unregister(oprofile_pdev);
|
||||||
platform_driver_unregister(&oprofile_driver);
|
platform_driver_unregister(&oprofile_driver);
|
||||||
@ -359,14 +359,13 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
|
|||||||
if (!counter_config) {
|
if (!counter_config) {
|
||||||
pr_info("oprofile: failed to allocate %d "
|
pr_info("oprofile: failed to allocate %d "
|
||||||
"counters\n", perf_num_counters);
|
"counters\n", perf_num_counters);
|
||||||
return -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = init_driverfs();
|
ret = init_driverfs();
|
||||||
if (ret) {
|
if (ret)
|
||||||
kfree(counter_config);
|
goto out;
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
for_each_possible_cpu(cpu) {
|
for_each_possible_cpu(cpu) {
|
||||||
perf_events[cpu] = kcalloc(perf_num_counters,
|
perf_events[cpu] = kcalloc(perf_num_counters,
|
||||||
@ -374,9 +373,8 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
|
|||||||
if (!perf_events[cpu]) {
|
if (!perf_events[cpu]) {
|
||||||
pr_info("oprofile: failed to allocate %d perf events "
|
pr_info("oprofile: failed to allocate %d perf events "
|
||||||
"for cpu %d\n", perf_num_counters, cpu);
|
"for cpu %d\n", perf_num_counters, cpu);
|
||||||
while (--cpu >= 0)
|
ret = -ENOMEM;
|
||||||
kfree(perf_events[cpu]);
|
goto out;
|
||||||
return -ENOMEM;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,28 +391,33 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
|
|||||||
else
|
else
|
||||||
pr_info("oprofile: using %s\n", ops->cpu_type);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void oprofile_arch_exit(void)
|
void __exit oprofile_arch_exit(void)
|
||||||
{
|
{
|
||||||
int cpu, id;
|
int cpu, id;
|
||||||
struct perf_event *event;
|
struct perf_event *event;
|
||||||
|
|
||||||
if (*perf_events) {
|
for_each_possible_cpu(cpu) {
|
||||||
exit_driverfs();
|
for (id = 0; id < perf_num_counters; ++id) {
|
||||||
for_each_possible_cpu(cpu) {
|
event = perf_events[cpu][id];
|
||||||
for (id = 0; id < perf_num_counters; ++id) {
|
if (event)
|
||||||
event = perf_events[cpu][id];
|
perf_event_release_kernel(event);
|
||||||
if (event != NULL)
|
|
||||||
perf_event_release_kernel(event);
|
|
||||||
}
|
|
||||||
kfree(perf_events[cpu]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kfree(perf_events[cpu]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (counter_config)
|
kfree(counter_config);
|
||||||
kfree(counter_config);
|
exit_driverfs();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
int __init oprofile_arch_init(struct oprofile_operations *ops)
|
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");
|
pr_info("oprofile: hardware counters not available\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
void oprofile_arch_exit(void) {}
|
void __exit oprofile_arch_exit(void) {}
|
||||||
#endif /* CONFIG_HW_PERF_EVENTS */
|
#endif /* CONFIG_HW_PERF_EVENTS */
|
||||||
|
Loading…
Reference in New Issue
Block a user