Re: [PATCH] perf/bpf: Fix lockless access to parent_event->prog in perf_event_alloc()
kernel test robot <[email protected]>
| Newsgroups | dev.linux.lists.oe-kbuild-all,org.kernel.vger.bpf,org.kernel.vger.linux-kernel,org.kernel.vger.linux-perf-users,org.kernel.vger.linux-trace-kernel |
|---|---|
| Message-ID | <[email protected]> |
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/[email protected]/config) compiler: sparc64-linux-gcc (GCC) 12.5.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260825/[email protected]/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 <[email protected]> | Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/ 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