diff options
author | Chuyan Zhang <me@zcy.moe> | 2023-11-18 02:15:11 -0800 |
---|---|---|
committer | Chuyan Zhang <me@zcy.moe> | 2023-11-18 02:15:11 -0800 |
commit | cd0163da154367f5437ae1423bc97c450d74adf7 (patch) | |
tree | c8f88dae8da14f9c2614170e48c5eedd279459f5 /src | |
parent | 95d8d84eef645b52d92fd3fb8fdea7aed1f6d474 (diff) | |
download | myfs-cd0163da154367f5437ae1423bc97c450d74adf7.tar.gz myfs-cd0163da154367f5437ae1423bc97c450d74adf7.zip |
I hate cache!
Diffstat (limited to 'src')
-rw-r--r-- | src/cached_inode.rs | 26 | ||||
-rw-r--r-- | src/disk/bitmap.rs | 28 | ||||
-rw-r--r-- | src/disk/data_block.rs | 89 | ||||
-rw-r--r-- | src/disk/inode.rs | 4 | ||||
-rw-r--r-- | src/main.rs | 599 |
5 files changed, 478 insertions, 268 deletions
diff --git a/src/cached_inode.rs b/src/cached_inode.rs index 814c1aa..a4e8202 100644 --- a/src/cached_inode.rs +++ b/src/cached_inode.rs @@ -1,3 +1,4 @@ +use crate::disk::data_block::{Block, DataBlock}; use crate::disk::inode::Inode; pub struct CachedInode { @@ -5,3 +6,28 @@ pub struct CachedInode { pub index: usize, pub dirty: bool, } + +#[derive(Clone)] +pub struct CachedBlock<T: Block> { + pub block: T, + pub index: usize, + pub dirty: bool, +} + +impl<T: Block> CachedBlock<T> { + fn cast<U: Block>(&self) -> CachedBlock<U> { + unsafe { std::mem::transmute_copy(&self) } + } +} + +pub fn convert_mut<U: Block, T: Block>(input_block: &mut CachedBlock<U>) -> &mut CachedBlock<T> { + let ptr = input_block as *const CachedBlock<U> as *mut u8; + let block = ptr.cast::<CachedBlock<T>>(); + unsafe { &mut *block } +} + +pub fn convert<U: Block, T: Block>(input_block: &CachedBlock<U>) -> &CachedBlock<T> { + let ptr = input_block as *const CachedBlock<U> as *mut u8; + let block = ptr.cast::<CachedBlock<T>>(); + unsafe { &*block } +} diff --git a/src/disk/bitmap.rs b/src/disk/bitmap.rs index d5a8fe9..64389c2 100644 --- a/src/disk/bitmap.rs +++ b/src/disk/bitmap.rs @@ -1,4 +1,5 @@ use crate::block_device::{BlockDevice, BLOCK_SIZE}; +use std::cell::RefCell; use std::sync::Arc; pub struct Bitmap { @@ -6,7 +7,6 @@ pub struct Bitmap { pub length: usize, pub device: Arc<dyn BlockDevice>, pub data: Vec<u8>, - pub dirty_blocks: Vec<usize>, } impl Bitmap { @@ -16,15 +16,14 @@ impl Bitmap { length, device, data: vec![0u8; length * BLOCK_SIZE], - dirty_blocks: Vec::new(), } } pub fn allocate(&mut self) -> Option<usize> { + // let mut data = self.data.borrow_mut(); for (i, byte) in self.data.iter_mut().enumerate() { let leading_ones = byte.leading_ones(); if leading_ones != 8 { *byte |= (1 << (7 - leading_ones)) as u8; - self.dirty_blocks.push(i / BLOCK_SIZE); return Some(i * 8 + leading_ones as usize); } } @@ -33,6 +32,7 @@ impl Bitmap { } pub fn query(&self, index: usize) -> bool { + // let data = self.data.borrow(); if index == 0 { false } else { @@ -40,15 +40,15 @@ impl Bitmap { } } - fn write_back(&mut self) { - for block_index_offset in self.dirty_blocks.iter() { - let buffer_front_index = BLOCK_SIZE * block_index_offset; - let buffer_back_index = BLOCK_SIZE * (block_index_offset + 1); - self.device.write( - self.starting_block + block_index_offset, - &self.data[buffer_front_index..buffer_back_index], - ); - } - self.dirty_blocks = Vec::new(); - } + // fn write_back(&mut self) { + // for block_index_offset in self.dirty_blocks.iter() { + // let buffer_front_index = BLOCK_SIZE * block_index_offset; + // let buffer_back_index = BLOCK_SIZE * (block_index_offset + 1); + // self.device.write( + // self.starting_block + block_index_offset, + // &self.data[buffer_front_index..buffer_back_index], + // ); + // } + // self.dirty_blocks = Vec::new(); + // } } diff --git a/src/disk/data_block.rs b/src/disk/data_block.rs index 2160b91..9c8cc26 100644 --- a/src/disk/data_block.rs +++ b/src/disk/data_block.rs @@ -1,12 +1,54 @@ -pub trait Block: Default {} +use crate::disk::inode::Inode; +use libc::pathconf; + +pub trait Block: Default + Clone {} + +#[derive(Clone)] +pub struct DataBlock(pub(crate) [u8; 4096]); + +impl Default for DataBlock { + fn default() -> Self { + Self([0; 4096]) + } +} -#[derive(Default)] -pub struct DataBlock([u8; 4096]); impl Block for DataBlock {} +#[derive(Clone)] +pub struct InodeBlock { + pub(crate) inodes: [Inode; 16], +} + +impl Default for InodeBlock { + fn default() -> Self { + Self { + inodes: [ + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + Inode::empty(), + ], + } + } +} + +impl Block for InodeBlock {} + const FULL_MAP: u32 = 0b111_111_111_111_111; -#[derive(Default)] +#[derive(Clone)] pub struct DirectoryBlock { entries: [[u8; 256]; 15], inode_ids: [usize; 15], @@ -14,6 +56,17 @@ pub struct DirectoryBlock { reserved: [u8; 132], } +impl Default for DirectoryBlock { + fn default() -> Self { + Self { + entries: [[0; 256]; 15], + inode_ids: [0; 15], + occupancy_map: 0, + reserved: [0xFF; 132], + } + } +} + impl Block for DirectoryBlock {} impl DirectoryBlock { @@ -42,11 +95,17 @@ impl DirectoryBlock { } } -#[derive(Default)] +#[derive(Clone)] pub struct IndirectBlock { pub entries: [u32; 1024], } +impl Default for IndirectBlock { + fn default() -> Self { + Self { entries: [0; 1024] } + } +} + impl Block for IndirectBlock {} impl IndirectBlock { @@ -59,11 +118,19 @@ impl IndirectBlock { } } -#[derive(Default)] +#[derive(Clone)] pub struct DoubleIndirectBlock { pub indirect: [u32; 1024], } +impl Default for DoubleIndirectBlock { + fn default() -> Self { + Self { + indirect: [0; 1024], + } + } +} + impl Block for DoubleIndirectBlock {} impl DoubleIndirectBlock { @@ -76,11 +143,19 @@ impl DoubleIndirectBlock { } } -#[derive(Default)] +#[derive(Clone)] pub struct TripleIndirectBlock { pub double_indirect: [u32; 1024], } +impl Default for TripleIndirectBlock { + fn default() -> Self { + Self { + double_indirect: [0; 1024], + } + } +} + impl Block for TripleIndirectBlock {} impl TripleIndirectBlock { diff --git a/src/disk/inode.rs b/src/disk/inode.rs index 6adc75d..48085d8 100644 --- a/src/disk/inode.rs +++ b/src/disk/inode.rs @@ -2,7 +2,7 @@ use bitflags::bitflags; const DIRECT_NUMBER: usize = 15; -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub struct InodeMode(u16); bitflags! { @@ -37,7 +37,7 @@ bitflags! { /// - added more direct blocks for a total size of 128 bytes /// TODO: do we need to extend time precision? #[repr(C)] -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Inode { mode: InodeMode, uid: u32, diff --git a/src/main.rs b/src/main.rs index 0e799e4..2885b14 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,19 +2,23 @@ mod block_device; mod cached_inode; mod disk; -use std::collections::HashMap; +use and_then_some::BoolExt; use clap::Parser; use fuser::{ Filesystem, KernelConfig, MountOption, ReplyAttr, ReplyData, ReplyDirectory, ReplyEmpty, ReplyEntry, ReplyLseek, ReplyWrite, Request, TimeOrNow, }; use log::debug; +use lru::LruCache; use std::ffi::OsStr; +use std::num::NonZeroUsize; use std::sync::Arc; use std::time::{Duration, SystemTime, UNIX_EPOCH}; -use crate::cached_inode::CachedInode; -use crate::disk::data_block::{Block, DoubleIndirectBlock, IndirectBlock, TripleIndirectBlock}; +use crate::cached_inode::{convert, convert_mut, CachedBlock, CachedInode}; +use crate::disk::data_block::{ + Block, DataBlock, DoubleIndirectBlock, IndirectBlock, InodeBlock, TripleIndirectBlock, +}; use crate::disk::inode::InodeMode; use block_device::{memory_disk::MemoryDisk, BlockDevice, BLOCK_SIZE}; use disk::bitmap::Bitmap; @@ -63,8 +67,9 @@ struct MyFS { inode_start_block: usize, data_start_block: usize, - cached_inode: HashMap<usize, CachedInode>, - cache: [[u8; 4096]; 8192], + cached_inodes: LruCache<usize, CachedInode>, + cached_blocks: LruCache<usize, CachedBlock<DataBlock>>, + // cached_block_cleanness: LruCache<usize, bool>, } impl MyFS { @@ -95,12 +100,15 @@ impl MyFS { + data_block_number ); - let data_bitmap = Bitmap::new(1, data_bitmap_block_number, device.clone()); - let inode_bitmap = Bitmap::new( + let mut data_bitmap = Bitmap::new(1, data_bitmap_block_number, device.clone()); + let _ = data_bitmap.allocate().unwrap(); // data block 0 is not usable + let mut inode_bitmap = Bitmap::new( data_bitmap_block_number + 1, inode_bitmap_block_number, device.clone(), ); + let _ = inode_bitmap.allocate().unwrap(); // inode block 0 is not usable + let mut fs = Self { device, data_bitmap, @@ -110,28 +118,16 @@ impl MyFS { + inode_bitmap_block_number + inode_block_number + 1, - cached_inode: HashMap::new(), - cache: [[0; 4096]; 8192], + cached_inodes: LruCache::new(NonZeroUsize::new(256).unwrap()), + cached_blocks: LruCache::new(NonZeroUsize::new(256).unwrap()), }; - let _ = fs.data_bitmap.allocate().unwrap(); // data block 0 is not usable - let _ = fs.inode_bitmap.allocate().unwrap(); // inode block 0 is not usable - let root_inode_index = fs.inode_bitmap.allocate().unwrap(); // Inode starts from 1 - assert_eq!(root_inode_index, 1); - let (root_inode_block, root_inode_offset) = fs.locate_inode(root_inode_index); - fs.put_inode( - root_inode_block, - root_inode_offset, - &Inode::directory( - 0o755, - get_current_uid(), - get_current_gid(), - Self::time_now(), - 0, - 0, - 0, - 0, - ), + fs.create_inode_2( + 0o755, + InodeMode::IFDIR, + get_current_uid(), + get_current_gid(), + 0, ); fs @@ -144,18 +140,6 @@ impl MyFS { .as_secs() as u32 } - pub fn inode_active(&self, inode: usize) -> bool { - self.inode_bitmap.query(inode) - } - - /// 输入 inode 编号, 返回它对应的 block number 和 block 内 offset - pub fn locate_inode(&self, inode_index: usize) -> (usize, usize) { - let block_number = - inode_index / INODE_PER_BLOCK + 1 + self.inode_bitmap.length + self.data_bitmap.length; - let block_offset = inode_index % INODE_PER_BLOCK * INODE_SIZE; - (block_number, block_offset) - } - pub fn create_inode( &mut self, permissions: u16, @@ -180,198 +164,323 @@ impl MyFS { index: inode_index, dirty: false, }; - self.cached_inode.insert(inode_index, inode); + self.cached_inodes.put(inode_index, inode); // TODO write back evicted inode inode_index }) } - /// 得有一个 Inode Cache 数据结构! - pub fn read_inode( + pub fn create_inode_2( &mut self, - index: usize, - ) -> bool { - if self.cached_inode.contains_key(&index) { - return true; - } // 已经在 Inode Cache 里了, 返回 true - if self.inode_bitmap.query(index) { - let (block, offset) = self.locate_inode(index); - let inode = CachedInode { - inode: self.fetch_inode(block, offset), - index, - dirty: false, - }; - self.cached_inode.insert(index, inode); - return true; - } // 没有在 Inode Cache 里, 但是是有效 inode, 可以读到 Cache 里, 返回 true - false // 都没有, 返回 false. + permissions: u16, + mode: InodeMode, + uid: u32, + gid: u32, + flags: u32, + ) -> Option<usize> { + self.inode_bitmap.allocate().map(|inode_index| { + self.get_inode_mut_2(inode_index).map(|inode| { + *inode = Inode::make_inode( + permissions, + mode, + uid, + gid, + Self::time_now(), + flags, + 0, + 0, + 0, + ); + }); + inode_index + }) } - pub fn write_back_inode( - &mut self, - index: usize, - ) -> bool { - if let Some(cached_inode) = self.cached_inode.get_mut(&index) { - if cached_inode.dirty { - let (block, offset) = self.locate_inode(cached_inode.index); - self.put_inode(block, offset, &cached_inode.inode); - cached_inode.dirty = false; - } - true // Inode 在 Cache 中, 如果 dirty 则写回, 如果不脏不用管, 都返回写回成功. + fn update_block<T: Block>(&mut self, block: CachedBlock<T>) -> bool { + if self.cached_blocks.contains(&block.index) { + let data_block = convert::<T, DataBlock>(&block).clone(); + self.cached_blocks.push(block.index, data_block); + true } else { - false // Inode 没有在 Cache 中, 返回失败. + false } } - // TODO: 实现一个 LRU 的 cache 机制, 不要每次都开 buffer - fn put_inode(&mut self, block: usize, offset: usize, inode: &Inode) { - let mut buffer = vec![0u8; BLOCK_SIZE]; - self.device.read(block, buffer.as_mut_slice()); + fn get_block<T: Block>(&mut self, index: usize) -> Option<&CachedBlock<T>> { + self.load_block(index) + .and_then(|| self.cached_blocks.get(&index).map(convert::<DataBlock, T>)) + } + + fn get_block_mut<T: Block>(&mut self, index: usize) -> Option<&mut CachedBlock<T>> { + self.load_block(index).and_then(|| { + self.cached_blocks + .get_mut(&index) + .map(convert_mut::<DataBlock, T>) + }) + } + + fn load_block(&mut self, index: usize) -> bool { + // 反正我自己保证所有实现了 Block trait 的数据结构都是 4K bytes 长, 来回 cast 没问题 + // 如果 block cache 里没有这个 block + if self.cached_blocks.contains(&index) == false { + if self.data_bitmap.query(index) == false { + return false; + } // 先看这个 block 是不是 valid, 不 valid 直接返回 None + let block = DataBlock::default(); + let buffer = unsafe { + std::slice::from_raw_parts_mut(&block as *const DataBlock as *mut u8, BLOCK_SIZE) + }; + self.device.read(index, buffer); + let cached_block = CachedBlock { + block, + index, + dirty: false, + }; + if let Some((old_index, old_block)) = self.cached_blocks.push(index, cached_block) { + assert_ne!(old_index, index); // 只有 block 不在 cache 里的时候才会插入 + if old_block.dirty { + let old_block_ptr = &old_block.block as *const DataBlock as *mut u8; + let old_block_buffer = + unsafe { std::slice::from_raw_parts(old_block_ptr, BLOCK_SIZE) }; + self.device.write(old_index, old_block_buffer); + } + } // 如果 valid 就放到 block cache 里, 同时将(可能)被驱逐的 block 依据其是否为脏块进行写回 + } + + true + } - let inode_raw = inode as *const Inode as *const u8; - let inode_slice = unsafe { std::slice::from_raw_parts(inode_raw, INODE_SIZE) }; - buffer[offset..offset + INODE_SIZE].copy_from_slice(inode_slice); + fn get_inode_2(&mut self, inode_index: usize) -> Option<&Inode> { + self.inode_bitmap.query(inode_index).and_then(|| { + let (block_index, offset) = self.locate_inode(inode_index); + self.get_block::<InodeBlock>(block_index) + .map(|cached_block| &cached_block.block.inodes[offset / INODE_SIZE]) + }) + } - self.device.write(block, buffer.as_slice()); + fn get_inode_mut_2(&mut self, inode_index: usize) -> Option<&mut Inode> { + self.inode_bitmap.query(inode_index).and_then(|| { + let (block_index, offset) = self.locate_inode(inode_index); + self.get_block_mut::<InodeBlock>(block_index) + .map(|cached_block| { + cached_block.dirty = true; // 保守一些, 只要返回了 &mut Inode 这个页一定标记为脏 + &mut cached_block.block.inodes[offset / INODE_SIZE] + }) + }) } - pub fn write_inode(&mut self, inode_index: usize, inode: &Inode) -> bool { - if self.inode_active(inode_index) { - let (block, offset) = self.locate_inode(inode_index); - self.put_inode(block, offset, inode); - true - } else { - false + /// 不使用 inode cache, 只用 block cache 的方案 + fn load_inode_2(&mut self, inode_index: usize) -> bool { + // 首先保证 inode 有效, 无效返回 false + if !self.inode_bitmap.query(inode_index) { + return false; + } + // 找到 inode + let (block_index, _) = self.locate_inode(inode_index); + if self.cached_blocks.contains(&block_index) { + return true; } + + return self.load_block(block_index); + } + + fn get_inode(&mut self, inode_index: usize) -> Option<&CachedInode> { + self.load_inode(inode_index) + .and_then(|| self.cached_inodes.get(&inode_index)) } - pub fn get_inode(&self, inode_index: usize) -> Option<Inode> { - if self.inode_active(inode_index) { - let (block, offset) = self.locate_inode(inode_index); - Some(self.fetch_inode(block, offset)) + fn get_inode_mut(&mut self, inode_index: usize) -> Option<&mut CachedInode> { + self.load_inode(inode_index) + .and_then(|| self.cached_inodes.get_mut(&inode_index)) + } + + fn load_inode(&mut self, inode_index: usize) -> bool { + // 首先保证 inode 有效, 无效返回 false + if !self.inode_bitmap.query(inode_index) { + return false; + } + // 如果已经缓存了就返回 true + if self.cached_inodes.contains(&inode_index) { + return true; + } + // inode 有效但没有在 cache 里 + let (block_index, offset) = self.locate_inode(inode_index); + // 找到 inode 所在的 block + if let Some(inode_block) = self.get_block::<DataBlock>(block_index) { + // 创建新的 inode 并且从 block 中加载. + let inode = unsafe { std::mem::zeroed::<Inode>() }; + let inode_slice = unsafe { + std::slice::from_raw_parts_mut(&inode as *const Inode as *mut u8, INODE_SIZE) + }; + inode_slice.copy_from_slice(&inode_block.block.0[offset..offset + INODE_SIZE]); + + let cached_inode = CachedInode { + inode, + index: inode_index, + dirty: false, + }; + + // 将加载好的 inode 放进 inode cache + if let Some((old_index, old_inode)) = self.cached_inodes.push(inode_index, cached_inode) + { + assert_ne!(old_index, inode_index); // 如果 old_index == inode index 说明它原本就在 inode cache 里了. + if old_inode.dirty { + // 如果旧的 inode 被修改过了, 将它写回 block cache 并且标记对应 block 为脏 + let (old_block_index, old_offset) = self.locate_inode(old_index); + self.get_block_mut::<DataBlock>(old_block_index) + .map(|cached_block| { + let old_inode_ptr = &old_inode.inode as *const Inode as *const u8; + let old_inode_slice = + unsafe { std::slice::from_raw_parts(old_inode_ptr, INODE_SIZE) }; + cached_block.dirty = true; + cached_block.block.0[old_offset..old_offset + INODE_SIZE] + .copy_from_slice(old_inode_slice); + }) + .expect("Writing inode back to a invalid block!"); // Debug use + } + } } else { - None + panic!("Getting inode from a invalid block!"); // Debug use } + + true + } + + /// 输入 inode 编号, 返回它对应的 block number 和 block 内 offset + pub fn locate_inode(&self, inode_index: usize) -> (usize, usize) { + let block_number = + inode_index / INODE_PER_BLOCK + 1 + self.inode_bitmap.length + self.data_bitmap.length; + let block_offset = inode_index % INODE_PER_BLOCK * INODE_SIZE; + (block_number, block_offset) } /// 为 Inode 分配新 block, 返回 block 的编号 pub fn allocate_block(&mut self, inode: &mut Inode) -> Option<u32> { - /// 从 direct block 里面尝试分配 + // 先看这个 inode 的 direct block 有没有空闲 for index in inode.direct.iter_mut() { - /// 如果这个位置没被分配, 分配一个 index 塞进去 - if self.data_bitmap.query(*index as usize) == false { - let block_index = self.data_bitmap.allocate() as u32; + if !self.data_bitmap.query(*index as usize) { + let block_index = self + .data_bitmap + .allocate() + .unwrap() as u32; *index = block_index; inode.n_blocks += 1; - // TODO 标记 inode 所在 block 为脏 + // 当调用 get_inode_mut 拿出 &mut Inode 的时候对应的 block 在 cache 里已经脏了 return Some(block_index); } } - /// 如果这个 indirect block 还未分配, 分配一个 - if self.data_bitmap.query(inode.single_indirect as usize) == false { - // TODO 标记 inode 所在 block 为脏 - inode.single_indirect = self.data_bitmap.allocate() as u32; + // direct block 全部分配完了, 先检查 indirect block 有没有分配, 没有就分配一个 + if !self.data_bitmap.query(inode.single_indirect as usize) { + inode.single_indirect = self + .data_bitmap + .allocate() + .expect("No free space for new block") as u32; } + // 在 indirect block 里尝试分配 if let Some(block_index) = self.allocate_in_indirect(inode.single_indirect) { - // TODO 标记 inode 所在 block 为脏 inode.n_blocks += 1; return Some(block_index); } - /// 如果 double indirect block 还未分配, 分配一个 - if self.data_bitmap.query(inode.double_indirect as usize) == false { - // TODO 标记 inode 所在 block 为脏 - inode.double_indirect = self.data_bitmap.allocate() as u32; + // direct & indirect block 全部分配完了, 先检查 double indirect block 有没有分配, 没有就分配一个 + if !self.data_bitmap.query(inode.double_indirect as usize) { + inode.double_indirect = self + .data_bitmap + .allocate() + .expect("No free space for new block") as u32; } + // 在 double indirect block 里尝试分配 if let Some(block_index) = self.alloc_in_double_indirect(inode.double_indirect) { - // TODO 标记 inode 所在 block 为脏 inode.n_blocks += 1; return Some(block_index); } - /// 如果 triple indirect block 还未分配, 分配一个 - if self.data_bitmap.query(inode.triple_indirect as usize) == false { - // TODO 标记 inode 所在 block 为脏 - inode.triple_indirect = self.data_bitmap.allocate() as u32; + // direct, indirect & double indirect block 全部分配完了, 先检查 triple indirect block 有没有分配, 没有就分配一个 + if !self.data_bitmap.query(inode.triple_indirect as usize) { + inode.triple_indirect = self + .data_bitmap + .allocate() + .expect("No free space for new block") as u32; } + // 在 double indirect block 里尝试分配 if let Some(block_index) = self.alloc_in_triple_indirect(inode.triple_indirect) { - // TODO 标记 inode 所在 block 为脏 inode.n_blocks += 1; return Some(block_index); } - - /// 到这里说明真没空间了 None } fn allocate_in_indirect(&mut self, indirect_entry: u32) -> Option<u32> { // 取出 single indirect block, 尝试在里面分配 - let indirect = self.fetch_block::<IndirectBlock>(*indirect_entry); - for entry in indirect.entries.iter_mut() { - // 如果这个位置没被分配, 分配一个 index 塞进去 - if self.data_bitmap.query(*entry as usize) == false { - let block_index = self.data_bitmap.allocate() as u32; - *entry = block_index; - // TODO 标记 single indirect 为脏 - return Some(block_index); + let indirect_entry = indirect_entry as usize; + + if let Some(block) = self + .get_block(indirect_entry) + .map(convert::<DataBlock, IndirectBlock>) + { + let mut indirect_block = block.clone(); + for entry in indirect_block.block.entries.iter_mut() { + if self.data_bitmap.query(*entry as usize) == false { + indirect_block.dirty = true; // 把这个块标记为 dirty + let block_index = self.data_bitmap.allocate().expect("No free space") as u32; + *entry = block_index; + self.update_block(indirect_block); + return Some(block_index); + } } } None } fn alloc_in_double_indirect(&mut self, double_indirect_entry: u32) -> Option<u32> { - let double_indirect = self.fetch_block::<DoubleIndirectBlock>(double_indirect_entry); - for indirect_entry in double_indirect.indirect.iter_mut() { - if self.data_bitmap.query(*indirect_entry as usize) == false { - // TODO 标记 double indirect 为脏 - *indirect_entry = self.data_bitmap.allocate() as u32; - } - if let Some(block_index) = self.allocate_in_indirect(*indirect_entry) { - return Some(block_index); + let double_indirect_entry = double_indirect_entry as usize; + + if let Some(block) = self + .get_block(double_indirect_entry) + .map(convert::<DataBlock, DoubleIndirectBlock>) + { + let mut double_indirect_block = block.clone(); + for indirect_entry in double_indirect_block.block.indirect.iter_mut() { + if self.data_bitmap.query(*indirect_entry as usize) == false { + double_indirect_block.dirty = true; + *indirect_entry = self.data_bitmap.allocate().expect("No free space") as u32; + } + + if let Some(block_index) = self.allocate_in_indirect(*indirect_entry) { + if double_indirect_block.dirty { + self.update_block(double_indirect_block); + } + return Some(block_index); + } } } None } fn alloc_in_triple_indirect(&mut self, triple_indirect_entry: u32) -> Option<u32> { - let triple_indirect = self.fetch_block::<TripleIndirectBlock>(triple_indirect_entry); - for double_indirect_entry in triple_indirect.double_indirect.iter_mut() { - if self.data_bitmap.query(*double_indirect_entry as usize) == false { - // TODO 标记 triple indirect 为脏 - *double_indirect_entry = self.data_bitmap.allocate() as u32; - } - if let Some(block_index) = self.alloc_in_double_indirect(*double_indirect_entry) { - return Some(block_index); + let triple_indirect_entry = triple_indirect_entry as usize; + + if let Some(block) = self + .get_block(triple_indirect_entry) + .map(convert::<DataBlock, TripleIndirectBlock>) + { + let mut triple_indirect_block = block.clone(); + for double_indirect_entry in triple_indirect_block.block.double_indirect.iter_mut() { + if self.data_bitmap.query(*double_indirect_entry as usize) == false { + triple_indirect_block.dirty = true; + *double_indirect_entry = + self.data_bitmap.allocate().expect("No free space") as u32; + } + if let Some(block_index) = self.alloc_in_double_indirect(*double_indirect_entry) { + if triple_indirect_block.dirty { + self.update_block(triple_indirect_block); + } + return Some(block_index); + } } } None } - - // TODO: 实现一个 LRU 的 cache 机制, 不要每次都开 buffer - fn fetch_block<T: Block>(&self, block_index: u32) -> T { - let mut buffer = vec![0u8; BLOCK_SIZE]; - self.device - .read(block_index as usize, buffer.as_mut_slice()); - - let block = T::default(); - let block_slice = - unsafe { std::slice::from_raw_parts_mut(&block as *const T as *mut u8, BLOCK_SIZE) }; - block_slice.copy_from_slice(&buffer[..]); - block - } - - // TODO: 实现一个 LRU 的 cache 机制, 不要每次都开 buffer - fn fetch_inode(&self, block: usize, offset: usize) -> Inode { - let mut buffer = vec![0u8; BLOCK_SIZE]; - self.device.read(block, buffer.as_mut_slice()); - - let inode = Inode::empty(); - let inode_slice = unsafe { - std::slice::from_raw_parts_mut(&inode as *const Inode as *mut u8, INODE_SIZE) - }; - inode_slice.copy_from_slice(&buffer[offset..offset + INODE_SIZE]); - inode - } } impl Filesystem for MyFS { @@ -384,50 +493,22 @@ impl Filesystem for MyFS { debug!("Filesystem::destroy()"); } - fn access(&mut self, _req: &Request<'_>, ino: u64, mask: i32, reply: ReplyEmpty) { - debug!("Filesystem::getattr(ino: {}, mask: {})", ino, mask); - if let Some(inode) = self.get_inode(ino as usize) { - reply.ok() - } else { - reply.error(ENOENT) - } - } - - fn mkdir( - &mut self, - _req: &Request<'_>, - parent: u64, - name: &OsStr, - mode: u32, - umask: u32, - reply: ReplyEntry, - ) { + fn lookup(&mut self, _req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEntry) { debug!( - "Filesystem::mkdir(parent: {}, name: {:?}, mode: {}, umask: {})", - parent, name, mode, umask + "Filesystem::lookup called with parent {} name {}", + parent, + name.to_str().unwrap() ); - if let Some(inode) = self.get_inode(parent as usize) { - } else { - reply.error(ENOENT); + let parent = parent as usize; + if let Some(inode) = self.get_inode_2(parent) { + // debug!("{:?}", inode); } - // reply.error(ENOSPC); - } - - fn mknod( - &mut self, - _req: &Request<'_>, - parent: u64, - name: &OsStr, - mode: u32, - umask: u32, - rdev: u32, - reply: ReplyEntry, - ) { - debug!( - "Filesystem::mknod(parent: {}, name: {:?}, mode: {}, umask: {}, rdev: {})", - parent, name, mode, umask, rdev - ); - reply.error(ENOSPC); + // if self.inode_active(parent) { + // let (block, offset) = self.locate_inode(parent); + // let inode = self.get_inode_2(block, offset); + // debug!("{:?}", inode); + // } + reply.error(ENOENT); } fn forget(&mut self, _req: &Request<'_>, _ino: u64, _nlookup: u64) { @@ -438,7 +519,7 @@ impl Filesystem for MyFS { fn getattr(&mut self, _req: &Request<'_>, ino: u64, reply: ReplyAttr) { debug!("Filesystem::getattr(ino: {})", ino); let ino = ino as usize; - if let Some(inode) = self.get_inode(ino) { + if let Some(inode) = self.get_inode_2(ino) { // debug!("{:?}", inode); } reply.error(ENOENT); @@ -475,60 +556,41 @@ impl Filesystem for MyFS { reply.error(ENOSYS); } - fn lseek( + fn mknod( &mut self, _req: &Request<'_>, - ino: u64, - fh: u64, - offset: i64, - whence: i32, - reply: ReplyLseek, + parent: u64, + name: &OsStr, + mode: u32, + umask: u32, + rdev: u32, + reply: ReplyEntry, ) { debug!( - "lseek(ino: {:#x?}, fh: {}, offset: {}, whence: {})", - ino, fh, offset, whence + "Filesystem::mknod(parent: {}, name: {:?}, mode: {}, umask: {}, rdev: {})", + parent, name, mode, umask, rdev ); - reply.error(ENOSYS); + reply.error(ENOSPC); } - fn copy_file_range( + fn mkdir( &mut self, _req: &Request<'_>, - ino_in: u64, - fh_in: u64, - offset_in: i64, - ino_out: u64, - fh_out: u64, - offset_out: i64, - len: u64, - flags: u32, - reply: ReplyWrite, + parent: u64, + name: &OsStr, + mode: u32, + umask: u32, + reply: ReplyEntry, ) { debug!( - "copy_file_range(ino_in: {:#x?}, fh_in: {}, \ - offset_in: {}, ino_out: {:#x?}, fh_out: {}, offset_out: {}, \ - len: {}, flags: {})", - ino_in, fh_in, offset_in, ino_out, fh_out, offset_out, len, flags - ); - reply.error(ENOSYS); - } - - fn lookup(&mut self, _req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEntry) { - debug!( - "Filesystem::lookup called with parent {} name {}", - parent, - name.to_str().unwrap() + "Filesystem::mkdir(parent: {}, name: {:?}, mode: {}, umask: {})", + parent, name, mode, umask ); - let parent = parent as usize; - if let Some(inode) = self.get_inode(parent) { - // debug!("{:?}", inode); + if let Some(inode) = self.get_inode_2(parent as usize) { + } else { + reply.error(ENOENT); } - // if self.inode_active(parent) { - // let (block, offset) = self.locate_inode(parent); - // let inode = self.get_inode(block, offset); - // debug!("{:?}", inode); - // } - reply.error(ENOENT); + // reply.error(ENOSPC); } fn read( @@ -555,6 +617,53 @@ impl Filesystem for MyFS { ) { todo!() } + + fn access(&mut self, _req: &Request<'_>, ino: u64, mask: i32, reply: ReplyEmpty) { + debug!("Filesystem::getattr(ino: {}, mask: {})", ino, mask); + if let Some(inode) = self.get_inode_2(ino as usize) { + reply.ok() + } else { + reply.error(ENOENT) + } + } + + fn lseek( + &mut self, + _req: &Request<'_>, + ino: u64, + fh: u64, + offset: i64, + whence: i32, + reply: ReplyLseek, + ) { + debug!( + "lseek(ino: {:#x?}, fh: {}, offset: {}, whence: {})", + ino, fh, offset, whence + ); + reply.error(ENOSYS); + } + + fn copy_file_range( + &mut self, + _req: &Request<'_>, + ino_in: u64, + fh_in: u64, + offset_in: i64, + ino_out: u64, + fh_out: u64, + offset_out: i64, + len: u64, + flags: u32, + reply: ReplyWrite, + ) { + debug!( + "copy_file_range(ino_in: {:#x?}, fh_in: {}, \ + offset_in: {}, ino_out: {:#x?}, fh_out: {}, offset_out: {}, \ + len: {}, flags: {})", + ino_in, fh_in, offset_in, ino_out, fh_out, offset_out, len, flags + ); + reply.error(ENOSYS); + } } fn main() { |