Performance events changes for v7.1
Subsystems (2)
Linus,
Please pull the latest perf/core Git tree from:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git perf-core-2026-04-13
for you to fetch changes up to 5a84b600050c5f16b8bba25dd0e7aea845880407:
Performance events changes for v7.1:
Core updates:
- Try to allocate task_ctx_data quickly, to optimize O(N^2) algorithm on large systems with O(100k) threads (Namhyung Kim)
AMD PMU driver IBS support updates and fixes, by Ravi Bangoria:
- Fix interrupt accounting for discarded samples
- Fix a Zen5-specific quirk
- Fix PhyAddrVal handling
- Fix NMI-safety with perf_allow_kernel()
- Fix a race between event add and NMIs
Intel PMU driver updates:
- Only check GP counters for PEBS constraints validation (Dapeng Mi)
MSR driver:
- Turn SMI_COUNT and PPERF on by default, instead of a long list of CPU models to enable them on (Kan Liang)
Misc cleanups and fixes by Aldf Conte, Anshuman Khandual, Namhyung Kim, Ravi Bangoria and Yen-Hsiang Hsu.
Thanks,
Ingo
------------------>
Aldo Conte (1):
perf/x86/intel/p4: Fix unused variable warning in p4_pmu_init()
Anshuman Khandual (1):
perf/events: Replace READ_ONCE() with standard pgtable accessors
Dapeng Mi (1):
perf/x86/intel: Only check GP counters for PEBS constraints validation
Kan Liang (1):
perf/x86/msr: Make SMI and PPERF on by default
Namhyung Kim (3):
perf/core: Pass GFP flags to attach_task_ctx_data() perf/core: Try to allocate task_ctx_data quickly perf/core: Simplify __detach_global_ctx_data()
Ravi Bangoria (12):
perf/amd/ibs: Account interrupt for discarded samples perf/amd/ibs: Limit ldlat->l3missonly dependency to Zen5 perf/amd/ibs: Preserve PhyAddrVal bit when clearing PhyAddr MSR perf/amd/ibs: Avoid calling perf_allow_kernel() from the IBS NMI handler perf/amd/ibs: Avoid race between event add and NMI perf/amd/ibs: Define macro for ldlat mask and shift perf/amd/ibs: Add new MSRs and CPUID bits definitions perf/amd/ibs: Support IBS_{FETCH|OP}_CTL2[Dis] to eliminate RMW race perf/amd/ibs: Enable fetch latency filtering
perf/amd/ibs: Enable RIP bit63 hardware filtering perf/amd/ibs: Enable streaming store filter
perf/amd/ibs: Advertise remote socket capability
Yen-Hsiang Hsu (1):
perf/x86/amd/ibs: Fix comment typo in ibs_op_data
arch/x86/events/amd/ibs.c | 264 ++++++++++++++++++++++++++++++++--- arch/x86/events/intel/core.c | 22 +-- arch/x86/events/intel/p4.c | 6 +- arch/x86/events/msr.c | 82 +---------- arch/x86/events/perf_event_flags.h | 1 + arch/x86/include/asm/amd/ibs.h | 6 +- arch/x86/include/asm/msr-index.h | 2 + arch/x86/include/asm/perf_event.h | 55 +++++--- kernel/events/core.c | 43 +++--- tools/arch/x86/include/asm/amd/ibs.h | 2 +- 10 files changed, 331 insertions(+), 152 deletions(-)
arch/x86/events/amd/ibs.c +246 -18
@@ -32,6 +32,13 @@ static u32 ibs_caps;/* attr.config2 */ #define IBS_SW_FILTER_MASK 1 +/* attr.config1 */ +#define IBS_OP_CONFIG1_LDLAT_MASK (0xFFFULL << 0) +#define IBS_OP_CONFIG1_STRMST_MASK (1ULL << 12) +#define IBS_OP_CONFIG1_STRMST_SHIFT (12) + +#define IBS_FETCH_CONFIG1_FETCHLAT_MASK (0x7FFULL << 0) +/* * IBS states: *
@@ -83,9 +90,11 @@ struct cpu_perf_ibs {struct perf_ibs {struct pmu pmu;unsigned int msr; +unsigned int msr2;u64 config_mask;u64 cnt_mask;u64 enable_mask; +u64 disable_mask;u64 valid_mask;u16 min_period;u64 max_period;
@@ -274,7 +283,23 @@ static bool perf_ibs_ldlat_event(struct perf_ibs *perf_ibs, {return perf_ibs == &perf_ibs_op && (ibs_caps &IBS_CAPS_OPLDLAT ) && - (event->attr.config1 &0xFFF ); + (event->attr.config1 &IBS_OP_CONFIG1_LDLAT_MASK ); +} + +static bool perf_ibs_fetch_lat_event (struct perf_ibs *perf_ibs, +struct perf_event *event) +{ +return perf_ibs == &perf_ibs_fetch && + (ibs_caps &IBS_CAPS_FETCHLAT ) && + (event->attr.config1 &IBS_FETCH_CONFIG1_FETCHLAT_MASK ); +} + +static bool perf_ibs_strmst_event (struct perf_ibs *perf_ibs, +struct perf_event *event) +{ +return perf_ibs == &perf_ibs_op && + (ibs_caps &IBS_CAPS_STRMST_RMTSOCKET ) && + (event->attr.config1 &IBS_OP_CONFIG1_STRMST_MASK ); }static int perf_ibs_init (struct perf_event *event)
@@ -289,6 +314,8 @@ static int perf_ibs_init(struct perf_event *event)return -ENOENT ; config = event->attr.config; + hwc->extra_reg.config =0 ; + hwc->extra_reg.reg =0 ;if (event->pmu != &perf_ibs->pmu)return -ENOENT ;
@@ -304,15 +331,44 @@ static int perf_ibs_init(struct perf_event *event) event->attr.exclude_idle)return -EINVAL ; -if (!(event->attr.config2 &IBS_SW_FILTER_MASK ) && - (event->attr.exclude_kernel || event->attr.exclude_user || - event->attr.exclude_hv)) -return -EINVAL ; - ret =validate_group (event);if (ret)return ret; +if (perf_allow_kernel ()) + hwc->flags |=PERF_X86_EVENT_UNPRIVILEGED ; + +if (ibs_caps &IBS_CAPS_DIS ) { + hwc->extra_reg.config &= ~perf_ibs->disable_mask; + hwc->extra_reg.reg = perf_ibs->msr2; + } + +if (ibs_caps &IBS_CAPS_BIT63_FILTER ) { +if (perf_ibs == &perf_ibs_fetch) { +if (event->attr.exclude_kernel) { + hwc->extra_reg.config |=IBS_FETCH_2_EXCL_RIP_63_EQ_1 ; + hwc->extra_reg.reg = perf_ibs->msr2; + } +if (event->attr.exclude_user) { + hwc->extra_reg.config |=IBS_FETCH_2_EXCL_RIP_63_EQ_0 ; + hwc->extra_reg.reg = perf_ibs->msr2; + } + }else { +if (event->attr.exclude_kernel) { + hwc->extra_reg.config |=IBS_OP_2_EXCL_RIP_63_EQ_1 ; + hwc->extra_reg.reg = perf_ibs->msr2; + } +if (event->attr.exclude_user) { + hwc->extra_reg.config |=IBS_OP_2_EXCL_RIP_63_EQ_0 ; + hwc->extra_reg.reg = perf_ibs->msr2; + } + } + }else if (!(event->attr.config2 &IBS_SW_FILTER_MASK ) && + (event->attr.exclude_kernel || event->attr.exclude_user || + event->attr.exclude_hv)) { +return -EINVAL ; + } +if (hwc->sample_period) {if (config & perf_ibs->cnt_mask)/* raw max_cnt may not be set */
@@ -349,14 +405,37 @@ static int perf_ibs_init(struct perf_event *event) }if (perf_ibs_ldlat_event (perf_ibs, event)) { -u64 ldlat = event->attr.config1 &0xFFF ; +u64 ldlat = event->attr.config1 &IBS_OP_CONFIG1_LDLAT_MASK ;if (ldlat <128 || ldlat >2048 )return -EINVAL ; ldlat >>=7 ; - config |= (ldlat -1 ) <<59 ; - config |=IBS_OP_L3MISSONLY |IBS_OP_LDLAT_EN ; + config |= (ldlat -1 ) <<IBS_OP_LDLAT_THRSH_SHIFT ; + + config |=IBS_OP_LDLAT_EN ; +if (cpu_feature_enabled (X86_FEATURE_ZEN5 )) + config |=IBS_OP_L3MISSONLY ; + } + +if (perf_ibs_fetch_lat_event (perf_ibs, event)) { +u64 fetchlat = event->attr.config1 &IBS_FETCH_CONFIG1_FETCHLAT_MASK ; + +if (fetchlat <128 || fetchlat >1920 ) +return -EINVAL ; + fetchlat >>=7 ; + + hwc->extra_reg.reg = perf_ibs->msr2; + hwc->extra_reg.config |= fetchlat <<IBS_FETCH_2_FETCHLAT_FILTER_SHIFT ; + } + +if (perf_ibs_strmst_event (perf_ibs, event)) { +u64 strmst = event->attr.config1 &IBS_OP_CONFIG1_STRMST_MASK ; + + strmst >>=IBS_OP_CONFIG1_STRMST_SHIFT ; + + hwc->extra_reg.reg = perf_ibs->msr2; + hwc->extra_reg.config |= strmst <<IBS_OP_2_STRM_ST_FILTER_SHIFT ; }/*
@@ -439,6 +518,9 @@ static inline void perf_ibs_enable_event(struct perf_ibs *perf_ibs,wrmsrq (hwc->config_base, tmp & ~perf_ibs->enable_mask);wrmsrq (hwc->config_base, tmp | perf_ibs->enable_mask); + +if (hwc->extra_reg.reg) +wrmsrq (hwc->extra_reg.reg, hwc->extra_reg.config); }/*
@@ -451,6 +533,11 @@ static inline void perf_ibs_enable_event(struct perf_ibs *perf_ibs,static inline void perf_ibs_disable_event (struct perf_ibs *perf_ibs,struct hw_perf_event *hwc,u64 config) { +if (ibs_caps &IBS_CAPS_DIS ) { +wrmsrq (hwc->extra_reg.reg, perf_ibs->disable_mask); +return ; + } + config &= ~perf_ibs->cnt_mask;if (boot_cpu_data.x86 ==0x10 )wrmsrq (hwc->config_base, config);
@@ -487,6 +574,14 @@ static void perf_ibs_start(struct perf_event *event, int flags) } config |= period >>4 ; +/* +* Reset the IBS_{FETCH|OP}_CTL MSR before updating pcpu->state. +* Doing so prevents a race condition in which an NMI due to other +* source might accidentally activate the event before we enable +* it ourselves. +*/ +perf_ibs_disable_event (perf_ibs, hwc,0 ); +/* * Set STARTED before enabling the hardware, such that a subsequent NMI * must observe it.
@@ -631,6 +726,11 @@ PMU_EVENT_ATTR_STRING(ldlat, ibs_op_ldlat_format, "config1:0-11");PMU_EVENT_ATTR_STRING (zen4_ibs_extensions, zen4_ibs_extensions,"1" );PMU_EVENT_ATTR_STRING (ldlat, ibs_op_ldlat_cap,"1" );PMU_EVENT_ATTR_STRING (dtlb_pgsize, ibs_op_dtlb_pgsize_cap,"1" ); +PMU_EVENT_ATTR_STRING (fetchlat, ibs_fetch_lat_format,"config1:0-10" ); +PMU_EVENT_ATTR_STRING (fetchlat, ibs_fetch_lat_cap,"1" ); +PMU_EVENT_ATTR_STRING (strmst, ibs_op_strmst_format,"config1:12" ); +PMU_EVENT_ATTR_STRING (strmst, ibs_op_strmst_cap,"1" ); +PMU_EVENT_ATTR_STRING (rmtsocket, ibs_op_rmtsocket_cap,"1" );static umode_t zen4_ibs_extensions_is_visible (struct kobject *kobj,struct attribute *attr,int i)
@@ -638,6 +738,24 @@ zen4_ibs_extensions_is_visible(struct kobject *kobj, struct attribute *attr, intreturn ibs_caps &IBS_CAPS_ZEN4 ? attr->mode :0 ; } +static umode_t +ibs_fetch_lat_is_visible (struct kobject *kobj,struct attribute *attr,int i) +{ +return ibs_caps &IBS_CAPS_FETCHLAT ? attr->mode :0 ; +} + +static umode_t +ibs_op_strmst_is_visible (struct kobject *kobj,struct attribute *attr,int i) +{ +return ibs_caps &IBS_CAPS_STRMST_RMTSOCKET ? attr->mode :0 ; +} + +static umode_t +ibs_op_rmtsocket_is_visible (struct kobject *kobj,struct attribute *attr,int i) +{ +return ibs_caps &IBS_CAPS_STRMST_RMTSOCKET ? attr->mode :0 ; +} +static umode_t ibs_op_ldlat_is_visible (struct kobject *kobj,struct attribute *attr,int i) {
@@ -666,6 +784,16 @@ static struct attribute *zen4_ibs_extensions_attrs[] = { NULL, }; +static struct attribute *ibs_fetch_lat_format_attrs[] = { + &ibs_fetch_lat_format.attr.attr, +NULL , +}; + +static struct attribute *ibs_fetch_lat_cap_attrs[] = { + &ibs_fetch_lat_cap.attr.attr, +NULL , +}; +static struct attribute *ibs_op_ldlat_cap_attrs[] = { &ibs_op_ldlat_cap.attr.attr,NULL ,
@@ -676,6 +804,16 @@ static struct attribute *ibs_op_dtlb_pgsize_cap_attrs[] = { NULL, }; +static struct attribute *ibs_op_strmst_cap_attrs[] = { + &ibs_op_strmst_cap.attr.attr, +NULL , +}; + +static struct attribute *ibs_op_rmtsocket_cap_attrs[] = { + &ibs_op_rmtsocket_cap.attr.attr, +NULL , +}; +static struct attribute_group group_fetch_formats = { .name ="format" , .attrs = fetch_attrs,
@@ -693,6 +831,18 @@ static struct attribute_group group_zen4_ibs_extensions = { .is_visible = zen4_ibs_extensions_is_visible, }; +static struct attribute_group group_ibs_fetch_lat_cap = { + .name ="caps" , + .attrs = ibs_fetch_lat_cap_attrs, + .is_visible = ibs_fetch_lat_is_visible, +}; + +static struct attribute_group group_ibs_fetch_lat_format = { + .name ="format" , + .attrs = ibs_fetch_lat_format_attrs, + .is_visible = ibs_fetch_lat_is_visible, +}; +static struct attribute_group group_ibs_op_ldlat_cap = { .name ="caps" , .attrs = ibs_op_ldlat_cap_attrs,
@@ -705,6 +855,18 @@ static struct attribute_group group_ibs_op_dtlb_pgsize_cap = { .is_visible = ibs_op_dtlb_pgsize_is_visible, }; +static struct attribute_group group_ibs_op_strmst_cap = { + .name ="caps" , + .attrs = ibs_op_strmst_cap_attrs, + .is_visible = ibs_op_strmst_is_visible, +}; + +static struct attribute_group group_ibs_op_rmtsocket_cap = { + .name ="caps" , + .attrs = ibs_op_rmtsocket_cap_attrs, + .is_visible = ibs_op_rmtsocket_is_visible, +}; +static const struct attribute_group *fetch_attr_groups[] = { &group_fetch_formats, &empty_caps_group,
@@ -714,6 +876,8 @@ static const struct attribute_group *fetch_attr_groups[] = {static const struct attribute_group *fetch_attr_update[] = { &group_fetch_l3missonly, &group_zen4_ibs_extensions, + &group_ibs_fetch_lat_cap, + &group_ibs_fetch_lat_format,NULL , };
@@ -748,6 +912,11 @@ static struct attribute *ibs_op_ldlat_format_attrs[] = { NULL, }; +static struct attribute *ibs_op_strmst_format_attrs[] = { + &ibs_op_strmst_format.attr.attr, +NULL , +}; +static struct attribute_group group_cnt_ctl = { .name ="format" , .attrs = cnt_ctl_attrs,
@@ -772,6 +941,12 @@ static struct attribute_group group_ibs_op_ldlat_format = { .is_visible = ibs_op_ldlat_is_visible, }; +static struct attribute_group group_ibs_op_strmst_format = { + .name ="format" , + .attrs = ibs_op_strmst_format_attrs, + .is_visible = ibs_op_strmst_is_visible, +}; +static const struct attribute_group *op_attr_update[] = { &group_cnt_ctl, &group_op_l3missonly,
@@ -779,6 +954,9 @@ static const struct attribute_group *op_attr_update[] = { &group_ibs_op_ldlat_cap, &group_ibs_op_ldlat_format, &group_ibs_op_dtlb_pgsize_cap, + &group_ibs_op_strmst_cap, + &group_ibs_op_strmst_format, + &group_ibs_op_rmtsocket_cap, NULL, };
@@ -795,6 +973,7 @@ static struct perf_ibs perf_ibs_fetch = { .check_period = perf_ibs_check_period, }, .msr = MSR_AMD64_IBSFETCHCTL, + .msr2 = MSR_AMD64_IBSFETCHCTL2, .config_mask = IBS_FETCH_MAX_CNT | IBS_FETCH_RAND_EN, .cnt_mask = IBS_FETCH_MAX_CNT, .enable_mask = IBS_FETCH_ENABLE,
@@ -820,6 +999,7 @@ static struct perf_ibs perf_ibs_op = { .check_period = perf_ibs_check_period, }, .msr = MSR_AMD64_IBSOPCTL, + .msr2 = MSR_AMD64_IBSOPCTL2, .config_mask = IBS_OP_MAX_CNT, .cnt_mask =IBS_OP_MAX_CNT |IBS_OP_CUR_CNT | IBS_OP_CUR_CNT_RAND,
@@ -1155,7 +1335,8 @@ static int perf_ibs_get_offset_max(struct perf_ibs *perf_ibs, {if (event->attr.sample_type &PERF_SAMPLE_RAW ||perf_ibs_is_mem_sample_type (perf_ibs, event) || -perf_ibs_ldlat_event (perf_ibs, event)) +perf_ibs_ldlat_event (perf_ibs, event) || +perf_ibs_fetch_lat_event (perf_ibs, event))return perf_ibs->offset_max;else if (check_rip)return 3 ;
@@ -1190,7 +1371,7 @@ static bool perf_ibs_is_kernel_br_target(struct perf_event *event, op_data.op_brn_ret && kernel_ip(br_target)); } -static bool perf_ibs_swfilt_discard (struct perf_ibs *perf_ibs,struct perf_event *event, +static bool perf_ibs_discard_sample (struct perf_ibs *perf_ibs,struct perf_event *event,struct pt_regs *regs,struct perf_ibs_data *ibs_data,int br_target_idx) {
@@ -1214,12 +1395,10 @@ static void perf_ibs_phyaddr_clear(struct perf_ibs *perf_ibs, struct perf_ibs_data *ibs_data) {if (perf_ibs == &perf_ibs_op) { - ibs_data->regs[ibs_op_msr_idx (MSR_AMD64_IBSOPDATA3 )] &= ~(1ULL <<18 ); ibs_data->regs[ibs_op_msr_idx (MSR_AMD64_IBSDCPHYSAD )] =0 ;return ; } - ibs_data->regs[ibs_fetch_msr_idx (MSR_AMD64_IBSFETCHCTL )] &= ~(1ULL <<52 ); ibs_data->regs[ibs_fetch_msr_idx (MSR_AMD64_IBSFETCHPHYSAD )] =0 ; }
@@ -1293,8 +1472,20 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)* within [128, 2048] range. */ if (!op_data3.ld_op || !op_data3.dc_miss || - op_data3.dc_miss_lat <= (event->attr.config1 &0xFFF )) + op_data3.dc_miss_lat <= (event->attr.config1 &IBS_OP_CONFIG1_LDLAT_MASK )) { + throttle =perf_event_account_interrupt (event); goto out; + } + } + +if (perf_ibs_fetch_lat_event (perf_ibs, event)) { +union ibs_fetch_ctl fetch_ctl; + + fetch_ctl.val = ibs_data.regs[ibs_fetch_msr_idx (MSR_AMD64_IBSFETCHCTL )]; +if (fetch_ctl.fetch_lat < (event->attr.config1 &IBS_FETCH_CONFIG1_FETCHLAT_MASK )) { + throttle =perf_event_account_interrupt (event); + goto out; + } }/*
@@ -1326,15 +1517,18 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs) regs.flags &= ~PERF_EFLAGS_EXACT ; }else {/* Workaround for erratum #1197 */ -if (perf_ibs->fetch_ignore_if_zero_rip && !(ibs_data.regs[1 ])) +if (perf_ibs->fetch_ignore_if_zero_rip && !(ibs_data.regs[1 ])) { + throttle =perf_event_account_interrupt (event); goto out; + }set_linear_ip (®s, ibs_data.regs[1 ]); regs.flags |=PERF_EFLAGS_EXACT ; } -if ((event->attr.config2 &IBS_SW_FILTER_MASK ) && -perf_ibs_swfilt_discard (perf_ibs, event, ®s, &ibs_data, br_target_idx)) { +if (((ibs_caps &IBS_CAPS_BIT63_FILTER ) || + (event->attr.config2 &IBS_SW_FILTER_MASK )) && +perf_ibs_discard_sample (perf_ibs, event, ®s, &ibs_data, br_target_idx)) { throttle =perf_event_account_interrupt (event); goto out; }
@@ -1344,7 +1538,7 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)* unprivileged users. */ if ((event->attr.sample_type &PERF_SAMPLE_RAW ) && -perf_allow_kernel ()) { + (hwc->flags &PERF_X86_EVENT_UNPRIVILEGED )) {perf_ibs_phyaddr_clear (perf_ibs, &ibs_data); }
@@ -1375,6 +1569,9 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs) out:if (!throttle) { +if (ibs_caps &IBS_CAPS_DIS ) +wrmsrq (hwc->extra_reg.reg, perf_ibs->disable_mask); +if (perf_ibs == &perf_ibs_op) {if (ibs_caps &IBS_CAPS_OPCNTEXT ) { new_config = period &IBS_OP_MAX_CNT_EXT_MASK ;
@@ -1446,6 +1643,9 @@ static __init int perf_ibs_fetch_init(void)if (ibs_caps &IBS_CAPS_ZEN4 ) perf_ibs_fetch.config_mask |=IBS_FETCH_L3MISSONLY ; +if (ibs_caps &IBS_CAPS_DIS ) + perf_ibs_fetch.disable_mask =IBS_FETCH_2_DIS ; + perf_ibs_fetch.pmu.attr_groups = fetch_attr_groups; perf_ibs_fetch.pmu.attr_update = fetch_attr_update;
@@ -1467,6 +1667,9 @@ static __init int perf_ibs_op_init(void)if (ibs_caps &IBS_CAPS_ZEN4 ) perf_ibs_op.config_mask |=IBS_OP_L3MISSONLY ; +if (ibs_caps &IBS_CAPS_DIS ) + perf_ibs_op.disable_mask =IBS_OP_2_DIS ; + perf_ibs_op.pmu.attr_groups = op_attr_groups; perf_ibs_op.pmu.attr_update = op_attr_update;
@@ -1713,6 +1916,23 @@ static void clear_APIC_ibs(void)static int x86_pmu_amd_ibs_starting_cpu (unsigned int cpu) {setup_APIC_ibs (); + +if (ibs_caps &IBS_CAPS_DIS ) { +/* +* IBS enable sequence: +* CTL[En] = 1; +* CTL2[Dis] = 0; +* +* IBS disable sequence: +* CTL2[Dis] = 1; +* +* Set CTL2[Dis] when CPU comes up. This is needed to make +* enable sequence effective. +*/ +wrmsrq (MSR_AMD64_IBSFETCHCTL2 ,IBS_FETCH_2_DIS ); +wrmsrq (MSR_AMD64_IBSOPCTL2 ,IBS_OP_2_DIS ); + } +return 0 ; }
@@ -1771,6 +1991,14 @@ static __init int amd_ibs_init(void)perf_ibs_pm_init (); +#ifdef CONFIG_X86_32 +/* +* IBS_CAPS_BIT63_FILTER is used for exclude_kernel/user filtering, +* which obviously won't work for 32 bit kernel. +*/ + caps &= ~IBS_CAPS_BIT63_FILTER ; +#endif + ibs_caps = caps;/* make ibs_caps visible to other cpus: */ smp_mb ();
arch/x86/events/intel/core.c +14 -8
@@ -5770,7 +5770,7 @@ static void __intel_pmu_check_dyn_constr(struct event_constraint *constr, }if (check_fail) { -pr_info ("The two events 0x%llx and 0x%llx may not be " +pr_warn ("The two events 0x%llx and 0x%llx may not be " "fully scheduled under some circumstances as " "%s.\n" , c1->code, c2->code, dyn_constr_type_name[type]);
@@ -5783,6 +5783,7 @@ static void intel_pmu_check_dyn_constr(struct pmu *pmu, struct event_constraint *constr, u64 cntr_mask) { +u64 gp_mask =GENMASK_ULL (INTEL_PMC_MAX_GENERIC -1 ,0 );enum dyn_constr_type i;u64 mask;
@@ -5797,20 +5798,25 @@ static void intel_pmu_check_dyn_constr(struct pmu *pmu, mask = x86_pmu.lbr_counters;break ;case DYN_CONSTR_ACR_CNTR : - mask =hybrid (pmu, acr_cntr_mask64) &GENMASK_ULL (INTEL_PMC_MAX_GENERIC -1 ,0 ); + mask =hybrid (pmu, acr_cntr_mask64) & gp_mask;break ;case DYN_CONSTR_ACR_CAUSE : -if (hybrid (pmu, acr_cntr_mask64) ==hybrid (pmu, acr_cause_mask64)) +if (hybrid (pmu, acr_cntr_mask64) == +hybrid (pmu, acr_cause_mask64))continue ; - mask =hybrid (pmu, acr_cause_mask64) &GENMASK_ULL (INTEL_PMC_MAX_GENERIC -1 ,0 ); + mask =hybrid (pmu, acr_cause_mask64) & gp_mask;break ;case DYN_CONSTR_PEBS : -if (x86_pmu.arch_pebs) - mask =hybrid (pmu, arch_pebs_cap).counters; +if (x86_pmu.arch_pebs) { + mask =hybrid (pmu, arch_pebs_cap).counters & + gp_mask; + }break ;case DYN_CONSTR_PDIST : -if (x86_pmu.arch_pebs) - mask =hybrid (pmu, arch_pebs_cap).pdists; +if (x86_pmu.arch_pebs) { + mask =hybrid (pmu, arch_pebs_cap).pdists & + gp_mask; + }break ;default :pr_warn ("Unsupported dynamic constraint type %d\n" , i);
arch/x86/events/intel/p4.c +3 -3
@@ -1367,14 +1367,14 @@ static __initconst const struct x86_pmu p4_pmu = {__init int p4_pmu_init (void ) { -unsigned int low, high; +unsigned int misc;int i, reg;/* If we get stripped -- indexing fails */ BUILD_BUG_ON (ARCH_P4_MAX_CCCR >INTEL_PMC_MAX_GENERIC ); -rdmsr (MSR_IA32_MISC_ENABLE , low, high); -if (!(low & (1 <<7 ))) { +rdmsrq (MSR_IA32_MISC_ENABLE , misc); +if (!(misc &MSR_IA32_MISC_ENABLE_EMON )) {pr_cont ("unsupported Netburst CPU model %d " , boot_cpu_data.x86_model);return -ENODEV ;
arch/x86/events/msr.c +3 -79
96 lines not on this page · raw message
arch/x86/events/perf_event_flags.h +1 -0
@@ -23,3 +23,4 @@ PERF_ARCH(PEBS_LAT_HYBRID, 0x0020000) /* ld and st lat for hybrid */ PERF_ARCH(NEEDS_BRANCH_STACK, 0x0040000) /* require branch stack setup */ PERF_ARCH(BRANCH_COUNTERS, 0x0080000) /* logs the counters in the extra space of each branch */ PERF_ARCH(ACR, 0x0100000) /* Auto counter reload */ +PERF_ARCH (UNPRIVILEGED ,0x0200000 )/* Unprivileged event (wrt perf_allow_kernel()) */
arch/x86/include/asm/amd/ibs.h +4 -2
@@ -77,7 +77,7 @@ union ibs_op_data {__u64 val;struct {__u64 comp_to_ret_ctr:16 ,/* 0-15: op completion to retire count */ - tag_to_ret_ctr:16 ,/* 15-31: op tag to retire count */ + tag_to_ret_ctr:16 ,/* 16-31: op tag to retire count */ reserved1:2 ,/* 32-33: reserved */ op_return:1 ,/* 34: return op */ op_brn_taken:1, /* 35: taken branch op */
@@ -99,7 +99,9 @@ union ibs_op_data2 { rmt_node:1, /* 4: destination node */ cache_hit_st:1, /* 5: cache hit state */ data_src_hi:2, /* 6-7: data source high */ - reserved1:56; /* 8-63: reserved */ + strm_st:1, /* 8: streaming store */ + rmt_socket:1, /* 9: remote socket */ + reserved1:54; /* 10-63: reserved */ }; };
arch/x86/include/asm/msr-index.h +2 -0
@@ -698,6 +698,8 @@#define MSR_AMD64_IBSBRTARGET 0xc001103b#define MSR_AMD64_ICIBSEXTDCTL 0xc001103c#define MSR_AMD64_IBSOPDATA4 0xc001103d +#define MSR_AMD64_IBSOPCTL2 0xc001103e +#define MSR_AMD64_IBSFETCHCTL2 0xc001103f#define MSR_AMD64_IBS_REG_COUNT_MAX 8/* includes MSR_AMD64_IBSBRTARGET */ #define MSR_AMD64_SVM_AVIC_DOORBELL 0xc001011b#define MSR_AMD64_VM_PAGE_FLUSH 0xc001011e
arch/x86/include/asm/perf_event.h +36 -19
73 lines not on this page · raw message
kernel/events/core.c +21 -22
117 lines not on this page · raw message
tools/arch/x86/include/asm/amd/ibs.h +1 -1
@@ -77,7 +77,7 @@ union ibs_op_data {__u64 val;struct {__u64 comp_to_ret_ctr:16 ,/* 0-15: op completion to retire count */ - tag_to_ret_ctr:16 ,/* 15-31: op tag to retire count */ + tag_to_ret_ctr:16 ,/* 16-31: op tag to retire count */ reserved1:2 ,/* 32-33: reserved */ op_return:1 ,/* 34: return op */ op_brn_taken:1, /* 35: taken branch op */
[email protected]
AI reviewSashiko AI review found 2 potential issue(s): - [Critical] Pre-existing Stack Buffer Overflow in AMD IBS NMI handler on CPUs supporting `IBS_CAPS_OPDATA4`. - [High] Reference count leak of…
Sashiko AI review found 2 potential issue(s):
- [Critical] Pre-existing Stack Buffer Overflow in AMD IBS NMI handler on CPUs supporting IBS_CAPS_OPDATA4.
- [High] Reference count leak of perf_ctx_data in attach_global_ctx_data() when racing with a concurrent non-global context creation. --
commit 167b4d230f2ffe8284d5afdbd849ef2f4f05ef9a
Author: Ingo Molnar <[email protected]>
Performance events changes for v7.1
This commit pulls in various performance event changes for v7.1. It includes an optimization to allocate task_ctx_data quickly on large systems, updates and fixes for the AMD PMU driver IBS support, Intel PEBS constraint validation, and MSR driver changes.
Quoted 6 lines
kernel/events/core.c +0
-0@@ -5487,6 +5487,12 @@ attach_global_ctx_data(struct kmem_cache *ctx_cache) cd =NULL ; }
kernel/events/core.c attach_global_ctx_data(struct kmem_cache *ctx_cache) · line 5498
Quoted 10 lines
kernel/events/core.c +6
-0if (!cd) { +/* +* Try to allocate context quickly before +* traversing the whole thread list again. +*/ +if (!attach_task_ctx_data (p, ctx_cache, true,GFP_NOWAIT )) +continue ;get_task_struct (p); goto alloc; }
Could the new GFP_NOWAIT fast-path in attach_global_ctx_data() leak the perf_ctx_data reference if it races with a concurrent non-global context creation?
If attach_task_ctx_data() races with a per-task event attaching a non-global context, it will find an existing context where old is not NULL. It increments old->refcount and returns 0, but intentionally ignores the global argument and does not set old->global to 1.
Because it returns success, attach_global_ctx_data() executes continue and skips to the next thread. The context for the thread is left with an extra reference but global remains 0.
Later, when the global context is detached, __detach_global_ctx_data() iterates over all threads and only calls detach_task_ctx_data(p) if cd and cd->global are true. Since cd->global is 0, the context is skipped, permanently leaking the perf_ctx_data allocation.
kernel/events/core.c attach_global_ctx_data(struct kmem_cache *ctx_cache) · line 5509
Quoted 9 lines
kernel/events/core.c +1
-1@@ -5497,7 +5503,7 @@ attach_global_ctx_data(struct kmem_cache *ctx_cache)return 0 ; alloc: - ret =attach_task_ctx_data (p, ctx_cache, true); + ret =attach_task_ctx_data (p, ctx_cache, true,GFP_KERNEL );put_task_struct (p);if (ret) {__detach_global_ctx_data ();
Can this result in a double-increment leak? If the same race occurs, attach_task_ctx_data() bumps the refcount without setting global to 1 and returns success. Then goto again restarts the loop.
When the loop reaches the thread again, it evaluates:
cd = rcu_dereference(p->perf_ctx_data);
if (cd && !cd->global) {
cd->global = 1;
refcount_inc_not_zero(&cd->refcount);
}This bumps the refcount a second time. Since __detach_global_ctx_data() only decrements once, the extra reference is leaked.
arch/x86/include/asm/msr-index.h line 703
Quoted 10 lines
arch/x86/include/asm/msr-index.h +2
-0@@ -698,6 +698,8 @@#define MSR_AMD64_IBSBRTARGET 0xc001103b#define MSR_AMD64_ICIBSEXTDCTL 0xc001103c#define MSR_AMD64_IBSOPDATA4 0xc001103d +#define MSR_AMD64_IBSOPCTL2 0xc001103e +#define MSR_AMD64_IBSFETCHCTL2 0xc001103f#define MSR_AMD64_IBS_REG_COUNT_MAX 8/* includes MSR_AMD64_IBSBRTARGET */
This isn't a regression from the current patch, but looking at the adjacent MSR handling code, is there a potential stack buffer overflow in the IBS NMI handler on CPUs supporting IBS_CAPS_OPDATA4?
In arch/x86/events/amd/ibs.c, struct perf_ibs_data is allocated on the stack in perf_ibs_handle_irq(). Its regs array is sized using MSR_AMD64_IBS_REG_COUNT_MAX, which is 8.
When handling a perf_ibs_op event, the initial read loop fetches up to 7 MSRs, advancing the pointer buf to &ibs_data.regs[7].
Subsequently, the handler reads additional MSRs depending on CPU caps:
if (event->attr.sample_type & PERF_SAMPLE_RAW) {
if (perf_ibs == &perf_ibs_op) {
if (ibs_caps & IBS_CAPS_BRNTRGT) {
rdmsrq(MSR_AMD64_IBSBRTARGET, *buf++);
br_target_idx = size;
size++;
}
if (ibs_caps & IBS_CAPS_OPDATA4) {
rdmsrq(MSR_AMD64_IBSOPDATA4, *buf++);
size++;
}
}If the CPU supports IBS_CAPS_BRNTRGT, MSR_AMD64_IBSBRTARGET is read into regs[7], advancing buf to ®s[8].
If the CPU also supports IBS_CAPS_OPDATA4, it reads MSR_AMD64_IBSOPDATA4 into the next pointer position, which translates to regs[8]. This writes one element past the end of the 8-element array, overwriting adjacent local variables on the stack.
Furthermore, ibs_data.size is incremented to 9, so perf_sample_save_raw_data() will subsequently read 72 bytes of regs, exposing the corrupted stack data to user-space in the raw perf record. Since unprivileged users can configure RAW IBS events, this might lead to unintended behavior.
Should MSR_AMD64_IBS_REG_COUNT_MAX be increased to account for IBS_CAPS_OPDATA4?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Namhyung Kim
maintainerHello,
It seems sashio removes receipients in a reply. Added PeterZ.
Quoted 36 lines · On Mon, Apr 13, 2026 at 09:41:09AM +0000, [email protected] wrote:
Sashiko AI review found 2 potential issue(s):
- [Critical] Pre-existing Stack Buffer Overflow in AMD IBS NMI handler on CPUs supportingIBS_CAPS_OPDATA4.
- [High] Reference count leak ofperf_ctx_datainattach_global_ctx_data()when racing with a concurrent non-global context creation. --commit
167b4d230f2ffe8284d5afdbd849ef2f4f05ef9a
Author: Ingo Molnar <[email protected]>Performance events changes for v7.1
This commit pulls in various performance event changes for v7.1. It includes an optimization to allocate
task_ctx_dataquickly on large systems, updates and fixes for the AMD PMU driver IBS support, Intel PEBS constraint validation, and MSR driver changes.Quoted 6 lines
kernel/events/core.c +0
-0@@ -5487,6 +5487,12 @@ attach_global_ctx_data(struct kmem_cache *ctx_cache) cd =NULL ; }kernel/events/core.c attach_global_ctx_data(struct kmem_cache *ctx_cache) · line 5498
Quoted 10 lines
kernel/events/core.c +6
-0if (!cd) { +/* +* Try to allocate context quickly before +* traversing the whole thread list again. +*/ +if (!attach_task_ctx_data (p, ctx_cache, true,GFP_NOWAIT )) +continue ;get_task_struct (p); goto alloc; }Could the new
GFP_NOWAITfast-path inattach_global_ctx_data()leak theperf_ctx_datareference if it races with a concurrent non-global context creation?
Quoted 8 lines
If
attach_task_ctx_data()races with a per-task event attaching a non-global context, it will find an existing context where old is not NULL. It incrementsold->refcountand returns 0, but intentionally ignores the global argument and does not setold->globalto 1.Because it returns success,
attach_global_ctx_data()executes continue and skips to the next thread. The context for the thread is left with an extra reference but global remains 0.
Right, it looks like an existing problem. It should set the old->global like below:
kernel/events/core.c +2 -0
@@ -5447,6 +5447,8 @@ attach_task_ctx_data(struct task_struct *task, struct kmem_cache *ctx_cache, }if (refcount_inc_not_zero (&old->refcount)) { +if (global) + old->global =1 ;free_perf_ctx_data (cd);/* unused */ return 0 ; }
Quoted 22 lines
Later, when the global context is detached,
__detach_global_ctx_data()iterates over all threads and only callsdetach_task_ctx_data(p)if cd andcd->globalare true. Sincecd->globalis 0, the context is skipped, permanently leaking theperf_ctx_dataallocation.kernel/events/core.c attach_global_ctx_data(struct kmem_cache *ctx_cache) · line 5509
Quoted 9 lines
kernel/events/core.c +1
-1@@ -5497,7 +5503,7 @@ attach_global_ctx_data(struct kmem_cache *ctx_cache)return 0 ; alloc: - ret =attach_task_ctx_data (p, ctx_cache, true); + ret =attach_task_ctx_data (p, ctx_cache, true,GFP_KERNEL );put_task_struct (p);if (ret) {__detach_global_ctx_data ();Can this result in a double-increment leak? If the same race occurs,
attach_task_ctx_data()bumps the refcount without setting global to 1 and returns success. Then goto again restarts the loop.When the loop reaches the thread again, it evaluates:
Quoted 8 lines
cd = rcu_dereference(p->perf_ctx_data); if (cd && !cd->global) { cd->global = 1; refcount_inc_not_zero(&cd->refcount); }This bumps the refcount a second time. Since
__detach_global_ctx_data()only decrements once, the extra reference is leaked.
Looks correct and should be fixed by the above change as well. I'll send a formal patch if you're ok.
Thanks,
Namhyung
Quoted 45 lines
arch/x86/include/asm/msr-index.h line 703
Quoted 10 lines
arch/x86/include/asm/msr-index.h +2
-0@@ -698,6 +698,8 @@#define MSR_AMD64_IBSBRTARGET 0xc001103b#define MSR_AMD64_ICIBSEXTDCTL 0xc001103c#define MSR_AMD64_IBSOPDATA4 0xc001103d +#define MSR_AMD64_IBSOPCTL2 0xc001103e +#define MSR_AMD64_IBSFETCHCTL2 0xc001103f#define MSR_AMD64_IBS_REG_COUNT_MAX 8/* includes MSR_AMD64_IBSBRTARGET */ This isn't a regression from the current patch, but looking at the adjacent MSR handling code, is there a potential stack buffer overflow in the IBS NMI handler on CPUs supporting
IBS_CAPS_OPDATA4?In
arch/x86/events/amd/ibs.c, structperf_ibs_datais allocated on the stack inperf_ibs_handle_irq(). Its regs array is sized usingMSR_AMD64_IBS_REG_COUNT_MAX, which is 8.When handling a
perf_ibs_opevent, the initial read loop fetches up to 7 MSRs, advancing the pointer buf to &ibs_data.regs[7].Subsequently, the handler reads additional MSRs depending on CPU caps:
if (event->attr.sample_type & PERF_SAMPLE_RAW) { if (perf_ibs == &perf_ibs_op) { if (ibs_caps & IBS_CAPS_BRNTRGT) { rdmsrq(MSR_AMD64_IBSBRTARGET, *buf++); br_target_idx = size; size++; } if (ibs_caps & IBS_CAPS_OPDATA4) { rdmsrq(MSR_AMD64_IBSOPDATA4, *buf++); size++; } }If the CPU supports
IBS_CAPS_BRNTRGT,MSR_AMD64_IBSBRTARGETis read into regs[7], advancing buf to ®s[8].If the CPU also supports
IBS_CAPS_OPDATA4, it readsMSR_AMD64_IBSOPDATA4into the next pointer position, which translates to regs[8]. This writes one element past the end of the 8-element array, overwriting adjacent local variables on the stack.
Quoted 8 lines
Furthermore, ibs_data.size is incremented to 9, so
perf_sample_save_raw_data()will subsequently read 72 bytes of regs, exposing the corrupted stack data to user-space in the raw perf record. Since unprivileged users can configure RAW IBS events, this might lead to unintended behavior.Should
MSR_AMD64_IBS_REG_COUNT_MAXbe increased to account forIBS_CAPS_OPDATA4?
Thanks for the bug report.
While this seems like a genuine overflow issue, IbsOpData4 has been deprecated from long back. I was unable to find any platform that supports it. So it's not a real a concern.
Thanks,
Ravi
The pull request you sent on Mon, 13 Apr 2026 10:19:29 +0200:
The pull request you sent on Mon, 13 Apr 2026 10:19:29 +0200:
Quoted 1 line
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.gitperf-core-2026-04-13
has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/33c66eb5e9844429911bf5478c96c60f9f8af9d0
Thank you!
Signature · 2 lines
Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/prtracker.html