Skip to content

Commit a91f86e

Browse files
Lisa Robinsonchenhuacai
authored andcommitted
LoongArch: Fix PMU counter allocation for mixed-type event groups
When validating a perf event group, validate_group() unconditionally attempts to allocate hardware PMU counters for the leader, sibling events and the new event being added. This is incorrect for mixed-type groups. If a PERF_TYPE_SOFTWARE event is part of the group, the current code still tries to allocate a hardware PMU counter for it, which can wrongly consume hardware PMU resources and cause spurious allocation failures. Fix this by only allocating PMU counters for hardware events during group validation, and skipping software events. A trimmed down reproducer is as simple as this: #include <stdio.h> #include <assert.h> #include <unistd.h> #include <string.h> #include <sys/syscall.h> #include <linux/perf_event.h> int main (int argc, char *argv[]) { struct perf_event_attr attr = { 0 }; int fds[5]; attr.disabled = 1; attr.exclude_kernel = 1; attr.exclude_hv = 1; attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_ID | PERF_FORMAT_GROUP; attr.size = sizeof (attr); attr.type = PERF_TYPE_SOFTWARE; attr.config = PERF_COUNT_SW_DUMMY; fds[0] = syscall (SYS_perf_event_open, &attr, 0, -1, -1, 0); assert (fds[0] >= 0); attr.type = PERF_TYPE_HARDWARE; attr.config = PERF_COUNT_HW_CPU_CYCLES; fds[1] = syscall (SYS_perf_event_open, &attr, 0, -1, fds[0], 0); assert (fds[1] >= 0); attr.type = PERF_TYPE_HARDWARE; attr.config = PERF_COUNT_HW_INSTRUCTIONS; fds[2] = syscall (SYS_perf_event_open, &attr, 0, -1, fds[0], 0); assert (fds[2] >= 0); attr.type = PERF_TYPE_HARDWARE; attr.config = PERF_COUNT_HW_BRANCH_MISSES; fds[3] = syscall (SYS_perf_event_open, &attr, 0, -1, fds[0], 0); assert (fds[3] >= 0); attr.type = PERF_TYPE_HARDWARE; attr.config = PERF_COUNT_HW_CACHE_REFERENCES; fds[4] = syscall (SYS_perf_event_open, &attr, 0, -1, fds[0], 0); assert (fds[4] >= 0); printf ("PASSED\n"); return 0; } Cc: stable@vger.kernel.org Fixes: b37042b ("LoongArch: Add perf events support") Signed-off-by: Lisa Robinson <lisa@bytefly.space> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
1 parent 0d26ca8 commit a91f86e

1 file changed

Lines changed: 18 additions & 3 deletions

File tree

arch/loongarch/kernel/perf_event.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -626,22 +626,37 @@ static const struct loongarch_perf_event *loongarch_pmu_map_cache_event(u64 conf
626626
return pev;
627627
}
628628

629+
static inline bool loongarch_pmu_event_requires_counter(const struct perf_event *event)
630+
{
631+
switch (event->attr.type) {
632+
case PERF_TYPE_HARDWARE:
633+
case PERF_TYPE_HW_CACHE:
634+
case PERF_TYPE_RAW:
635+
return true;
636+
default:
637+
return false;
638+
}
639+
}
640+
629641
static int validate_group(struct perf_event *event)
630642
{
631643
struct cpu_hw_events fake_cpuc;
632644
struct perf_event *sibling, *leader = event->group_leader;
633645

634646
memset(&fake_cpuc, 0, sizeof(fake_cpuc));
635647

636-
if (loongarch_pmu_alloc_counter(&fake_cpuc, &leader->hw) < 0)
648+
if (loongarch_pmu_event_requires_counter(leader) &&
649+
loongarch_pmu_alloc_counter(&fake_cpuc, &leader->hw) < 0)
637650
return -EINVAL;
638651

639652
for_each_sibling_event(sibling, leader) {
640-
if (loongarch_pmu_alloc_counter(&fake_cpuc, &sibling->hw) < 0)
653+
if (loongarch_pmu_event_requires_counter(sibling) &&
654+
loongarch_pmu_alloc_counter(&fake_cpuc, &sibling->hw) < 0)
641655
return -EINVAL;
642656
}
643657

644-
if (loongarch_pmu_alloc_counter(&fake_cpuc, &event->hw) < 0)
658+
if (loongarch_pmu_event_requires_counter(event) &&
659+
loongarch_pmu_alloc_counter(&fake_cpuc, &event->hw) < 0)
645660
return -EINVAL;
646661

647662
return 0;

0 commit comments

Comments
 (0)