perf_event: push down type safety

This makes it more difficult to mishandle callers of `perf_event_open`.

Change `wakeup_events = 0` to 1; per `man 2 perf_event_open`:

  Prior to Linux 3.0, setting wakeup_events to 0 resulted in
  no overflow notifications; more recent kernels treat 0 the
  same as 1.
reviewable/pr1386/r4
Tamir Duberstein 1 week ago
parent 7e405c216e
commit 18c7f7ccd6
No known key found for this signature in database

@ -111,7 +111,7 @@ pub use crate::programs::{
lirc_mode2::LircMode2,
lsm::Lsm,
lsm_cgroup::LsmCgroup,
perf_event::{PerfEvent, PerfEventScope, SamplePolicy},
perf_event::PerfEvent,
probe::ProbeKind,
raw_trace_point::RawTracePoint,
sk_lookup::SkLookup,

@ -3,14 +3,8 @@
use std::os::fd::AsFd as _;
use aya_obj::generated::{
bpf_link_type,
bpf_prog_type::BPF_PROG_TYPE_PERF_EVENT,
perf_hw_cache_id, perf_hw_cache_op_id, perf_hw_cache_op_result_id, perf_hw_id, perf_sw_ids,
perf_type_id,
perf_type_id::{
PERF_TYPE_BREAKPOINT, PERF_TYPE_HARDWARE, PERF_TYPE_HW_CACHE, PERF_TYPE_RAW,
PERF_TYPE_SOFTWARE, PERF_TYPE_TRACEPOINT,
},
bpf_link_type, bpf_prog_type::BPF_PROG_TYPE_PERF_EVENT, perf_hw_cache_id, perf_hw_cache_op_id,
perf_hw_cache_op_result_id, perf_hw_id, perf_sw_ids, perf_type_id,
};
use crate::{
@ -84,7 +78,7 @@ pub enum PerfEventConfig {
macro_rules! impl_to_u32 {
($($t:ty, $fn:ident),*) => {
$(const fn $fn(id: $t) -> u32 {
$(pub(crate) const fn $fn(id: $t) -> u32 {
const _: [(); 4] = [(); std::mem::size_of::<$t>()];
id as u32
})*
@ -144,7 +138,7 @@ pub enum HardwareEvent {
}
impl HardwareEvent {
const fn into_primitive(self) -> u32 {
pub(crate) const fn into_primitive(self) -> u32 {
const _: [(); 4] = [(); std::mem::size_of::<HardwareEvent>()];
self as u32
}
@ -194,7 +188,7 @@ pub enum SoftwareEvent {
}
impl SoftwareEvent {
const fn into_primitive(self) -> u32 {
pub(crate) const fn into_primitive(self) -> u32 {
const _: [(); 4] = [(); std::mem::size_of::<SoftwareEvent>()];
self as u32
}
@ -229,7 +223,7 @@ pub enum HwCacheEvent {
}
impl HwCacheEvent {
const fn into_primitive(self) -> u32 {
pub(crate) const fn into_primitive(self) -> u32 {
const _: [(); 4] = [(); std::mem::size_of::<HwCacheEvent>()];
self as u32
}
@ -252,7 +246,7 @@ pub enum HwCacheOp {
}
impl HwCacheOp {
const fn into_primitive(self) -> u32 {
pub(crate) const fn into_primitive(self) -> u32 {
const _: [(); 4] = [(); std::mem::size_of::<HwCacheOp>()];
self as u32
}
@ -276,14 +270,14 @@ pub enum HwCacheResult {
}
impl HwCacheResult {
const fn into_primitive(self) -> u32 {
pub(crate) const fn into_primitive(self) -> u32 {
const _: [(); 4] = [(); std::mem::size_of::<HwCacheResult>()];
self as u32
}
}
/// Sample Policy
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Copy)]
pub enum SamplePolicy {
/// Period
Period(u64),
@ -291,8 +285,18 @@ pub enum SamplePolicy {
Frequency(u64),
}
/// Wakeup Policy
#[derive(Debug, Clone, Copy)]
pub(crate) enum WakeupPolicy {
/// Every N events
Events(u32),
/// Every N bytes
#[expect(dead_code)]
Watermark(u32),
}
/// The scope of a PerfEvent
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Copy)]
pub enum PerfEventScope {
/// calling process
CallingProcess {
@ -381,7 +385,7 @@ impl PerfEvent {
/// The returned value can be used to detach, see [PerfEvent::detach].
pub fn attach(
&mut self,
perf_type: PerfEventConfig,
config: PerfEventConfig,
scope: PerfEventScope,
sample_policy: SamplePolicy,
inherit: bool,
@ -389,49 +393,11 @@ impl PerfEvent {
let prog_fd = self.fd()?;
let prog_fd = prog_fd.as_fd();
let (perf_type, config) = match perf_type {
PerfEventConfig::Pmu { pmu_type, config } => (pmu_type, config),
PerfEventConfig::Hardware(hw_event) => (
perf_type_id_to_u32(PERF_TYPE_HARDWARE),
u64::from(hw_event.into_primitive()),
),
PerfEventConfig::Software(sw_event) => (
perf_type_id_to_u32(PERF_TYPE_SOFTWARE),
u64::from(sw_event.into_primitive()),
),
PerfEventConfig::TracePoint { event_id } => {
(perf_type_id_to_u32(PERF_TYPE_TRACEPOINT), event_id)
}
PerfEventConfig::HwCache {
event,
operation,
result,
} => (
perf_type_id_to_u32(PERF_TYPE_HW_CACHE),
u64::from(event.into_primitive())
| (u64::from(operation.into_primitive()) << 8)
| (u64::from(result.into_primitive()) << 16),
),
PerfEventConfig::Raw { event_id } => (perf_type_id_to_u32(PERF_TYPE_RAW), event_id),
PerfEventConfig::Breakpoint => (perf_type_id_to_u32(PERF_TYPE_BREAKPOINT), 0),
};
let (sample_period, sample_frequency) = match sample_policy {
SamplePolicy::Period(period) => (period, None),
SamplePolicy::Frequency(frequency) => (0, Some(frequency)),
};
let (pid, cpu) = match scope {
PerfEventScope::CallingProcess { cpu } => (0, cpu.map_or(-1, |cpu| cpu as i32)),
PerfEventScope::OneProcess { pid, cpu } => (pid, cpu.map_or(-1, |cpu| cpu as i32)),
PerfEventScope::AllProcessesOneCpu { cpu } => (-1, cpu as i32),
};
let fd = perf_event_open(
perf_type,
config,
pid,
cpu,
sample_period,
sample_frequency,
false,
scope,
sample_policy,
WakeupPolicy::Events(1),
inherit,
0,
)

@ -7,53 +7,97 @@ use std::{
use aya_obj::generated::{
PERF_FLAG_FD_CLOEXEC, perf_event_attr,
perf_event_sample_format::PERF_SAMPLE_RAW,
perf_sw_ids::PERF_COUNT_SW_BPF_OUTPUT,
perf_type_id::{PERF_TYPE_SOFTWARE, PERF_TYPE_TRACEPOINT},
perf_type_id::{
PERF_TYPE_BREAKPOINT, PERF_TYPE_HARDWARE, PERF_TYPE_HW_CACHE, PERF_TYPE_RAW,
PERF_TYPE_SOFTWARE, PERF_TYPE_TRACEPOINT,
},
};
use libc::pid_t;
use super::{PerfEventIoctlRequest, Syscall, syscall};
use crate::programs::perf_event::{
PerfEventConfig, PerfEventScope, SamplePolicy, SoftwareEvent, WakeupPolicy, perf_type_id_to_u32,
};
#[expect(clippy::too_many_arguments)]
pub(crate) fn perf_event_open(
perf_type: u32,
config: u64,
pid: pid_t,
cpu: c_int,
sample_period: u64,
sample_frequency: Option<u64>,
wakeup: bool,
config: PerfEventConfig,
scope: PerfEventScope,
sample_policy: SamplePolicy,
wakeup_policy: WakeupPolicy,
inherit: bool,
flags: u32,
) -> io::Result<crate::MockableFd> {
let mut attr = unsafe { mem::zeroed::<perf_event_attr>() };
let (perf_type, config) = match config {
PerfEventConfig::Pmu { pmu_type, config } => (pmu_type, config),
PerfEventConfig::Hardware(hw_event) => (
perf_type_id_to_u32(PERF_TYPE_HARDWARE),
u64::from(hw_event.into_primitive()),
),
PerfEventConfig::Software(sw_event) => (
perf_type_id_to_u32(PERF_TYPE_SOFTWARE),
u64::from(sw_event.into_primitive()),
),
PerfEventConfig::TracePoint { event_id } => {
(perf_type_id_to_u32(PERF_TYPE_TRACEPOINT), event_id)
}
PerfEventConfig::HwCache {
event,
operation,
result,
} => (
perf_type_id_to_u32(PERF_TYPE_HW_CACHE),
u64::from(event.into_primitive())
| (u64::from(operation.into_primitive()) << 8)
| (u64::from(result.into_primitive()) << 16),
),
PerfEventConfig::Raw { event_id } => (perf_type_id_to_u32(PERF_TYPE_RAW), event_id),
PerfEventConfig::Breakpoint => (perf_type_id_to_u32(PERF_TYPE_BREAKPOINT), 0),
};
attr.config = config;
attr.size = mem::size_of::<perf_event_attr>() as u32;
attr.type_ = perf_type;
attr.sample_type = PERF_SAMPLE_RAW as u64;
attr.set_inherit(if inherit { 1 } else { 0 });
attr.__bindgen_anon_2.wakeup_events = u32::from(wakeup);
if let Some(frequency) = sample_frequency {
match sample_policy {
SamplePolicy::Period(period) => {
attr.__bindgen_anon_1.sample_period = period;
}
SamplePolicy::Frequency(frequency) => {
attr.set_freq(1);
attr.__bindgen_anon_1.sample_freq = frequency;
} else {
attr.__bindgen_anon_1.sample_period = sample_period;
}
}
match wakeup_policy {
WakeupPolicy::Events(events) => {
attr.__bindgen_anon_2.wakeup_events = events;
}
WakeupPolicy::Watermark(watermark) => {
attr.set_watermark(1);
attr.__bindgen_anon_2.wakeup_watermark = watermark;
}
}
let (pid, cpu) = match scope {
PerfEventScope::CallingProcess { cpu } => (0, cpu.map_or(-1, |cpu| cpu as i32)),
PerfEventScope::OneProcess { pid, cpu } => (pid, cpu.map_or(-1, |cpu| cpu as i32)),
PerfEventScope::AllProcessesOneCpu { cpu } => (-1, cpu as i32),
};
perf_event_sys(attr, pid, cpu, flags)
}
pub(crate) fn perf_event_open_bpf(cpu: c_int) -> io::Result<crate::MockableFd> {
let cpu = cpu as u32;
perf_event_open(
PERF_TYPE_SOFTWARE as u32,
PERF_COUNT_SW_BPF_OUTPUT as u64,
-1,
cpu,
1,
None,
true,
PerfEventConfig::Software(SoftwareEvent::BpfOutput),
PerfEventScope::AllProcessesOneCpu { cpu },
SamplePolicy::Period(1),
WakeupPolicy::Events(1),
false,
PERF_FLAG_FD_CLOEXEC,
)

@ -5517,6 +5517,7 @@ impl core::clone::Clone for aya::programs::perf_event::PerfEventScope
pub fn aya::programs::perf_event::PerfEventScope::clone(&self) -> aya::programs::perf_event::PerfEventScope
impl core::fmt::Debug for aya::programs::perf_event::PerfEventScope
pub fn aya::programs::perf_event::PerfEventScope::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::marker::Copy for aya::programs::perf_event::PerfEventScope
impl core::marker::Freeze for aya::programs::perf_event::PerfEventScope
impl core::marker::Send for aya::programs::perf_event::PerfEventScope
impl core::marker::Sync for aya::programs::perf_event::PerfEventScope
@ -5552,6 +5553,7 @@ impl core::clone::Clone for aya::programs::perf_event::SamplePolicy
pub fn aya::programs::perf_event::SamplePolicy::clone(&self) -> aya::programs::perf_event::SamplePolicy
impl core::fmt::Debug for aya::programs::perf_event::SamplePolicy
pub fn aya::programs::perf_event::SamplePolicy::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::marker::Copy for aya::programs::perf_event::SamplePolicy
impl core::marker::Freeze for aya::programs::perf_event::SamplePolicy
impl core::marker::Send for aya::programs::perf_event::SamplePolicy
impl core::marker::Sync for aya::programs::perf_event::SamplePolicy
@ -5629,7 +5631,7 @@ pub fn aya::programs::perf_event::SoftwareEvent::from(t: T) -> T
pub struct aya::programs::perf_event::PerfEvent
impl aya::programs::perf_event::PerfEvent
pub const aya::programs::perf_event::PerfEvent::PROGRAM_TYPE: aya::programs::ProgramType
pub fn aya::programs::perf_event::PerfEvent::attach(&mut self, perf_type: aya::programs::perf_event::PerfEventConfig, scope: aya::programs::perf_event::PerfEventScope, sample_policy: aya::programs::perf_event::SamplePolicy, inherit: bool) -> core::result::Result<aya::programs::perf_event::PerfEventLinkId, aya::programs::ProgramError>
pub fn aya::programs::perf_event::PerfEvent::attach(&mut self, config: aya::programs::perf_event::PerfEventConfig, scope: aya::programs::perf_event::PerfEventScope, sample_policy: aya::programs::perf_event::SamplePolicy, inherit: bool) -> core::result::Result<aya::programs::perf_event::PerfEventLinkId, aya::programs::ProgramError>
pub fn aya::programs::perf_event::PerfEvent::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
impl aya::programs::perf_event::PerfEvent
pub fn aya::programs::perf_event::PerfEvent::detach(&mut self, link_id: aya::programs::perf_event::PerfEventLinkId) -> core::result::Result<(), aya::programs::ProgramError>
@ -7940,46 +7942,6 @@ impl<T> core::clone::CloneToUninit for aya::programs::LsmAttachType where T: cor
pub unsafe fn aya::programs::LsmAttachType::clone_to_uninit(&self, dest: *mut u8)
impl<T> core::convert::From<T> for aya::programs::LsmAttachType
pub fn aya::programs::LsmAttachType::from(t: T) -> T
pub enum aya::programs::PerfEventScope
pub aya::programs::PerfEventScope::AllProcessesOneCpu
pub aya::programs::PerfEventScope::AllProcessesOneCpu::cpu: u32
pub aya::programs::PerfEventScope::CallingProcess
pub aya::programs::PerfEventScope::CallingProcess::cpu: core::option::Option<u32>
pub aya::programs::PerfEventScope::OneProcess
pub aya::programs::PerfEventScope::OneProcess::cpu: core::option::Option<u32>
pub aya::programs::PerfEventScope::OneProcess::pid: i32
impl core::clone::Clone for aya::programs::perf_event::PerfEventScope
pub fn aya::programs::perf_event::PerfEventScope::clone(&self) -> aya::programs::perf_event::PerfEventScope
impl core::fmt::Debug for aya::programs::perf_event::PerfEventScope
pub fn aya::programs::perf_event::PerfEventScope::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::marker::Freeze for aya::programs::perf_event::PerfEventScope
impl core::marker::Send for aya::programs::perf_event::PerfEventScope
impl core::marker::Sync for aya::programs::perf_event::PerfEventScope
impl core::marker::Unpin for aya::programs::perf_event::PerfEventScope
impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::perf_event::PerfEventScope
impl core::panic::unwind_safe::UnwindSafe for aya::programs::perf_event::PerfEventScope
impl<T, U> core::convert::Into<U> for aya::programs::perf_event::PerfEventScope where U: core::convert::From<T>
pub fn aya::programs::perf_event::PerfEventScope::into(self) -> U
impl<T, U> core::convert::TryFrom<U> for aya::programs::perf_event::PerfEventScope where U: core::convert::Into<T>
pub type aya::programs::perf_event::PerfEventScope::Error = core::convert::Infallible
pub fn aya::programs::perf_event::PerfEventScope::try_from(value: U) -> core::result::Result<T, <T as core::convert::TryFrom<U>>::Error>
impl<T, U> core::convert::TryInto<U> for aya::programs::perf_event::PerfEventScope where U: core::convert::TryFrom<T>
pub type aya::programs::perf_event::PerfEventScope::Error = <U as core::convert::TryFrom<T>>::Error
pub fn aya::programs::perf_event::PerfEventScope::try_into(self) -> core::result::Result<U, <U as core::convert::TryFrom<T>>::Error>
impl<T> alloc::borrow::ToOwned for aya::programs::perf_event::PerfEventScope where T: core::clone::Clone
pub type aya::programs::perf_event::PerfEventScope::Owned = T
pub fn aya::programs::perf_event::PerfEventScope::clone_into(&self, target: &mut T)
pub fn aya::programs::perf_event::PerfEventScope::to_owned(&self) -> T
impl<T> core::any::Any for aya::programs::perf_event::PerfEventScope where T: 'static + ?core::marker::Sized
pub fn aya::programs::perf_event::PerfEventScope::type_id(&self) -> core::any::TypeId
impl<T> core::borrow::Borrow<T> for aya::programs::perf_event::PerfEventScope where T: ?core::marker::Sized
pub fn aya::programs::perf_event::PerfEventScope::borrow(&self) -> &T
impl<T> core::borrow::BorrowMut<T> for aya::programs::perf_event::PerfEventScope where T: ?core::marker::Sized
pub fn aya::programs::perf_event::PerfEventScope::borrow_mut(&mut self) -> &mut T
impl<T> core::clone::CloneToUninit for aya::programs::perf_event::PerfEventScope where T: core::clone::Clone
pub unsafe fn aya::programs::perf_event::PerfEventScope::clone_to_uninit(&self, dest: *mut u8)
impl<T> core::convert::From<T> for aya::programs::perf_event::PerfEventScope
pub fn aya::programs::perf_event::PerfEventScope::from(t: T) -> T
pub enum aya::programs::ProbeKind
pub aya::programs::ProbeKind::KProbe
pub aya::programs::ProbeKind::KRetProbe
@ -8390,41 +8352,6 @@ impl<T> core::clone::CloneToUninit for aya::programs::ProgramType where T: core:
pub unsafe fn aya::programs::ProgramType::clone_to_uninit(&self, dest: *mut u8)
impl<T> core::convert::From<T> for aya::programs::ProgramType
pub fn aya::programs::ProgramType::from(t: T) -> T
pub enum aya::programs::SamplePolicy
pub aya::programs::SamplePolicy::Frequency(u64)
pub aya::programs::SamplePolicy::Period(u64)
impl core::clone::Clone for aya::programs::perf_event::SamplePolicy
pub fn aya::programs::perf_event::SamplePolicy::clone(&self) -> aya::programs::perf_event::SamplePolicy
impl core::fmt::Debug for aya::programs::perf_event::SamplePolicy
pub fn aya::programs::perf_event::SamplePolicy::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::marker::Freeze for aya::programs::perf_event::SamplePolicy
impl core::marker::Send for aya::programs::perf_event::SamplePolicy
impl core::marker::Sync for aya::programs::perf_event::SamplePolicy
impl core::marker::Unpin for aya::programs::perf_event::SamplePolicy
impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::perf_event::SamplePolicy
impl core::panic::unwind_safe::UnwindSafe for aya::programs::perf_event::SamplePolicy
impl<T, U> core::convert::Into<U> for aya::programs::perf_event::SamplePolicy where U: core::convert::From<T>
pub fn aya::programs::perf_event::SamplePolicy::into(self) -> U
impl<T, U> core::convert::TryFrom<U> for aya::programs::perf_event::SamplePolicy where U: core::convert::Into<T>
pub type aya::programs::perf_event::SamplePolicy::Error = core::convert::Infallible
pub fn aya::programs::perf_event::SamplePolicy::try_from(value: U) -> core::result::Result<T, <T as core::convert::TryFrom<U>>::Error>
impl<T, U> core::convert::TryInto<U> for aya::programs::perf_event::SamplePolicy where U: core::convert::TryFrom<T>
pub type aya::programs::perf_event::SamplePolicy::Error = <U as core::convert::TryFrom<T>>::Error
pub fn aya::programs::perf_event::SamplePolicy::try_into(self) -> core::result::Result<U, <U as core::convert::TryFrom<T>>::Error>
impl<T> alloc::borrow::ToOwned for aya::programs::perf_event::SamplePolicy where T: core::clone::Clone
pub type aya::programs::perf_event::SamplePolicy::Owned = T
pub fn aya::programs::perf_event::SamplePolicy::clone_into(&self, target: &mut T)
pub fn aya::programs::perf_event::SamplePolicy::to_owned(&self) -> T
impl<T> core::any::Any for aya::programs::perf_event::SamplePolicy where T: 'static + ?core::marker::Sized
pub fn aya::programs::perf_event::SamplePolicy::type_id(&self) -> core::any::TypeId
impl<T> core::borrow::Borrow<T> for aya::programs::perf_event::SamplePolicy where T: ?core::marker::Sized
pub fn aya::programs::perf_event::SamplePolicy::borrow(&self) -> &T
impl<T> core::borrow::BorrowMut<T> for aya::programs::perf_event::SamplePolicy where T: ?core::marker::Sized
pub fn aya::programs::perf_event::SamplePolicy::borrow_mut(&mut self) -> &mut T
impl<T> core::clone::CloneToUninit for aya::programs::perf_event::SamplePolicy where T: core::clone::Clone
pub unsafe fn aya::programs::perf_event::SamplePolicy::clone_to_uninit(&self, dest: *mut u8)
impl<T> core::convert::From<T> for aya::programs::perf_event::SamplePolicy
pub fn aya::programs::perf_event::SamplePolicy::from(t: T) -> T
pub enum aya::programs::SkSkbKind
pub aya::programs::SkSkbKind::StreamParser
pub aya::programs::SkSkbKind::StreamVerdict
@ -9576,7 +9503,7 @@ pub fn aya::programs::lsm_cgroup::LsmCgroup::from(t: T) -> T
pub struct aya::programs::PerfEvent
impl aya::programs::perf_event::PerfEvent
pub const aya::programs::perf_event::PerfEvent::PROGRAM_TYPE: aya::programs::ProgramType
pub fn aya::programs::perf_event::PerfEvent::attach(&mut self, perf_type: aya::programs::perf_event::PerfEventConfig, scope: aya::programs::perf_event::PerfEventScope, sample_policy: aya::programs::perf_event::SamplePolicy, inherit: bool) -> core::result::Result<aya::programs::perf_event::PerfEventLinkId, aya::programs::ProgramError>
pub fn aya::programs::perf_event::PerfEvent::attach(&mut self, config: aya::programs::perf_event::PerfEventConfig, scope: aya::programs::perf_event::PerfEventScope, sample_policy: aya::programs::perf_event::SamplePolicy, inherit: bool) -> core::result::Result<aya::programs::perf_event::PerfEventLinkId, aya::programs::ProgramError>
pub fn aya::programs::perf_event::PerfEvent::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
impl aya::programs::perf_event::PerfEvent
pub fn aya::programs::perf_event::PerfEvent::detach(&mut self, link_id: aya::programs::perf_event::PerfEventLinkId) -> core::result::Result<(), aya::programs::ProgramError>

Loading…
Cancel
Save