[PATCH v3 49/57] perf: Simplify perf_event_alloc()

From: Peter Zijlstra
Date: Mon Jun 12 2023 - 05:59:15 EST



Signed-off-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx>
---
kernel/events/core.c | 47 ++++++++++++++++++-----------------------------
1 file changed, 18 insertions(+), 29 deletions(-)

--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -5148,6 +5148,8 @@ static void __free_event(struct perf_eve
call_rcu(&event->rcu_head, free_event_rcu);
}

+DEFINE_FREE(__free_event, struct perf_event *, if (_T) __free_event(_T))
+
/* vs perf_event_alloc() success */
static void _free_event(struct perf_event *event)
{
@@ -11694,7 +11696,6 @@ perf_event_alloc(struct perf_event_attr
void *context, int cgroup_fd)
{
struct pmu *pmu;
- struct perf_event *event;
struct hw_perf_event *hwc;
long err = -EINVAL;
int node;
@@ -11709,8 +11710,8 @@ perf_event_alloc(struct perf_event_attr
}

node = (cpu >= 0) ? cpu_to_node(cpu) : -1;
- event = kmem_cache_alloc_node(perf_event_cache, GFP_KERNEL | __GFP_ZERO,
- node);
+ struct perf_event *event __free(__free_event) =
+ kmem_cache_alloc_node(perf_event_cache, GFP_KERNEL | __GFP_ZERO, node);
if (!event)
return ERR_PTR(-ENOMEM);

@@ -11815,51 +11816,43 @@ perf_event_alloc(struct perf_event_attr
* See perf_output_read().
*/
if (attr->inherit && (attr->sample_type & PERF_SAMPLE_READ))
- goto err;
+ return ERR_PTR(-EINVAL);

if (!has_branch_stack(event))
event->attr.branch_sample_type = 0;

pmu = perf_init_event(event);
- if (IS_ERR(pmu)) {
- err = PTR_ERR(pmu);
- goto err;
- }
+ if (IS_ERR(pmu))
+ return (void*)pmu;

/*
* Disallow uncore-task events. Similarly, disallow uncore-cgroup
* events (they don't make sense as the cgroup will be different
* on other CPUs in the uncore mask).
*/
- if (pmu->task_ctx_nr == perf_invalid_context && (task || cgroup_fd != -1)) {
- err = -EINVAL;
- goto err;
- }
+ if (pmu->task_ctx_nr == perf_invalid_context && (task || cgroup_fd != -1))
+ return ERR_PTR(-EINVAL);

if (event->attr.aux_output &&
- !(pmu->capabilities & PERF_PMU_CAP_AUX_OUTPUT)) {
- err = -EOPNOTSUPP;
- goto err;
- }
+ !(pmu->capabilities & PERF_PMU_CAP_AUX_OUTPUT))
+ return ERR_PTR(-EOPNOTSUPP);

if (cgroup_fd != -1) {
err = perf_cgroup_connect(cgroup_fd, event, attr, group_leader);
if (err)
- goto err;
+ return ERR_PTR(err);
}

err = exclusive_event_init(event);
if (err)
- goto err;
+ return ERR_PTR(err);

if (has_addr_filter(event)) {
event->addr_filter_ranges = kcalloc(pmu->nr_addr_filters,
sizeof(struct perf_addr_filter_range),
GFP_KERNEL);
- if (!event->addr_filter_ranges) {
- err = -ENOMEM;
- goto err;
- }
+ if (!event->addr_filter_ranges)
+ return ERR_PTR(-ENOMEM);

/*
* Clone the parent's vma offsets: they are valid until exec()
@@ -11883,22 +11876,18 @@ perf_event_alloc(struct perf_event_attr
if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN) {
err = get_callchain_buffers(attr->sample_max_stack);
if (err)
- goto err;
+ return ERR_PTR(err);
}
}

err = security_perf_event_alloc(event);
if (err)
- goto err;
+ return ERR_PTR(err);

/* symmetric to unaccount_event() in _free_event() */
account_event(event);

- return event;
-
-err:
- __free_event(event);
- return ERR_PTR(err);
+ return_ptr(event);
}

static int perf_copy_attr(struct perf_event_attr __user *uattr,