aya: encode perf_event_open(2) contract

Per man 2 perf_event_open:

> RETURN VALUE
>   On success, perf_event_open() returns the new file descriptor.  On
>   error, -1 is returned and errno is set to indicate the error.

Bake this into our syscalls so we stop using `_` so much which can hide
information loss. Remove the type parameter to SysResult.
reviewable/pr1194/r1
Tamir Duberstein 2 weeks ago
parent bdd8ae2d0b
commit 055e36e8d9

@ -83,7 +83,7 @@ impl<T: BorrowMut<MapData>, V: Pod> BloomFilter<T, V> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::{ffi::c_long, io}; use std::io;
use assert_matches::assert_matches; use assert_matches::assert_matches;
use aya_obj::generated::{ use aya_obj::generated::{
@ -105,7 +105,7 @@ mod tests {
test_utils::new_obj_map::<u32>(BPF_MAP_TYPE_BLOOM_FILTER) test_utils::new_obj_map::<u32>(BPF_MAP_TYPE_BLOOM_FILTER)
} }
fn sys_error(value: i32) -> SysResult<c_long> { fn sys_error(value: i32) -> SysResult {
Err((-1, io::Error::from_raw_os_error(value))) Err((-1, io::Error::from_raw_os_error(value)))
} }

@ -103,7 +103,7 @@ impl<T: Borrow<MapData>, K: Pod, V: Pod> IterableMap<K, V> for HashMap<T, K, V>
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::{ffi::c_long, io}; use std::io;
use assert_matches::assert_matches; use assert_matches::assert_matches;
use aya_obj::generated::{ use aya_obj::generated::{
@ -125,7 +125,7 @@ mod tests {
test_utils::new_obj_map::<u32>(BPF_MAP_TYPE_HASH) test_utils::new_obj_map::<u32>(BPF_MAP_TYPE_HASH)
} }
fn sys_error(value: i32) -> SysResult<c_long> { fn sys_error(value: i32) -> SysResult {
Err((-1, io::Error::from_raw_os_error(value))) Err((-1, io::Error::from_raw_os_error(value)))
} }
@ -306,13 +306,13 @@ mod tests {
} }
} }
fn set_next_key<T: Copy>(attr: &bpf_attr, next: T) -> SysResult<c_long> { fn set_next_key<T: Copy>(attr: &bpf_attr, next: T) -> SysResult {
let key = unsafe { attr.__bindgen_anon_2.__bindgen_anon_1.next_key } as *const T as *mut T; let key = unsafe { attr.__bindgen_anon_2.__bindgen_anon_1.next_key } as *const T as *mut T;
unsafe { *key = next }; unsafe { *key = next };
Ok(0) Ok(0)
} }
fn set_ret<T: Copy>(attr: &bpf_attr, ret: T) -> SysResult<c_long> { fn set_ret<T: Copy>(attr: &bpf_attr, ret: T) -> SysResult {
let value = unsafe { attr.__bindgen_anon_2.__bindgen_anon_1.value } as *const T as *mut T; let value = unsafe { attr.__bindgen_anon_2.__bindgen_anon_1.value } as *const T as *mut T;
unsafe { *value = ret }; unsafe { *value = ret };
Ok(0) Ok(0)
@ -333,7 +333,7 @@ mod tests {
assert_matches!(keys, Ok(ks) if ks.is_empty()) assert_matches!(keys, Ok(ks) if ks.is_empty())
} }
fn get_next_key(attr: &bpf_attr) -> SysResult<c_long> { fn get_next_key(attr: &bpf_attr) -> SysResult {
match bpf_key(attr) { match bpf_key(attr) {
None => set_next_key(attr, 10), None => set_next_key(attr, 10),
Some(10) => set_next_key(attr, 20), Some(10) => set_next_key(attr, 20),
@ -343,7 +343,7 @@ mod tests {
} }
} }
fn lookup_elem(attr: &bpf_attr) -> SysResult<c_long> { fn lookup_elem(attr: &bpf_attr) -> SysResult {
match bpf_key(attr) { match bpf_key(attr) {
Some(10) => set_ret(attr, 100), Some(10) => set_ret(attr, 100),
Some(20) => set_ret(attr, 200), Some(20) => set_ret(attr, 200),

@ -149,7 +149,7 @@ impl<T: Borrow<MapData>, K: Pod, V: Pod> IterableMap<K, PerCpuValues<V>>
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::{ffi::c_long, io}; use std::io;
use assert_matches::assert_matches; use assert_matches::assert_matches;
use aya_obj::generated::bpf_map_type::{ use aya_obj::generated::bpf_map_type::{
@ -163,7 +163,7 @@ mod tests {
sys::{override_syscall, SysResult}, sys::{override_syscall, SysResult},
}; };
fn sys_error(value: i32) -> SysResult<c_long> { fn sys_error(value: i32) -> SysResult {
Err((-1, io::Error::from_raw_os_error(value))) Err((-1, io::Error::from_raw_os_error(value)))
} }

@ -190,7 +190,7 @@ impl<T: Borrow<MapData>, K: Pod, V: Pod> IterableMap<Key<K>, V> for LpmTrie<T, K
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::{ffi::c_long, io, net::Ipv4Addr}; use std::{io, net::Ipv4Addr};
use assert_matches::assert_matches; use assert_matches::assert_matches;
use aya_obj::generated::{ use aya_obj::generated::{
@ -212,7 +212,7 @@ mod tests {
test_utils::new_obj_map::<Key<u32>>(BPF_MAP_TYPE_LPM_TRIE) test_utils::new_obj_map::<Key<u32>>(BPF_MAP_TYPE_LPM_TRIE)
} }
fn sys_error(value: i32) -> SysResult<c_long> { fn sys_error(value: i32) -> SysResult {
Err((-1, io::Error::from_raw_os_error(value))) Err((-1, io::Error::from_raw_os_error(value)))
} }

@ -102,7 +102,7 @@ impl PerfBuffer {
} }
let fd = perf_event_open_bpf(cpu_id as i32) let fd = perf_event_open_bpf(cpu_id as i32)
.map_err(|(_, io_error)| PerfBufferError::OpenError { io_error })?; .map_err(|io_error| PerfBufferError::OpenError { io_error })?;
let size = page_size * page_count; let size = page_size * page_count;
let mmap = MMap::new( let mmap = MMap::new(
fd.as_fd(), fd.as_fd(),
@ -260,7 +260,7 @@ impl AsFd for PerfBuffer {
impl Drop for PerfBuffer { impl Drop for PerfBuffer {
fn drop(&mut self) { fn drop(&mut self) {
let _: SysResult<_> = perf_event_ioctl(self.fd.as_fd(), PERF_EVENT_IOC_DISABLE, 0); let _: SysResult = perf_event_ioctl(self.fd.as_fd(), PERF_EVENT_IOC_DISABLE, 0);
} }
} }

@ -71,7 +71,7 @@ impl Link for PerfLink {
fn detach(self) -> Result<(), ProgramError> { fn detach(self) -> Result<(), ProgramError> {
let Self { perf_fd, event } = self; let Self { perf_fd, event } = self;
let _: SysResult<_> = perf_event_ioctl(perf_fd.as_fd(), PERF_EVENT_IOC_DISABLE, 0); let _: SysResult = perf_event_ioctl(perf_fd.as_fd(), PERF_EVENT_IOC_DISABLE, 0);
if let Some(event) = event { if let Some(event) = event {
let _: Result<_, _> = detach_debug_fs(event); let _: Result<_, _> = detach_debug_fs(event);
} }

@ -176,7 +176,7 @@ impl PerfEvent {
inherit, inherit,
0, 0,
) )
.map_err(|(_code, io_error)| SyscallError { .map_err(|io_error| SyscallError {
call: "perf_event_open", call: "perf_event_open",
io_error, io_error,
})?; })?;

@ -177,7 +177,7 @@ fn create_as_probe(
}; };
perf_event_open_probe(perf_ty, ret_bit, fn_name, offset, pid) perf_event_open_probe(perf_ty, ret_bit, fn_name, offset, pid)
.map_err(|(_code, io_error)| SyscallError { .map_err(|io_error| SyscallError {
call: "perf_event_open", call: "perf_event_open",
io_error, io_error,
}) })
@ -203,7 +203,7 @@ fn create_as_trace_point(
let category = format!("{}s", kind.pmu()); let category = format!("{}s", kind.pmu());
let tpid = read_sys_fs_trace_point_id(tracefs, &category, event_alias.as_ref())?; let tpid = read_sys_fs_trace_point_id(tracefs, &category, event_alias.as_ref())?;
let fd = perf_event_open_trace_point(tpid, pid).map_err(|(_code, io_error)| SyscallError { let fd = perf_event_open_trace_point(tpid, pid).map_err(|io_error| SyscallError {
call: "perf_event_open", call: "perf_event_open",
io_error, io_error,
})?; })?;

@ -76,11 +76,10 @@ impl TracePoint {
let prog_fd = prog_fd.as_fd(); let prog_fd = prog_fd.as_fd();
let tracefs = find_tracefs_path()?; let tracefs = find_tracefs_path()?;
let id = read_sys_fs_trace_point_id(tracefs, category, name.as_ref())?; let id = read_sys_fs_trace_point_id(tracefs, category, name.as_ref())?;
let fd = let fd = perf_event_open_trace_point(id, None).map_err(|io_error| SyscallError {
perf_event_open_trace_point(id, None).map_err(|(_code, io_error)| SyscallError { call: "perf_event_open_trace_point",
call: "perf_event_open_trace_point", io_error,
io_error, })?;
})?;
let link = perf_attach(prog_fd, fd, None /* cookie */)?; let link = perf_attach(prog_fd, fd, None /* cookie */)?;
self.data.links.insert(TracePointLink::new(link)) self.data.links.insert(TracePointLink::new(link))

@ -1,12 +1,8 @@
use std::{ use std::{cell::RefCell, ffi::c_void, io, ptr};
cell::RefCell,
ffi::{c_long, c_void},
io, ptr,
};
use super::{SysResult, Syscall}; use super::{SysResult, Syscall};
type SyscallFn = unsafe fn(Syscall<'_>) -> SysResult<c_long>; type SyscallFn = unsafe fn(Syscall<'_>) -> SysResult;
#[cfg(test)] #[cfg(test)]
thread_local! { thread_local! {
@ -15,11 +11,11 @@ thread_local! {
} }
#[cfg(test)] #[cfg(test)]
unsafe fn test_syscall(_call: Syscall<'_>) -> SysResult<c_long> { unsafe fn test_syscall(_call: Syscall<'_>) -> SysResult {
Err((-1, io::Error::from_raw_os_error(libc::EINVAL))) Err((-1, io::Error::from_raw_os_error(libc::EINVAL)))
} }
#[cfg(test)] #[cfg(test)]
pub(crate) fn override_syscall(call: unsafe fn(Syscall<'_>) -> SysResult<c_long>) { pub(crate) fn override_syscall(call: unsafe fn(Syscall<'_>) -> SysResult) {
TEST_SYSCALL.with(|test_impl| *test_impl.borrow_mut() = call); TEST_SYSCALL.with(|test_impl| *test_impl.borrow_mut() = call);
} }

@ -24,7 +24,7 @@ pub(crate) use netlink::*;
pub(crate) use perf_event::*; pub(crate) use perf_event::*;
use thiserror::Error; use thiserror::Error;
pub(crate) type SysResult<T> = Result<T, (c_long, io::Error)>; pub(crate) type SysResult = Result<c_long, (c_long, io::Error)>;
pub(crate) enum Syscall<'a> { pub(crate) enum Syscall<'a> {
Ebpf { Ebpf {
@ -88,7 +88,7 @@ impl std::fmt::Debug for Syscall<'_> {
} }
} }
fn syscall(call: Syscall<'_>) -> SysResult<c_long> { fn syscall(call: Syscall<'_>) -> SysResult {
#[cfg(test)] #[cfg(test)]
return TEST_SYSCALL.with(|test_impl| unsafe { test_impl.borrow()(call) }); return TEST_SYSCALL.with(|test_impl| unsafe { test_impl.borrow()(call) });

@ -1,5 +1,5 @@
use std::{ use std::{
ffi::{c_int, c_long, CString, OsStr}, ffi::{c_int, CString, OsStr},
io, mem, io, mem,
os::fd::{BorrowedFd, FromRawFd as _}, os::fd::{BorrowedFd, FromRawFd as _},
}; };
@ -26,7 +26,7 @@ pub(crate) fn perf_event_open(
wakeup: bool, wakeup: bool,
inherit: bool, inherit: bool,
flags: u32, flags: u32,
) -> SysResult<crate::MockableFd> { ) -> io::Result<crate::MockableFd> {
let mut attr = unsafe { mem::zeroed::<perf_event_attr>() }; let mut attr = unsafe { mem::zeroed::<perf_event_attr>() };
attr.config = config; attr.config = config;
@ -46,7 +46,7 @@ pub(crate) fn perf_event_open(
perf_event_sys(attr, pid, cpu, flags) perf_event_sys(attr, pid, cpu, flags)
} }
pub(crate) fn perf_event_open_bpf(cpu: c_int) -> SysResult<crate::MockableFd> { pub(crate) fn perf_event_open_bpf(cpu: c_int) -> io::Result<crate::MockableFd> {
perf_event_open( perf_event_open(
PERF_TYPE_SOFTWARE as u32, PERF_TYPE_SOFTWARE as u32,
PERF_COUNT_SW_BPF_OUTPUT as u64, PERF_COUNT_SW_BPF_OUTPUT as u64,
@ -66,7 +66,7 @@ pub(crate) fn perf_event_open_probe(
name: &OsStr, name: &OsStr,
offset: u64, offset: u64,
pid: Option<pid_t>, pid: Option<pid_t>,
) -> SysResult<crate::MockableFd> { ) -> io::Result<crate::MockableFd> {
use std::os::unix::ffi::OsStrExt as _; use std::os::unix::ffi::OsStrExt as _;
let mut attr = unsafe { mem::zeroed::<perf_event_attr>() }; let mut attr = unsafe { mem::zeroed::<perf_event_attr>() };
@ -91,7 +91,7 @@ pub(crate) fn perf_event_open_probe(
pub(crate) fn perf_event_open_trace_point( pub(crate) fn perf_event_open_trace_point(
id: u32, id: u32,
pid: Option<pid_t>, pid: Option<pid_t>,
) -> SysResult<crate::MockableFd> { ) -> io::Result<crate::MockableFd> {
let mut attr = unsafe { mem::zeroed::<perf_event_attr>() }; let mut attr = unsafe { mem::zeroed::<perf_event_attr>() };
attr.size = mem::size_of::<perf_event_attr>() as u32; attr.size = mem::size_of::<perf_event_attr>() as u32;
@ -104,7 +104,7 @@ pub(crate) fn perf_event_open_trace_point(
perf_event_sys(attr, pid, cpu, PERF_FLAG_FD_CLOEXEC) perf_event_sys(attr, pid, cpu, PERF_FLAG_FD_CLOEXEC)
} }
pub(crate) fn perf_event_ioctl(fd: BorrowedFd<'_>, request: u32, arg: c_int) -> SysResult<c_long> { pub(crate) fn perf_event_ioctl(fd: BorrowedFd<'_>, request: u32, arg: c_int) -> SysResult {
let call = Syscall::PerfEventIoctl { fd, request, arg }; let call = Syscall::PerfEventIoctl { fd, request, arg };
#[cfg(not(test))] #[cfg(not(test))]
return syscall(call); return syscall(call);
@ -118,22 +118,23 @@ fn perf_event_sys(
pid: pid_t, pid: pid_t,
cpu: i32, cpu: i32,
flags: u32, flags: u32,
) -> SysResult<crate::MockableFd> { ) -> io::Result<crate::MockableFd> {
let fd = syscall(Syscall::PerfEventOpen { let fd = syscall(Syscall::PerfEventOpen {
attr, attr,
pid, pid,
cpu, cpu,
group: -1, group: -1,
flags, flags,
})
.map_err(|(code, io_error)| {
assert_eq!(code, -1);
io_error
})?; })?;
let fd = fd.try_into().map_err(|std::num::TryFromIntError { .. }| { let fd = fd.try_into().map_err(|std::num::TryFromIntError { .. }| {
( io::Error::new(
fd, io::ErrorKind::InvalidData,
io::Error::new( format!("perf_event_open: invalid fd returned: {fd}"),
io::ErrorKind::InvalidData,
format!("perf_event_open: invalid fd returned: {fd}"),
),
) )
})?; })?;

Loading…
Cancel
Save