Re: [PATCH] perf/bpf: Fix lockless access to parent_event->prog in perf_event_alloc()

From: kernel test robot

Date: Mon Aug 24 2026 - 18:53:45 EST


Hi Deepanshu,

kernel test robot noticed the following build errors:

[auto build test ERROR on perf-tools-next/perf-tools-next]
[also build test ERROR on tip/perf/core perf-tools/perf-tools linus/master v7.2 next-20260821]
[cannot apply to acme/perf/core]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/Deepanshu-Kartikey/perf-bpf-Fix-lockless-access-to-parent_event-prog-in-perf_event_alloc/20260821-071210
base: https://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git perf-tools-next
patch link: https://lore.kernel.org/r/20260821014210.18681-1-kartikey406%40gmail.com
patch subject: [PATCH] perf/bpf: Fix lockless access to parent_event->prog in perf_event_alloc()
config: sparc-randconfig-002-20260825 (https://download.01.org/0day-ci/archive/20260825/202608250601.kP2R1VQE-lkp@xxxxxxxxx/config)
compiler: sparc64-linux-gcc (GCC) 12.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260825/202608250601.kP2R1VQE-lkp@xxxxxxxxx/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@xxxxxxxxx>
| Closes: https://lore.kernel.org/oe-kbuild-all/202608250601.kP2R1VQE-lkp@xxxxxxxxx/

All errors (new ones prefixed by >>):

sparc64-linux-ld: kernel/events/core.o: in function `perf_event_alloc':
>> kernel/events/core.c:13438:(.text+0x9be0): undefined reference to `bpf_event_mutex'
>> sparc64-linux-ld: kernel/events/core.c:13438:(.text+0x9bec): undefined reference to `bpf_event_mutex'
sparc64-linux-ld: kernel/events/core.c:13444:(.text+0x9c14): undefined reference to `bpf_event_mutex'


vim +13438 kernel/events/core.c

13340
13341 /*
13342 * Allocate and initialize an event structure
13343 */
13344 static struct perf_event *
13345 perf_event_alloc(struct perf_event_attr *attr, int cpu,
13346 struct task_struct *task,
13347 struct perf_event *group_leader,
13348 struct perf_event *parent_event,
13349 perf_overflow_handler_t overflow_handler,
13350 void *context, int cgroup_fd)
13351 {
13352 struct pmu *pmu;
13353 struct hw_perf_event *hwc;
13354 long err = -EINVAL;
13355 int node;
13356
13357 if ((unsigned)cpu >= nr_cpu_ids) {
13358 if (!task || cpu != -1)
13359 return ERR_PTR(-EINVAL);
13360 }
13361 if (attr->sigtrap && !task) {
13362 /* Requires a task: avoid signalling random tasks. */
13363 return ERR_PTR(-EINVAL);
13364 }
13365
13366 node = (cpu >= 0) ? cpu_to_node(cpu) : -1;
13367 struct perf_event *event __free(__free_event) =
13368 kmem_cache_alloc_node(perf_event_cache, GFP_KERNEL | __GFP_ZERO, node);
13369 if (!event)
13370 return ERR_PTR(-ENOMEM);
13371
13372 /*
13373 * Single events are their own group leaders, with an
13374 * empty sibling list:
13375 */
13376 if (!group_leader)
13377 group_leader = event;
13378
13379 mutex_init(&event->child_mutex);
13380 INIT_LIST_HEAD(&event->child_list);
13381
13382 INIT_LIST_HEAD(&event->event_entry);
13383 INIT_LIST_HEAD(&event->sibling_list);
13384 INIT_LIST_HEAD(&event->active_list);
13385 init_event_group(event);
13386 INIT_LIST_HEAD(&event->rb_entry);
13387 INIT_LIST_HEAD(&event->active_entry);
13388 INIT_LIST_HEAD(&event->addr_filters.list);
13389 INIT_HLIST_NODE(&event->hlist_entry);
13390 INIT_LIST_HEAD(&event->pmu_list);
13391
13392
13393 init_waitqueue_head(&event->waitq);
13394 init_irq_work(&event->pending_irq, perf_pending_irq);
13395 event->pending_disable_irq = IRQ_WORK_INIT_HARD(perf_pending_disable);
13396 init_task_work(&event->pending_task, perf_pending_task);
13397
13398 mutex_init(&event->mmap_mutex);
13399 raw_spin_lock_init(&event->addr_filters.lock);
13400
13401 atomic_long_set(&event->refcount, 1);
13402 event->cpu = cpu;
13403 event->attr = *attr;
13404 event->group_leader = group_leader;
13405 event->pmu = NULL;
13406 event->oncpu = -1;
13407
13408 event->parent = parent_event;
13409
13410 event->ns = get_pid_ns(task_active_pid_ns(current));
13411 event->id = atomic64_inc_return(&perf_event_id);
13412
13413 event->state = PERF_EVENT_STATE_INACTIVE;
13414
13415 if (parent_event)
13416 event->event_caps = parent_event->event_caps;
13417
13418 if (task) {
13419 event->attach_state = PERF_ATTACH_TASK;
13420 /*
13421 * XXX pmu::event_init needs to know what task to account to
13422 * and we cannot use the ctx information because we need the
13423 * pmu before we get a ctx.
13424 */
13425 event->hw.target = get_task_struct(task);
13426 }
13427
13428 event->clock = &local_clock;
13429 if (parent_event)
13430 event->clock = parent_event->clock;
13431
13432 if (!overflow_handler && parent_event) {
13433 overflow_handler = parent_event->overflow_handler;
13434 context = parent_event->overflow_handler_context;
13435 #if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_EVENT_TRACING)
13436 struct bpf_prog *prog;
13437
13438 mutex_lock(&bpf_event_mutex);
13439 prog = parent_event->prog;
13440 if (prog) {
13441 bpf_prog_inc(prog);
13442 event->prog = prog;
13443 }
13444 mutex_unlock(&bpf_event_mutex);
13445 #endif
13446 }
13447
13448 if (overflow_handler) {
13449 event->overflow_handler = overflow_handler;
13450 event->overflow_handler_context = context;
13451 } else if (is_write_backward(event)){
13452 event->overflow_handler = perf_event_output_backward;
13453 event->overflow_handler_context = NULL;
13454 } else {
13455 event->overflow_handler = perf_event_output_forward;
13456 event->overflow_handler_context = NULL;
13457 }
13458
13459 perf_event__state_init(event);
13460
13461 pmu = NULL;
13462
13463 hwc = &event->hw;
13464 hwc->sample_period = attr->sample_period;
13465 if (is_event_in_freq_mode(event))
13466 hwc->sample_period = 1;
13467 hwc->last_period = hwc->sample_period;
13468
13469 local64_set(&hwc->period_left, hwc->sample_period);
13470
13471 /*
13472 * We do not support PERF_SAMPLE_READ on inherited events unless
13473 * PERF_SAMPLE_TID is also selected, which allows inherited events to
13474 * collect per-thread samples.
13475 * See perf_output_read().
13476 */
13477 if (has_inherit_and_sample_read(attr) && !(attr->sample_type & PERF_SAMPLE_TID))
13478 return ERR_PTR(-EINVAL);
13479
13480 if (!has_branch_stack(event))
13481 event->attr.branch_sample_type = 0;
13482
13483 pmu = perf_init_event(event);
13484 if (IS_ERR(pmu))
13485 return (void*)pmu;
13486
13487 /*
13488 * The PERF_ATTACH_TASK_DATA is set in the event_init()->hw_config().
13489 * The attach should be right after the perf_init_event().
13490 * Otherwise, the __free_event() would mistakenly detach the non-exist
13491 * perf_ctx_data because of the other errors between them.
13492 */
13493 if (event->attach_state & PERF_ATTACH_TASK_DATA) {
13494 err = attach_perf_ctx_data(event);
13495 if (err)
13496 return ERR_PTR(err);
13497 }
13498
13499 /*
13500 * Disallow uncore-task events. Similarly, disallow uncore-cgroup
13501 * events (they don't make sense as the cgroup will be different
13502 * on other CPUs in the uncore mask).
13503 */
13504 if (pmu->task_ctx_nr == perf_invalid_context && (task || cgroup_fd != -1))
13505 return ERR_PTR(-EINVAL);
13506
13507 if (event->attr.aux_output &&
13508 (!(pmu->capabilities & PERF_PMU_CAP_AUX_OUTPUT) ||
13509 event->attr.aux_pause || event->attr.aux_resume))
13510 return ERR_PTR(-EOPNOTSUPP);
13511
13512 if (event->attr.aux_pause && event->attr.aux_resume)
13513 return ERR_PTR(-EINVAL);
13514
13515 if (event->attr.aux_start_paused) {
13516 if (!(pmu->capabilities & PERF_PMU_CAP_AUX_PAUSE))
13517 return ERR_PTR(-EOPNOTSUPP);
13518 event->hw.aux_paused = 1;
13519 }
13520
13521 if (cgroup_fd != -1) {
13522 err = perf_cgroup_connect(cgroup_fd, event, attr, group_leader);
13523 if (err)
13524 return ERR_PTR(err);
13525 }
13526
13527 err = exclusive_event_init(event);
13528 if (err)
13529 return ERR_PTR(err);
13530
13531 if (has_addr_filter(event)) {
13532 event->addr_filter_ranges = kcalloc(pmu->nr_addr_filters,
13533 sizeof(struct perf_addr_filter_range),
13534 GFP_KERNEL);
13535 if (!event->addr_filter_ranges)
13536 return ERR_PTR(-ENOMEM);
13537
13538 /*
13539 * Clone the parent's vma offsets: they are valid until exec()
13540 * even if the mm is not shared with the parent.
13541 */
13542 if (event->parent) {
13543 struct perf_addr_filters_head *ifh = perf_event_addr_filters(event);
13544
13545 raw_spin_lock_irq(&ifh->lock);
13546 memcpy(event->addr_filter_ranges,
13547 event->parent->addr_filter_ranges,
13548 pmu->nr_addr_filters * sizeof(struct perf_addr_filter_range));
13549 raw_spin_unlock_irq(&ifh->lock);
13550 }
13551
13552 /* force hw sync on the address filters */
13553 event->addr_filters_gen = 1;
13554 }
13555
13556 if (!event->parent) {
13557 if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN) {
13558 err = get_callchain_buffers(attr->sample_max_stack);
13559 if (err)
13560 return ERR_PTR(err);
13561 event->attach_state |= PERF_ATTACH_CALLCHAIN;
13562 }
13563 }
13564
13565 err = security_perf_event_alloc(event);
13566 if (err)
13567 return ERR_PTR(err);
13568
13569 err = mediated_pmu_account_event(event);
13570 if (err)
13571 return ERR_PTR(err);
13572
13573 /* symmetric to unaccount_event() in _free_event() */
13574 account_event(event);
13575
13576 /*
13577 * Event creation should be under SRCU, see perf_pmu_unregister().
13578 */
13579 lockdep_assert_held(&pmus_srcu);
13580 scoped_guard (spinlock, &pmu->events_lock)
13581 list_add(&event->pmu_list, &pmu->events);
13582
13583 return_ptr(event);
13584 }
13585

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki