perf/x86: set pmu->module in Intel PMU modules
Subsystems (2)
PATCH 1/1 perf/x86: set pmu->module in Intel PMU modules
The conversion of Intel PMU drivers into modules did not include reference counting. The machine will crash when attempting to access deleted code if an event from a module PMU is started and the module removed before the event is destroyed.
i.e. this crashes the machine:
$ insmod intel-rapl-perf.ko $ perf stat -e power/energy-cores/ -C 0 & $ rmmod intel-rapl-perf.ko
Set THIS_MODULE to pmu->module in Intel module PMUs so that generic code can handle reference counting and deny rmmod while an event still exists.
--- arch/x86/events/intel/cstate.c | 2 ++ arch/x86/events/intel/rapl.c | 1 + arch/x86/events/intel/uncore.c | 1 + 3 files changed, 4 insertions(+)
arch/x86/events/intel/cstate.c +2 -0
@@ -434,6 +434,7 @@ static struct pmu cstate_core_pmu = { .stop = cstate_pmu_event_stop, .read = cstate_pmu_event_update, .capabilities = PERF_PMU_CAP_NO_INTERRUPT, + .module = THIS_MODULE, };static struct pmu cstate_pkg_pmu = {
@@ -447,6 +448,7 @@ static struct pmu cstate_pkg_pmu = { .stop = cstate_pmu_event_stop, .read = cstate_pmu_event_update, .capabilities = PERF_PMU_CAP_NO_INTERRUPT, + .module = THIS_MODULE, };static const struct cstate_model nhm_cstates__initconst = {
arch/x86/events/intel/rapl.c +1 -0
@@ -697,6 +697,7 @@ static int __init init_rapl_pmus(void) rapl_pmus->pmu.start = rapl_pmu_event_start; rapl_pmus->pmu.stop = rapl_pmu_event_stop; rapl_pmus->pmu.read = rapl_pmu_event_read; + rapl_pmus->pmu.module =THIS_MODULE ;return 0 ; }
arch/x86/events/intel/uncore.c +1 -0
@@ -733,6 +733,7 @@ static int uncore_pmu_register(struct intel_uncore_pmu *pmu) .start = uncore_pmu_event_start, .stop = uncore_pmu_event_stop, .read = uncore_pmu_event_read, + .module = THIS_MODULE, }; }else { pmu->pmu = *pmu->type->pmu;
Signature · 1 line
2.8.0.rc3.226.g39d4020
tip-bot for David Carrillo-Cisneros
merge bot[tip:perf/urgent] perf/x86: Set pmu->module in Intel PMU modules
perf/x86: Set pmu->module in Intel PMU modules
Commit-ID: 74545f63890e38520eb4d1dbedcadaa9c0dbc824 Gitweb: http://git.kernel.org/tip/74545f63890e38520eb4d1dbedcadaa9c0dbc824 Author: David Carrillo-Cisneros <[email protected]> AuthorDate: Thu, 22 Dec 2016 17:17:40 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 5 Jan 2017 09:13:55 +0100
perf/x86: Set pmu->module in Intel PMU modules
The conversion of Intel PMU drivers into modules did not include reference counting. The machine will crash when attempting to access deleted code if an event from a module PMU is started and the module removed before the event is destroyed.
i.e. this crashes the machine:
$ insmod intel-rapl-perf.ko $ perf stat -e power/energy-cores/ -C 0 & $ rmmod intel-rapl-perf.ko
Set THIS_MODULE to pmu->module in Intel module PMUs so that generic code can handle reference counting and deny rmmod while an event still exists.
--- arch/x86/events/intel/cstate.c | 2 ++ arch/x86/events/intel/rapl.c | 1 + arch/x86/events/intel/uncore.c | 1 + 3 files changed, 4 insertions(+)
arch/x86/events/intel/cstate.c +2 -0
@@ -434,6 +434,7 @@ static struct pmu cstate_core_pmu = { .stop = cstate_pmu_event_stop, .read = cstate_pmu_event_update, .capabilities = PERF_PMU_CAP_NO_INTERRUPT, + .module = THIS_MODULE, };static struct pmu cstate_pkg_pmu = {
@@ -447,6 +448,7 @@ static struct pmu cstate_pkg_pmu = { .stop = cstate_pmu_event_stop, .read = cstate_pmu_event_update, .capabilities = PERF_PMU_CAP_NO_INTERRUPT, + .module = THIS_MODULE, };static const struct cstate_model nhm_cstates__initconst = {
arch/x86/events/intel/rapl.c +1 -0
@@ -697,6 +697,7 @@ static int __init init_rapl_pmus(void) rapl_pmus->pmu.start = rapl_pmu_event_start; rapl_pmus->pmu.stop = rapl_pmu_event_stop; rapl_pmus->pmu.read = rapl_pmu_event_read; + rapl_pmus->pmu.module =THIS_MODULE ;return 0 ; }
arch/x86/events/intel/uncore.c +1 -0
@@ -733,6 +733,7 @@ static int uncore_pmu_register(struct intel_uncore_pmu *pmu) .start = uncore_pmu_event_start, .stop = uncore_pmu_event_stop, .read = uncore_pmu_event_read, + .module = THIS_MODULE, }; }else { pmu->pmu = *pmu->type->pmu;
Peter Zijlstra
maintainerRe: [tip:perf/urgent] perf/x86: Set pmu->module in Intel PMU modules
Quoted 35 lines · tip-bot for David Carrillo-Cisneros
arch/x86/events/intel/cstate.c +2
-0@@ -434,6 +434,7 @@ static struct pmu cstate_core_pmu = { .stop = cstate_pmu_event_stop, .read = cstate_pmu_event_update, .capabilities = PERF_PMU_CAP_NO_INTERRUPT, + .module = THIS_MODULE, };static struct pmu cstate_pkg_pmu = {@@ -447,6 +448,7 @@ static struct pmu cstate_pkg_pmu = { .stop = cstate_pmu_event_stop, .read = cstate_pmu_event_update, .capabilities = PERF_PMU_CAP_NO_INTERRUPT, + .module = THIS_MODULE, };static const struct cstate_model nhm_cstates__initconst = {arch/x86/events/intel/rapl.c +1
-0@@ -697,6 +697,7 @@ static int __init init_rapl_pmus(void) rapl_pmus->pmu.start = rapl_pmu_event_start; rapl_pmus->pmu.stop = rapl_pmu_event_stop; rapl_pmus->pmu.read = rapl_pmu_event_read; + rapl_pmus->pmu.module =THIS_MODULE ;return 0 ; }arch/x86/events/intel/uncore.c +0
-0
arch/x86/events/intel/uncore.c static int uncore_pmu_register(struct intel_uncore_pmu *pmu) · line 739
Quoted 7 lines
arch/x86/events/intel/uncore.c +1
-0@@ -733,6 +733,7 @@ static int uncore_pmu_register(struct intel_uncore_pmu *pmu) .start = uncore_pmu_event_start, .stop = uncore_pmu_event_stop, .read = uncore_pmu_event_read, + .module = THIS_MODULE, }; }else { pmu->pmu = *pmu->type->pmu;
Ah, forgot about this, thanks for picking it up.
The first time I saw this I thought about doing something like the below, but never got around to testing if that works and subsequently forgot about things again.
Does this make sense and or work?
---
include/linux/perf_event.h +8 -1
@@ -852,7 +852,14 @@ extern int perf_aux_output_skip(struct perf_output_handle *handle, unsigned long size);extern void *perf_get_aux (struct perf_output_handle *handle); -extern int perf_pmu_register (struct pmu *pmu,const char *name,int type); +extern int __perf_pmu_register (struct pmu *pmu,const char *name,int type); + +#define perf_pmu_register (_pmu, _name, _type) \ +({ \ + (_pmu)->module = THIS_MODULE; \ + __perf_pmu_register((_pmu), (_name), (_type)); \ +}) +extern void perf_pmu_unregister (struct pmu *pmu);extern int perf_num_counters (void );
kernel/events/core.c +1 -1
@@ -8752,7 +8767,7 @@ static int pmu_dev_alloc(struct pmu *pmu)static struct lock_class_key cpuctx_mutex;static struct lock_class_key cpuctx_lock; -int perf_pmu_register (struct pmu *pmu,const char *name,int type) +int __perf_pmu_register (struct pmu *pmu,const char *name,int type) {int cpu, ret;
Re: [tip:perf/urgent] perf/x86: Set pmu->module in Intel PMU modules
Quoted 6 lines · Peter Zijlstra
The first time I saw this I thought about doing something like the below, but never got around to testing if that works and subsequently forgot about things again.
Does this make sense and or work?
I'd argue against it.
It will "work", but it's fragile. In particular, if something ever ends up using perf_pmu_register() through some indirect helper function, it will do the wrong thing, because
include/linux/perf_event.h extern int perf_aux_output_skip(struct perf_output_handle *handle, · line 861
Quoted 5 lines
include/linux/perf_event.h +5
-0+#define perf_pmu_register (_pmu, _name, _type) \ +({ \ + (_pmu)->module = THIS_MODULE; \ + __perf_pmu_register((_pmu), (_name), (_type)); \ +})
.. at that point "THIS_MODULE" could be the module that contains the helper function that may not actually be the actual end-point module.
Looking at the situation right now, that never happens and all the users seem to be "leaf" modules. But it would worry me a bit.
Linus
Peter Zijlstra
maintainerRe: [tip:perf/urgent] perf/x86: Set pmu->module in Intel PMU modules
Quoted 9 lines · Linus Torvalds
Quoted 6 lines · Peter Zijlstra
The first time I saw this I thought about doing something like the below, but never got around to testing if that works and subsequently forgot about things again.
Does this make sense and or work?
I'd argue against it.
Fair enough; /me files it in the bit-bucket.