aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/events/core.c
diff options
context:
space:
mode:
authorYan, Zheng <zheng.z.yan@intel.com>2014-03-18 04:56:41 -0400
committerIngo Molnar <mingo@kernel.org>2014-04-18 06:54:45 -0400
commitc464c76eec4be587604ca082e8cded7e6b89f3bf (patch)
tree673036d1b0058e3703ef53b69cf7547ae469141d /kernel/events/core.c
parent1111b680d34bc19190f02a1b4479c3fcc592c22e (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.c15
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}
3234static void free_event(struct perf_event *event) 3238static 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}
6558EXPORT_SYMBOL_GPL(perf_pmu_register);
6554 6559
6555void perf_pmu_unregister(struct pmu *pmu) 6560void 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}
6580EXPORT_SYMBOL_GPL(perf_pmu_unregister);
6575 6581
6576struct pmu *perf_init_event(struct perf_event *event) 6582struct 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,
6771err_pmu: 6785err_pmu:
6772 if (event->destroy) 6786 if (event->destroy)
6773 event->destroy(event); 6787 event->destroy(event);
6788 module_put(pmu->module);
6774err_ns: 6789err_ns:
6775 if (event->ns) 6790 if (event->ns)
6776 put_pid_ns(event->ns); 6791 put_pid_ns(event->ns);