diff --git a/kernel/libk/src/vfs/block/cache.rs b/kernel/libk/src/vfs/block/cache.rs index 9392f60d..e7a54c65 100644 --- a/kernel/libk/src/vfs/block/cache.rs +++ b/kernel/libk/src/vfs/block/cache.rs @@ -4,7 +4,7 @@ use alloc::sync::Arc; use libk_mm::PageBox; use libk_util::{ lru_hash_table::LruCache, - sync::spin_rwlock::{IrqSafeRwLock, IrqSafeRwLockReadGuard}, + sync::spin_rwlock::{IrqSafeRwLock, IrqSafeRwLockReadGuard, IrqSafeRwLockWriteGuard}, }; use yggdrasil_abi::error::Error; @@ -22,6 +22,11 @@ pub struct CachedBlockRef { lock: IrqSafeRwLockReadGuard<'static, CachedBlock>, } +pub struct CachedBlockMut { + _entry: Arc<IrqSafeRwLock<CachedBlock>>, + lock: IrqSafeRwLockWriteGuard<'static, CachedBlock>, +} + pub struct BlockCache { device: &'static dyn BlockDevice, block_size: usize, @@ -70,11 +75,20 @@ impl BlockCache { }))) } - pub async fn get<'a>(&'a self, address: u64) -> Result<CachedBlockRef, Error> { + async fn entry<'a>( + &'a self, + address: u64, + ) -> Result< + MappedAsyncMutexGuard< + 'a, + Arc<IrqSafeRwLock<CachedBlock>>, + LruCache<u64, Arc<IrqSafeRwLock<CachedBlock>>>, + >, + Error, + > { debug_assert_eq!(address % self.block_size as u64, 0); - let entry: MappedAsyncMutexGuard<_, LruCache<u64, Arc<IrqSafeRwLock<CachedBlock>>>> = self - .cache + self.cache .lock() .await .try_map_guard_async::<_, Error, _>(|cache: &'a mut LruCache<_, _>| async move { @@ -88,9 +102,19 @@ impl BlockCache { Ok(value) }) - .await?; + .await + } - Ok(CachedBlockRef::new(entry.deref())) + pub async fn get<'a>(&'a self, address: u64) -> Result<CachedBlockRef, Error> { + self.entry(address) + .await + .map(|e| CachedBlockRef::new(e.deref())) + } + + pub async fn get_mut<'a>(&'a self, address: u64) -> Result<CachedBlockMut, Error> { + self.entry(address) + .await + .map(|mut e| CachedBlockMut::new(e.deref_mut())) } pub async fn flush(&self) { @@ -118,6 +142,18 @@ impl CachedBlockRef { } } +impl CachedBlockMut { + pub fn new(entry: &Arc<IrqSafeRwLock<CachedBlock>>) -> Self { + let entry = entry.clone(); + // Safety: ok, Arc instance is still held + let lock = unsafe { core::mem::transmute(entry.write()) }; + Self { + lock, + _entry: entry, + } + } +} + impl Deref for CachedBlockRef { type Target = PageBox<[u8]>; @@ -126,6 +162,20 @@ impl Deref for CachedBlockRef { } } +impl Deref for CachedBlockMut { + type Target = PageBox<[u8]>; + + fn deref(&self) -> &Self::Target { + self.lock.deref() + } +} + +impl DerefMut for CachedBlockMut { + fn deref_mut(&mut self) -> &mut Self::Target { + self.lock.deref_mut() + } +} + impl Deref for CachedBlock { type Target = PageBox<[u8]>;