diff options
| author | Patrick Fay <pfay@codeaurora.org> | 2016-11-03 17:07:16 -0700 |
|---|---|---|
| committer | Patrick Fay <pfay@codeaurora.org> | 2017-01-16 11:52:33 -0800 |
| commit | 377c09d738d74ee059c100e4834fdc5c6736636d (patch) | |
| tree | 0ab4c025a681d7cd45b70d9a8ab7ae00990bd608 | |
| parent | 573979dee2a76e4d7f61cb867c12afbaed7e1eb5 (diff) | |
perf: Fix NULL pointer ref in exclude_idle update
Commit 573979dee2a7 ("perf: Add support for exclude_idle attribute")
registers an idle callback routine armv8pmu_idle_update. Currently
the idle update routine might be called before the pmu has allocated
all the per_cpu structures. This can result in a null pointer
reference. Change arm_pmu_device_probe to allocate the structures
via cpu_pmu_init() before the init_fn() call (which eventually does the
idle_notify_register call). Change a branch to out_free to
out_destroy as out_free doesn't cleanup what was allocated in
cpu_pmu_init(). Also have armv8pmu_idle_update check that the
structure is not null before using it.
Change-Id: Ie1198fc1783804c61467889c68656d6e8c9c9edf
Signed-off-by: Patrick Fay <pfay@codeaurora.org>
| -rw-r--r-- | arch/arm64/kernel/perf_event.c | 3 | ||||
| -rw-r--r-- | drivers/perf/arm_pmu.c | 10 |
2 files changed, 8 insertions, 5 deletions
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index 10db9cbaf49e..e8f5a17707d4 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -590,6 +590,9 @@ static void armv8pmu_idle_update(struct arm_pmu *cpu_pmu) hw_events = this_cpu_ptr(cpu_pmu->hw_events); + if (!hw_events) + return; + for (idx = 0; idx < cpu_pmu->num_events; ++idx) { if (!test_bit(idx, hw_events->used_mask)) diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index 71154ec99d3c..13b79438af1c 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -1051,6 +1051,10 @@ int arm_pmu_device_probe(struct platform_device *pdev, pmu->plat_device = pdev; + ret = cpu_pmu_init(pmu); + if (ret) + goto out_free; + if (node && (of_id = of_match_node(of_table, pdev->dev.of_node))) { init_fn = of_id->data; @@ -1073,13 +1077,9 @@ int arm_pmu_device_probe(struct platform_device *pdev, if (ret) { pr_info("%s: failed to probe PMU!\n", of_node_full_name(node)); - goto out_free; + goto out_destroy; } - ret = cpu_pmu_init(pmu); - if (ret) - goto out_free; - ret = perf_pmu_register(&pmu->pmu, pmu->name, -1); if (ret) goto out_destroy; |
