|
@@ -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);
|