diff --git a/easy-fs/Cargo.toml b/easy-fs/Cargo.toml index 3beb3ff2..16ffc303 100644 --- a/easy-fs/Cargo.toml +++ b/easy-fs/Cargo.toml @@ -7,4 +7,6 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -spin = "0.7.0" \ No newline at end of file +spin = "0.7.0" +#lazy_static = { version = "1.4.0", features = ["spin_no_std"] } +lazy_static = "1.4.0" \ No newline at end of file diff --git a/easy-fs/src/bin/main.rs b/easy-fs/src/bin/main.rs index 3af832aa..1a8061fd 100644 --- a/easy-fs/src/bin/main.rs +++ b/easy-fs/src/bin/main.rs @@ -4,7 +4,6 @@ extern crate alloc; use easy_fs::{ BlockDevice, EasyFileSystem, - Inode, }; use std::fs::{File, OpenOptions}; use std::io::{Read, Write, Seek, SeekFrom}; @@ -54,7 +53,7 @@ fn easy_fs_pack() -> std::io::Result<()> { root_inode.create("filea"); root_inode.create("fileb"); for name in root_inode.ls() { - println!("name"); + println!("{}", name); } Ok(()) } \ No newline at end of file diff --git a/easy-fs/src/block_cache.rs b/easy-fs/src/block_cache.rs new file mode 100644 index 00000000..34450f63 --- /dev/null +++ b/easy-fs/src/block_cache.rs @@ -0,0 +1,86 @@ +use super::{ + BlockDevice, + BLOCK_SZ, +}; +use alloc::sync::{Arc, Weak}; +use alloc::collections::BTreeMap; +use lazy_static::*; +use spin::Mutex; + +pub struct BlockCache { + cache: [u8; BLOCK_SZ], + block_id: usize, + block_device: Arc, +} + +impl BlockCache { + pub fn new(block_id: usize, block_device: Arc) -> Self { + let mut cache = [0u8; BLOCK_SZ]; + block_device.read_block(block_id, &mut cache); + Self { + cache, + block_id, + block_device, + } + } + pub fn start_addr(&self, offset: usize) -> usize { + &self.cache[offset] as *const _ as usize + } +} + +impl Drop for BlockCache { + fn drop(&mut self) { + // write back + self.block_device.write_block(self.block_id, &self.cache); + // invalid in block cache manager + BLOCK_CACHE_MANAGER.lock().invalid(self.block_id); + } +} + +pub struct BlockCacheManager { + map: BTreeMap>, +} + +lazy_static! { + static ref BLOCK_CACHE_MANAGER: Mutex = Mutex::new( + BlockCacheManager::new() + ); +} + +impl BlockCacheManager { + pub fn new() -> Self { + Self { map: BTreeMap::new() } + } + pub fn get( + &mut self, + block_id: usize, + block_device: Arc + ) -> Arc { + if let Some(block_cache) = self.map.get(&block_id) { + // return cloned + block_cache.upgrade().unwrap().clone() + } else { + // fetch from disk + let block_cache = Arc::new(BlockCache::new( + block_id, + block_device.clone() + )); + self.map.insert( + block_id, + Arc::downgrade(&block_cache), + ); + // return + block_cache + } + } + pub fn invalid(&mut self, block_id: usize) { + assert!(self.map.remove(&block_id).is_some()); + } +} + +pub fn get_block_cache( + block_id: usize, + block_device: Arc +) -> Arc { + BLOCK_CACHE_MANAGER.lock().get(block_id, block_device) +} \ No newline at end of file diff --git a/easy-fs/src/dirty.rs b/easy-fs/src/dirty.rs index 8fa7a895..fc02aab4 100644 --- a/easy-fs/src/dirty.rs +++ b/easy-fs/src/dirty.rs @@ -1,45 +1,38 @@ -use super::BlockDevice; -use super::BLOCK_SZ; +use super::{ + BlockDevice, + BLOCK_SZ, + BlockCache, + get_block_cache, +}; use alloc::sync::Arc; use core::marker::PhantomData; pub struct Dirty { - block_id: usize, - block_cache: [u8; BLOCK_SZ], + block_cache: Arc, offset: usize, - dirty: bool, - block_device: Arc, phantom: PhantomData, } impl Dirty where T: Sized { pub fn new(block_id: usize, offset: usize, block_device: Arc) -> Self { Self { - block_id, - block_cache: { - let mut cache = [0u8; BLOCK_SZ]; - block_device.read_block(block_id as usize, &mut cache); - cache - }, + block_cache: get_block_cache(block_id, block_device.clone()), offset, - dirty: false, - block_device, phantom: PhantomData, } } pub fn get_mut(&mut self) -> &mut T { - self.dirty = true; let type_size = core::mem::size_of::(); // assert that the struct is inside a block assert!(self.offset + type_size <= BLOCK_SZ); - let start_addr = &self.block_cache[self.offset] as *const _ as usize; + let start_addr = self.block_cache.start_addr(self.offset); unsafe { &mut *(start_addr as *mut T) } } pub fn get_ref(&self) -> &T { let type_size = core::mem::size_of::(); // assert that the struct is inside a block assert!(self.offset + type_size <= BLOCK_SZ); - let start_addr = &self.block_cache[self.offset] as *const _ as usize; + let start_addr = self.block_cache.start_addr(self.offset); unsafe { &*(start_addr as *const T) } } pub fn read(&self, f: impl FnOnce(&T) -> V) -> V { @@ -48,16 +41,4 @@ impl Dirty where T: Sized { pub fn modify(&mut self, f: impl FnOnce(&mut T)) { f(self.get_mut()); } - pub fn write_back(&mut self) { - if self.dirty { - self.block_device - .write_block(self.block_id as usize, &self.block_cache); - } - } } - -impl Drop for Dirty { - fn drop(&mut self) { - self.write_back(); - } -} \ No newline at end of file diff --git a/easy-fs/src/layout.rs b/easy-fs/src/layout.rs index 174d64cf..d262f354 100644 --- a/easy-fs/src/layout.rs +++ b/easy-fs/src/layout.rs @@ -247,7 +247,7 @@ pub struct DirEntry { pub const DIRENT_SZ: usize = 32; -pub type DirentBlock = [DirEntry; BLOCK_SZ / DIRENT_SZ]; +//pub type DirentBlock = [DirEntry; BLOCK_SZ / DIRENT_SZ]; pub type DirentBytes = [u8; DIRENT_SZ]; impl DirEntry { diff --git a/easy-fs/src/lib.rs b/easy-fs/src/lib.rs index 4202fb4b..dfd1725e 100644 --- a/easy-fs/src/lib.rs +++ b/easy-fs/src/lib.rs @@ -6,6 +6,7 @@ mod efs; mod dirty; mod bitmap; mod vfs; +mod block_cache; pub const BLOCK_SZ: usize = 512; pub use block_dev::BlockDevice; @@ -13,4 +14,5 @@ pub use efs::EasyFileSystem; pub use vfs::Inode; use layout::*; use dirty::Dirty; -use bitmap::Bitmap; \ No newline at end of file +use bitmap::Bitmap; +use block_cache::{BlockCache, get_block_cache}; \ No newline at end of file diff --git a/easy-fs/src/vfs.rs b/easy-fs/src/vfs.rs index 2a989f99..30b31cf9 100644 --- a/easy-fs/src/vfs.rs +++ b/easy-fs/src/vfs.rs @@ -6,13 +6,11 @@ use super::{ DirEntry, DirentBytes, EasyFileSystem, - BLOCK_SZ, DIRENT_SZ, }; use alloc::sync::Arc; use alloc::string::String; use alloc::vec::Vec; -use crate::layout::DiskInodeType::Directory; use spin::{Mutex, MutexGuard}; pub struct Inode {