The error path of perf_pmu_register() is of course very similar to a subset of perf_pmu_unregister(). Extract this common part in __perf_pmu_unregister() and simplify things. Signed-off-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx> --- kernel/events/core.c | 51 ++++++++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 27 deletions(-) --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -11426,20 +11426,35 @@ static int pmu_dev_alloc(struct pmu *pmu static struct lock_class_key cpuctx_mutex; static struct lock_class_key cpuctx_lock; +static void __perf_pmu_unregister(struct pmu *pmu) +{ + free_percpu(pmu->pmu_disable_count); + if (pmu->type >= 0) + idr_remove(&pmu_idr, pmu->type); + if (pmu_bus_running && pmu->dev && pmu->dev != PMU_NULL_DEV) { + if (pmu->nr_addr_filters) + device_remove_file(pmu->dev, &dev_attr_nr_addr_filters); + device_del(pmu->dev); + put_device(pmu->dev); + } + free_pmu_context(pmu); +} + int perf_pmu_register(struct pmu *pmu, const char *name, int type) { int cpu, ret, max = PERF_TYPE_MAX; + pmu->type = -1; + mutex_lock(&pmus_lock); ret = -ENOMEM; pmu->pmu_disable_count = alloc_percpu(int); if (!pmu->pmu_disable_count) goto unlock; - pmu->type = -1; if (WARN_ONCE(!name, "Can not register anonymous pmu.\n")) { ret = -EINVAL; - goto free_pdc; + goto free; } pmu->name = name; @@ -11449,23 +11464,22 @@ int perf_pmu_register(struct pmu *pmu, c ret = idr_alloc(&pmu_idr, pmu, max, 0, GFP_KERNEL); if (ret < 0) - goto free_pdc; + goto free; WARN_ON(type >= 0 && ret != type); - type = ret; - pmu->type = type; + pmu->type = ret; if (pmu_bus_running && !pmu->dev) { ret = pmu_dev_alloc(pmu); if (ret) - goto free_idr; + goto free; } ret = -ENOMEM; pmu->cpu_pmu_context = alloc_percpu(struct perf_cpu_pmu_context); if (!pmu->cpu_pmu_context) - goto free_dev; + goto free; for_each_possible_cpu(cpu) { struct perf_cpu_pmu_context *cpc; @@ -11511,17 +11525,8 @@ int perf_pmu_register(struct pmu *pmu, c return ret; -free_dev: - if (pmu->dev && pmu->dev != PMU_NULL_DEV) { - device_del(pmu->dev); - put_device(pmu->dev); - } - -free_idr: - idr_remove(&pmu_idr, pmu->type); - -free_pdc: - free_percpu(pmu->pmu_disable_count); +free: + __perf_pmu_unregister(pmu); goto unlock; } EXPORT_SYMBOL_GPL(perf_pmu_register); @@ -11538,15 +11543,7 @@ void perf_pmu_unregister(struct pmu *pmu synchronize_srcu(&pmus_srcu); synchronize_rcu(); - free_percpu(pmu->pmu_disable_count); - idr_remove(&pmu_idr, pmu->type); - if (pmu_bus_running && pmu->dev && pmu->dev != PMU_NULL_DEV) { - if (pmu->nr_addr_filters) - device_remove_file(pmu->dev, &dev_attr_nr_addr_filters); - device_del(pmu->dev); - put_device(pmu->dev); - } - free_pmu_context(pmu); + __perf_pmu_unregister(pmu); mutex_unlock(&pmus_lock); } EXPORT_SYMBOL_GPL(perf_pmu_unregister);