aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Olsa <jolsa@redhat.com>2016-10-20 07:10:11 -0400
committerIngo Molnar <mingo@kernel.org>2016-10-28 05:06:25 -0400
commit0933840acf7b65d6d30a5b6089d882afea57aca3 (patch)
treed70660c9cc59695decc9860a0446d4dd476feeac
parent889882bce2a5f69242c1f3acd840983f467499b9 (diff)
perf/core: Protect PMU device removal with a 'pmu_bus_running' check, to fix CONFIG_DEBUG_TEST_DRIVER_REMOVE=y kernel panic
CAI Qian reported a crash in the PMU uncore device removal code, enabled by the CONFIG_DEBUG_TEST_DRIVER_REMOVE=y option: https://marc.info/?l=linux-kernel&m=147688837328451 The reason for the crash is that perf_pmu_unregister() tries to remove a PMU device which is not added at this point. We add PMU devices only after pmu_bus is registered, which happens in the perf_event_sysfs_init() call and sets the 'pmu_bus_running' flag. The fix is to get the 'pmu_bus_running' flag state at the point the PMU is taken out of the PMU list and remove the device later only if it's set. Reported-by: CAI Qian <caiqian@redhat.com> Tested-by: CAI Qian <caiqian@redhat.com> Signed-off-by: Jiri Olsa <jolsa@kernel.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Kan Liang <kan.liang@intel.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Rob Herring <robh@kernel.org> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/20161020111011.GA13361@krava Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--kernel/events/core.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c
index c6e47e97b33f..a5d2e62faf7e 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -8855,7 +8855,10 @@ EXPORT_SYMBOL_GPL(perf_pmu_register);
8855 8855
8856void perf_pmu_unregister(struct pmu *pmu) 8856void perf_pmu_unregister(struct pmu *pmu)
8857{ 8857{
8858 int remove_device;
8859
8858 mutex_lock(&pmus_lock); 8860 mutex_lock(&pmus_lock);
8861 remove_device = pmu_bus_running;
8859 list_del_rcu(&pmu->entry); 8862 list_del_rcu(&pmu->entry);
8860 mutex_unlock(&pmus_lock); 8863 mutex_unlock(&pmus_lock);
8861 8864
@@ -8869,10 +8872,12 @@ void perf_pmu_unregister(struct pmu *pmu)
8869 free_percpu(pmu->pmu_disable_count); 8872 free_percpu(pmu->pmu_disable_count);
8870 if (pmu->type >= PERF_TYPE_MAX) 8873 if (pmu->type >= PERF_TYPE_MAX)
8871 idr_remove(&pmu_idr, pmu->type); 8874 idr_remove(&pmu_idr, pmu->type);
8872 if (pmu->nr_addr_filters) 8875 if (remove_device) {
8873 device_remove_file(pmu->dev, &dev_attr_nr_addr_filters); 8876 if (pmu->nr_addr_filters)
8874 device_del(pmu->dev); 8877 device_remove_file(pmu->dev, &dev_attr_nr_addr_filters);
8875 put_device(pmu->dev); 8878 device_del(pmu->dev);
8879 put_device(pmu->dev);
8880 }
8876 free_pmu_context(pmu); 8881 free_pmu_context(pmu);
8877} 8882}
8878EXPORT_SYMBOL_GPL(perf_pmu_unregister); 8883EXPORT_SYMBOL_GPL(perf_pmu_unregister);