init inode storage

pull/916/head
Addison Crump 6 months ago
parent 09442c2cbe
commit 932cef84b9
No known key found for this signature in database
GPG Key ID: D495C2DF24C779B2

@ -0,0 +1,148 @@
use core::{cell::UnsafeCell, marker::PhantomData, mem, ptr::NonNull};
use aya_ebpf_bindings::{
bindings::{
bpf_map_def,
bpf_map_type::{BPF_MAP_TYPE_HASH, BPF_MAP_TYPE_INODE_STORAGE},
BPF_LOCAL_STORAGE_GET_F_CREATE,
},
helpers::{bpf_inode_storage_delete, bpf_inode_storage_get},
};
use aya_ebpf_cty::{c_int, c_void};
use crate::maps::PinningType;
/// A BPF map of type BPF_MAP_TYPE_INODE_STORAGE, used for attaching local storage data to an inode.
/// See bpf_inode_storage_get in bpf-helpers(7) for details.
#[repr(transparent)]
pub struct InodeStorage<V> {
def: UnsafeCell<bpf_map_def>,
_v: PhantomData<V>,
}
impl<V> InodeStorage<V> {
/// Instantiate a [`InodeStorage`] map with the provided flags.
pub const fn new(flags: u32) -> InodeStorage<V> {
InodeStorage {
def: UnsafeCell::new(build_def::<V>(
BPF_MAP_TYPE_INODE_STORAGE,
flags,
PinningType::None,
)),
_v: PhantomData,
}
}
/// Instantiate a pinned [`InodeStorage`] map with the provided flags.
pub const fn pinned(flags: u32) -> InodeStorage<V> {
InodeStorage {
def: UnsafeCell::new(build_def::<V>(
BPF_MAP_TYPE_INODE_STORAGE,
flags,
PinningType::ByName,
)),
_v: PhantomData,
}
}
/// Get a local storage entry associated with this inode, or insert the provided value and get
/// the mutable reference to the information stored within the inode. Returns [`None`] if there
/// was an issue with inserting the new value.
///
/// ## Safety
///
/// This function is marked unsafe as accessing the same inode's local storage multiple times
/// would create multiple mutable references to the same data, which is not supported by Rust's
/// memory model.
#[inline]
pub unsafe fn get_or_insert(&self, inode: *mut c_void, initial: &V) -> Option<&mut V> {
self.get_or_insert_ptr(inode, initial).map(|p| &mut *p)
}
/// Get a pointer to the local storage entry associated with this inode, or insert the provided
/// value and get the mutable reference to the information stored within the inode. Returns
/// [`None`] if there was an issue with inserting the new value.
#[inline]
pub fn get_or_insert_ptr(&self, inode: *mut c_void, initial: &V) -> Option<*mut V> {
unsafe {
let ptr = bpf_inode_storage_get(
self.def.get() as *mut c_void,
inode,
initial as *const V as *const c_void as *mut c_void,
BPF_LOCAL_STORAGE_GET_F_CREATE as u64,
);
NonNull::new(ptr as *mut V).map(|p| p.as_ptr())
}
}
/// Get a local storage entry associated with this inode, or [`None`] if no such value exists.
///
/// ## Safety
///
/// This function is marked unsafe as accessing the same inode's local storage immutably at the
/// same time as mutably (e.g., but way of [`InodeStorage::get_mut`]) is not supported by Rust's
/// memory model.
#[inline]
pub unsafe fn get(&self, inode: *mut c_void) -> Option<&V> {
self.get_ptr(inode).map(|p| &*p)
}
/// Mutably access a local storage entry associated with this inode, or [`None`] if no such
/// value exists.
///
/// ## Safety
///
/// This function is marked unsafe as accessing the same inode's local storage mutably multiple
/// times is not supported by Rust's memory model.
#[inline]
pub unsafe fn get_mut(&self, inode: *mut c_void) -> Option<&mut V> {
self.get_ptr_mut(inode).map(|p| &mut *p)
}
/// Get a pointer to the local storage entry associated with this inode, or [`None`] if no such
/// value exists.
#[inline]
pub fn get_ptr(&self, inode: *mut c_void) -> Option<*const V> {
self.get_ptr_mut(inode).map(|p| p as *const V)
}
/// Get a mutable pointer to the local storage entry associated with this inode, or [`None`] if
/// no such value exists. You are responsible for ensuring that at most one mutable reference to
/// the same inode local storage exists at a given time.
#[inline]
pub fn get_ptr_mut(&self, inode: *mut c_void) -> Option<*mut V> {
unsafe {
let ptr = bpf_inode_storage_get(
self.def.get() as *mut c_void,
inode,
core::ptr::null_mut(),
0,
);
NonNull::new(ptr as *mut V).map(|p| p.as_ptr())
}
}
/// Remove a local storage entry associated with this inode. Returns `Err(-ENOENT)` if no such
/// value was present.
#[inline]
pub fn remove(&self, inode: *mut c_void) -> Result<(), c_int> {
let ret = unsafe { bpf_inode_storage_delete(self.def.get() as *mut c_void, inode) };
if ret == 0 {
Ok(())
} else {
Err(ret)
}
}
}
const fn build_def<V>(ty: u32, flags: u32, pin: PinningType) -> bpf_map_def {
bpf_map_def {
type_: ty,
key_size: mem::size_of::<c_int>() as u32,
value_size: mem::size_of::<V>() as u32,
max_entries: 0,
map_flags: flags,
id: 0,
pinning: pin as u32,
}
}

@ -8,6 +8,7 @@ pub(crate) enum PinningType {
pub mod array;
pub mod bloom_filter;
pub mod hash_map;
pub mod inode_storage;
pub mod lpm_trie;
pub mod per_cpu_array;
pub mod perf;

@ -24,6 +24,10 @@ path = "src/log.rs"
name = "map_test"
path = "src/map_test.rs"
[[bin]]
name = "inode_storage"
path = "src/inode_storage.rs"
[[bin]]
name = "name_test"
path = "src/name_test.rs"

@ -0,0 +1,7 @@
#![no_std]
#![no_main]
use aya_ebpf::{macros::map, maps::inode_storage::InodeStorage};
#[map]
static INODE_STORE: InodeStorage<usize> = InodeStorage::new(0);
Loading…
Cancel
Save