diff options
author | Yan, Zheng <zheng.z.yan@intel.com> | 2014-03-18 04:56:41 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-04-18 06:54:45 -0400 |
commit | c464c76eec4be587604ca082e8cded7e6b89f3bf (patch) | |
tree | 673036d1b0058e3703ef53b69cf7547ae469141d /kernel/events/core.c | |
parent | 1111b680d34bc19190f02a1b4479c3fcc592c22e (diff) |
perf: Allow building PMU drivers as modules
This patch adds support for building PMU driver as module. It exports
the functions perf_pmu_{register,unregister}() and adds reference tracking
for the PMU driver module.
When the PMU driver is built as a module, each active event of the PMU
holds a reference to the driver module.
Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1395133004-23205-1-git-send-email-zheng.z.yan@intel.com
Cc: eranian@google.com
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/events/core.c')
-rw-r--r-- | kernel/events/core.c | 15 |
1 files changed, 15 insertions, 0 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c index f83a71a3e46d..5129b1201050 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/hw_breakpoint.h> | 39 | #include <linux/hw_breakpoint.h> |
40 | #include <linux/mm_types.h> | 40 | #include <linux/mm_types.h> |
41 | #include <linux/cgroup.h> | 41 | #include <linux/cgroup.h> |
42 | #include <linux/module.h> | ||
42 | 43 | ||
43 | #include "internal.h" | 44 | #include "internal.h" |
44 | 45 | ||
@@ -3229,6 +3230,9 @@ static void __free_event(struct perf_event *event) | |||
3229 | if (event->ctx) | 3230 | if (event->ctx) |
3230 | put_ctx(event->ctx); | 3231 | put_ctx(event->ctx); |
3231 | 3232 | ||
3233 | if (event->pmu) | ||
3234 | module_put(event->pmu->module); | ||
3235 | |||
3232 | call_rcu(&event->rcu_head, free_event_rcu); | 3236 | call_rcu(&event->rcu_head, free_event_rcu); |
3233 | } | 3237 | } |
3234 | static void free_event(struct perf_event *event) | 3238 | static void free_event(struct perf_event *event) |
@@ -6551,6 +6555,7 @@ free_pdc: | |||
6551 | free_percpu(pmu->pmu_disable_count); | 6555 | free_percpu(pmu->pmu_disable_count); |
6552 | goto unlock; | 6556 | goto unlock; |
6553 | } | 6557 | } |
6558 | EXPORT_SYMBOL_GPL(perf_pmu_register); | ||
6554 | 6559 | ||
6555 | void perf_pmu_unregister(struct pmu *pmu) | 6560 | void perf_pmu_unregister(struct pmu *pmu) |
6556 | { | 6561 | { |
@@ -6572,6 +6577,7 @@ void perf_pmu_unregister(struct pmu *pmu) | |||
6572 | put_device(pmu->dev); | 6577 | put_device(pmu->dev); |
6573 | free_pmu_context(pmu); | 6578 | free_pmu_context(pmu); |
6574 | } | 6579 | } |
6580 | EXPORT_SYMBOL_GPL(perf_pmu_unregister); | ||
6575 | 6581 | ||
6576 | struct pmu *perf_init_event(struct perf_event *event) | 6582 | struct pmu *perf_init_event(struct perf_event *event) |
6577 | { | 6583 | { |
@@ -6585,6 +6591,10 @@ struct pmu *perf_init_event(struct perf_event *event) | |||
6585 | pmu = idr_find(&pmu_idr, event->attr.type); | 6591 | pmu = idr_find(&pmu_idr, event->attr.type); |
6586 | rcu_read_unlock(); | 6592 | rcu_read_unlock(); |
6587 | if (pmu) { | 6593 | if (pmu) { |
6594 | if (!try_module_get(pmu->module)) { | ||
6595 | pmu = ERR_PTR(-ENODEV); | ||
6596 | goto unlock; | ||
6597 | } | ||
6588 | event->pmu = pmu; | 6598 | event->pmu = pmu; |
6589 | ret = pmu->event_init(event); | 6599 | ret = pmu->event_init(event); |
6590 | if (ret) | 6600 | if (ret) |
@@ -6593,6 +6603,10 @@ struct pmu *perf_init_event(struct perf_event *event) | |||
6593 | } | 6603 | } |
6594 | 6604 | ||
6595 | list_for_each_entry_rcu(pmu, &pmus, entry) { | 6605 | list_for_each_entry_rcu(pmu, &pmus, entry) { |
6606 | if (!try_module_get(pmu->module)) { | ||
6607 | pmu = ERR_PTR(-ENODEV); | ||
6608 | goto unlock; | ||
6609 | } | ||
6596 | event->pmu = pmu; | 6610 | event->pmu = pmu; |
6597 | ret = pmu->event_init(event); | 6611 | ret = pmu->event_init(event); |
6598 | if (!ret) | 6612 | if (!ret) |
@@ -6771,6 +6785,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, | |||
6771 | err_pmu: | 6785 | err_pmu: |
6772 | if (event->destroy) | 6786 | if (event->destroy) |
6773 | event->destroy(event); | 6787 | event->destroy(event); |
6788 | module_put(pmu->module); | ||
6774 | err_ns: | 6789 | err_ns: |
6775 | if (event->ns) | 6790 | if (event->ns) |
6776 | put_pid_ns(event->ns); | 6791 | put_pid_ns(event->ns); |