ext2: re-enable block cache
This commit is contained in:
parent
93c143fa58
commit
dd2c948107
@ -180,7 +180,7 @@ impl Ext2Fs {
|
||||
(!unsupported, enabled)
|
||||
}
|
||||
|
||||
async fn create_fs(device: &'static dyn BlockDevice, _cached: bool) -> Result<Self, Error> {
|
||||
async fn create_fs(device: &'static dyn BlockDevice, cached: bool) -> Result<Self, Error> {
|
||||
let mut superblock = ExtendedSuperblock::zeroed();
|
||||
device
|
||||
.read_exact(
|
||||
@ -245,12 +245,10 @@ impl Ext2Fs {
|
||||
|
||||
log::info!("Inode size: {}", superblock.inode_size());
|
||||
|
||||
// TODO block cache produces data corruption
|
||||
let cache = DeviceMapper::uncached(device, block_size);
|
||||
// let cache = match cached {
|
||||
// false => MaybeCache::uncached(device, block_size),
|
||||
// true => MaybeCache::cached_with_capacity(device, block_size, 512),
|
||||
// };
|
||||
let mapper = match cached {
|
||||
false => DeviceMapper::uncached(device, block_size),
|
||||
true => DeviceMapper::cached_with_capacity(device, block_size, 512),
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
block_size,
|
||||
@ -263,8 +261,7 @@ impl Ext2Fs {
|
||||
block_group_inode_count,
|
||||
block_group_block_count,
|
||||
|
||||
// 128 × 8 cache
|
||||
mapper: cache,
|
||||
mapper,
|
||||
inode_cache: OneTimeInit::new(),
|
||||
state: IrqSafeRwLock::new(State {
|
||||
superblock,
|
||||
|
@ -4,7 +4,7 @@ use core::{
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use kernel_arch::mem::PhysicalMemoryAllocator;
|
||||
use libk_mm::{address::PhysicalAddress, phys::GlobalPhysicalAllocator, PageBox};
|
||||
use libk_util::{lru_hash_table::LruCache, sync::spin_rwlock::IrqSafeRwLock};
|
||||
@ -41,7 +41,7 @@ pub struct BlockCache<
|
||||
> {
|
||||
device: &'static dyn BlockDevice,
|
||||
block_size: usize,
|
||||
_pd: PhantomData<A>,
|
||||
cache: AsyncMutex<LruCache<u64, Arc<IrqSafeRwLock<CachedBlock<A>>>>>,
|
||||
}
|
||||
|
||||
impl DeviceMapper {
|
||||
@ -64,9 +64,8 @@ impl<A: PhysicalMemoryAllocator<Address = PhysicalAddress>> DeviceMapper<A> {
|
||||
block_size: usize,
|
||||
bucket_capacity: usize,
|
||||
) -> DeviceMapper<A> {
|
||||
todo!()
|
||||
// let cache = BlockCache::<A>::with_capacity_in(device, block_size, bucket_capacity);
|
||||
// DeviceMapper::<A>::Cached(cache)
|
||||
let cache = BlockCache::<A>::with_capacity_in(device, block_size, bucket_capacity);
|
||||
DeviceMapper::<A>::Cached(cache)
|
||||
}
|
||||
|
||||
pub fn uncached_in(device: &'static dyn BlockDevice, block_size: usize) -> DeviceMapper<A> {
|
||||
@ -84,7 +83,7 @@ impl<A: PhysicalMemoryAllocator<Address = PhysicalAddress>> DeviceMapper<A> {
|
||||
pub fn device(&self) -> &'static dyn BlockDevice {
|
||||
match self {
|
||||
Self::Uncached(uncache) => uncache.device(),
|
||||
Self::Cached(_cache) => todo!(),
|
||||
Self::Cached(cache) => cache.device(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,7 +94,7 @@ impl<A: PhysicalMemoryAllocator<Address = PhysicalAddress>> DeviceMapper<A> {
|
||||
) -> Result<T, Error> {
|
||||
match self {
|
||||
Self::Uncached(uncache) => uncache.try_with(pos, mapper).await,
|
||||
Self::Cached(_cache) => todo!(),
|
||||
Self::Cached(cache) => cache.try_with(pos, mapper).await,
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,14 +105,17 @@ impl<A: PhysicalMemoryAllocator<Address = PhysicalAddress>> DeviceMapper<A> {
|
||||
) -> Result<T, Error> {
|
||||
match self {
|
||||
Self::Uncached(uncache) => uncache.try_with_mut(pos, mapper).await,
|
||||
Self::Cached(_cache) => todo!(),
|
||||
Self::Cached(cache) => cache.try_with_mut(pos, mapper).await,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn flush(&self) -> Result<(), Error> {
|
||||
match self {
|
||||
Self::Uncached(_) => Ok(()),
|
||||
Self::Cached(_cache) => todo!(),
|
||||
Self::Cached(cache) => {
|
||||
cache.flush().await;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -148,6 +150,87 @@ impl<A: PhysicalMemoryAllocator<Address = PhysicalAddress>> UncachedCache<A> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: PhysicalMemoryAllocator<Address = PhysicalAddress>> BlockCache<A> {
|
||||
pub fn with_capacity_in(
|
||||
device: &'static dyn BlockDevice,
|
||||
block_size: usize,
|
||||
bucket_capacity: usize,
|
||||
) -> BlockCache<A> {
|
||||
if block_size % device.block_size() != 0 {
|
||||
panic!("Cache block size is not multiple of device block size");
|
||||
}
|
||||
BlockCache {
|
||||
device,
|
||||
block_size,
|
||||
cache: AsyncMutex::new(LruCache::with_capacity(bucket_capacity, 8)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn device(&self) -> &'static dyn BlockDevice {
|
||||
self.device
|
||||
}
|
||||
|
||||
async fn evict_block(&self, pos: u64, block: Arc<IrqSafeRwLock<CachedBlock<A>>>) {
|
||||
let read = block.read();
|
||||
if read.dirty {
|
||||
if let Err(err) = self.device.write_aligned(pos, read.data.as_slice()).await {
|
||||
log::error!("Disk error: flushing block {}: {:?}", pos, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn fetch_block(&self, pos: u64) -> Result<Arc<IrqSafeRwLock<CachedBlock<A>>>, Error> {
|
||||
let mut data = PageBox::new_uninit_slice_in(self.block_size)?;
|
||||
self.device.read_aligned(pos, data.as_slice_mut()).await?;
|
||||
let data = unsafe { data.assume_init_slice() };
|
||||
Ok(Arc::new(IrqSafeRwLock::new(CachedBlock {
|
||||
data,
|
||||
dirty: false,
|
||||
})))
|
||||
}
|
||||
|
||||
async fn entry(&self, pos: u64) -> Result<Arc<IrqSafeRwLock<CachedBlock<A>>>, Error> {
|
||||
let mut lock = self.cache.lock().await;
|
||||
let (value, evicted) = lock
|
||||
.try_get_or_insert_with_async(pos, || self.fetch_block(pos))
|
||||
.await?;
|
||||
|
||||
if let Some((pos, block)) = evicted {
|
||||
self.evict_block(pos, block).await;
|
||||
}
|
||||
|
||||
Ok(value.clone())
|
||||
}
|
||||
|
||||
pub async fn try_with<T, F: FnOnce(&[u8]) -> Result<T, Error>>(
|
||||
&self,
|
||||
pos: u64,
|
||||
mapper: F,
|
||||
) -> Result<T, Error> {
|
||||
let block = self.entry(pos).await?;
|
||||
let result = mapper(&block.read()[..])?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn try_with_mut<T, F: FnOnce(&mut [u8]) -> Result<T, Error>>(
|
||||
&self,
|
||||
pos: u64,
|
||||
mapper: F,
|
||||
) -> Result<T, Error> {
|
||||
let block = self.entry(pos).await?;
|
||||
let mut block = block.write();
|
||||
let result = mapper(&mut block[..])?;
|
||||
block.dirty = true;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn flush(&self) {
|
||||
for (pos, block) in self.cache.lock().await.flush() {
|
||||
self.evict_block(pos, block).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: PhysicalMemoryAllocator<Address = PhysicalAddress>> CachedBlock<A> {
|
||||
pub fn set_dirty(&mut self) {
|
||||
self.dirty = true;
|
||||
|
Loading…
x
Reference in New Issue
Block a user