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>
This commit is contained in:
Родитель
1111b680d3
Коммит
c464c76eec
|
@ -172,6 +172,7 @@ struct perf_event;
|
|||
struct pmu {
|
||||
struct list_head entry;
|
||||
|
||||
struct module *module;
|
||||
struct device *dev;
|
||||
const struct attribute_group **attr_groups;
|
||||
const char *name;
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include <linux/hw_breakpoint.h>
|
||||
#include <linux/mm_types.h>
|
||||
#include <linux/cgroup.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
|
@ -3229,6 +3230,9 @@ static void __free_event(struct perf_event *event)
|
|||
if (event->ctx)
|
||||
put_ctx(event->ctx);
|
||||
|
||||
if (event->pmu)
|
||||
module_put(event->pmu->module);
|
||||
|
||||
call_rcu(&event->rcu_head, free_event_rcu);
|
||||
}
|
||||
static void free_event(struct perf_event *event)
|
||||
|
@ -6551,6 +6555,7 @@ free_pdc:
|
|||
free_percpu(pmu->pmu_disable_count);
|
||||
goto unlock;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(perf_pmu_register);
|
||||
|
||||
void perf_pmu_unregister(struct pmu *pmu)
|
||||
{
|
||||
|
@ -6572,6 +6577,7 @@ void perf_pmu_unregister(struct pmu *pmu)
|
|||
put_device(pmu->dev);
|
||||
free_pmu_context(pmu);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(perf_pmu_unregister);
|
||||
|
||||
struct pmu *perf_init_event(struct perf_event *event)
|
||||
{
|
||||
|
@ -6585,6 +6591,10 @@ struct pmu *perf_init_event(struct perf_event *event)
|
|||
pmu = idr_find(&pmu_idr, event->attr.type);
|
||||
rcu_read_unlock();
|
||||
if (pmu) {
|
||||
if (!try_module_get(pmu->module)) {
|
||||
pmu = ERR_PTR(-ENODEV);
|
||||
goto unlock;
|
||||
}
|
||||
event->pmu = pmu;
|
||||
ret = pmu->event_init(event);
|
||||
if (ret)
|
||||
|
@ -6593,6 +6603,10 @@ struct pmu *perf_init_event(struct perf_event *event)
|
|||
}
|
||||
|
||||
list_for_each_entry_rcu(pmu, &pmus, entry) {
|
||||
if (!try_module_get(pmu->module)) {
|
||||
pmu = ERR_PTR(-ENODEV);
|
||||
goto unlock;
|
||||
}
|
||||
event->pmu = pmu;
|
||||
ret = pmu->event_init(event);
|
||||
if (!ret)
|
||||
|
@ -6771,6 +6785,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
|
|||
err_pmu:
|
||||
if (event->destroy)
|
||||
event->destroy(event);
|
||||
module_put(pmu->module);
|
||||
err_ns:
|
||||
if (event->ns)
|
||||
put_pid_ns(event->ns);
|
||||
|
|
Загрузка…
Ссылка в новой задаче