From 76ac602c3d79bb39c133c81a38425a77bc0b8b1f Mon Sep 17 00:00:00 2001 From: Chuyan Zhang Date: Sat, 25 Nov 2023 02:13:22 -0800 Subject: Some FUSE callbacks, some POSIX interface implementation --- src/memory/cached_block.rs | 85 ++--------------- src/memory/cached_inode.rs | 71 +++++++++++++- src/memory/inode_iter.rs | 233 +++++++++++++++++++++++++++++++++++++++++++++ src/memory/mod.rs | 1 + 4 files changed, 310 insertions(+), 80 deletions(-) create mode 100644 src/memory/inode_iter.rs (limited to 'src/memory') diff --git a/src/memory/cached_block.rs b/src/memory/cached_block.rs index eb59a4b..77cdf61 100644 --- a/src/memory/cached_block.rs +++ b/src/memory/cached_block.rs @@ -1,5 +1,6 @@ use crate::block_device::{BlockDevice, BLOCK_SIZE}; use crate::disk::block::Block; +use crate::disk::inode::Inode; use crate::AyaFS; use and_then_some::BoolExt; use log::debug; @@ -70,17 +71,18 @@ impl BlockCache { /// 从 LRU cache 里获取一个 block 的引用, 如果没有在 cache 中会加载. pub(crate) fn get_block(&mut self, index: usize) -> Option<&CachedBlock> { - self.load_block(index) - .and_then(|| self.cache.get(&index).map(convert::)) + if !self.cache.contains(&index) { + self.load_block(index); + } + self.cache.get(&index).map(convert::) } /// 从 LRU cache 里获取一个 block 的可变引用, 如果没有在 cache 中会加载. pub(crate) fn get_block_mut(&mut self, index: usize) -> Option<&mut CachedBlock> { - debug!("Blockcache get block mut"); - self.load_block(index).and_then(|| { - debug!("block loaded"); - self.cache.get_mut(&index).map(convert_mut::) - }) + if !self.cache.contains(&index) { + self.load_block(index); + } + self.cache.get_mut(&index).map(convert_mut::) } /// 从 LRU cache 中读取一个 block 的引用, *不会* 影响 LRU cache 的结构, 如果没有在 cache 中不会加载. @@ -145,73 +147,4 @@ impl AyaFS { pub(crate) fn update_block(&mut self, block: CachedBlock) -> bool { self.cached_blocks.update_block(block) } - - // pub(crate) fn update_block(&mut self, block: CachedBlock) -> bool { - // if self.cached_blocks.contains(&block.index) { - // let data_block = convert::(&block).clone(); - // self.cached_blocks.push(block.index, data_block); - // true - // } else { - // false - // } - // } - // - // /// 从 LRU cache 里获取一个 block 的引用, 如果没有在 cache 中会加载. - // pub(crate) fn get_block(&mut self, index: usize) -> Option<&CachedBlock> { - // self.load_block(index) - // .and_then(|| self.cached_blocks.get(&index).map(convert::)) - // } - // - // /// 从 LRU cache 里获取一个 block 的可变引用, 如果没有在 cache 中会加载. - // pub(crate) fn get_block_mut(&mut self, index: usize) -> Option<&mut CachedBlock> { - // self.load_block(index).and_then(|| { - // self.cached_blocks - // .get_mut(&index) - // .map(convert_mut::) - // }) - // } - // - // /// 从 LRU cache 中读取一个 block 的引用, *不会* 影响 LRU cache 的结构, 如果没有在 cache 中不会加载. - // pub(crate) fn peek_block(&self, index: usize) -> Option<&CachedBlock> { - // self.cached_blocks.peek(&index).map(convert::) - // } - // - // /// 从 LRU cache 中读取一个 block 的可变引用, *不会* 影响 LRU cache 的结构, 如果没有在 cache 中不会加载. - // pub(crate) fn peek_block_mut(&mut self, index: usize) -> Option<&mut CachedBlock> { - // self.cached_blocks.peek_mut(&index).map(convert_mut::) - // } - // - // pub(crate) fn load_block(&mut self, index: usize) -> bool { - // // 先看这个 block 是不是 valid, 不 valid 直接返回 false. - // if !self.data_bitmap.query(index) { - // self.cached_blocks.pop(&index); - // // deallocate 时只更新 bitmap 没有动 cache, lazy 地驱逐 cache 中的无效 entry. - // return false; - // } - // - // // 接下来这个 block 一定 valid. 如果 cache 里没有这个 block 就把它 load 到 cache 里 - // if self.cached_blocks.contains(&index) == false { - // 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); - // } - // } - // } - // - // true - // } } diff --git a/src/memory/cached_inode.rs b/src/memory/cached_inode.rs index dd5e5c3..be87850 100644 --- a/src/memory/cached_inode.rs +++ b/src/memory/cached_inode.rs @@ -1,10 +1,76 @@ -use crate::disk::block::InodeBlock; +use crate::disk::block::{DirectoryBlock, DirectoryEntry, InodeBlock}; use crate::disk::inode::{Inode, InodeMode, INODE_SIZE}; +use crate::utils::from_filetype; use crate::{utils, AyaFS}; use and_then_some::BoolExt; +use fuser::FileType; use log::debug; impl AyaFS { + pub(crate) fn create_file( + &mut self, + permissions: u16, + uid: u32, + gid: u32, + flags: u32, + ) -> Option<(usize, &Inode)> { + self.inode_bitmap.allocate().map(|inode_index| { + self.get_inode_mut(inode_index).map(|inode| { + *inode = Inode::file(permissions, uid, gid, utils::time_now(), flags, 0, 0, 0); + }); + (inode_index, self.get_inode(inode_index).unwrap()) + }) + } + + pub(crate) fn create_directory( + &mut self, + permissions: u16, + uid: u32, + gid: u32, + flags: u32, + ) -> Option<(usize, &Inode)> { + self.inode_bitmap.allocate().map(|inode_index| { + // 创建 Inode + let mut new_inode = + Inode::directory(permissions, uid, gid, utils::time_now(), flags, 0, 0, 0); + // 分配第一个 direct block + new_inode.direct[0] = self.allocate_block_for(&mut new_inode).unwrap(); + new_inode.size = 2; + // 在 direct block 里分配 . 和 .. + if let Some(directory_block) = + self.get_block_mut::(new_inode.direct[0] as usize) + { + let dot = '.'.to_ascii_lowercase() as u8; + // add dot entry + directory_block.block.entries[0] = DirectoryEntry { + inode: inode_index as u32, + record_len: 264, + name_len: 1, + file_type: 0x2, + name: [0; 256], + }; + directory_block.block.entries[0].name[0] = dot; + + // add dot dot entry + directory_block.block.entries[1] = DirectoryEntry { + inode: 0, // TODO set this as parent inode number + record_len: 264, + name_len: 2, + file_type: 0x2, + name: [0; 256], + }; + directory_block.block.entries[1].name[0] = dot; + directory_block.block.entries[1].name[1] = dot; + } + // 把 inode 放到指定位置 + self.get_inode_mut(inode_index).map(|inode| { + *inode = new_inode; + }); + + (inode_index, self.get_inode(inode_index).unwrap()) + }) + } + pub(crate) fn create_inode( &mut self, permissions: u16, @@ -13,9 +79,7 @@ impl AyaFS { gid: u32, flags: u32, ) -> Option { - debug!("create inode"); self.inode_bitmap.allocate().map(|inode_index| { - debug!("creating inode"); self.get_inode_mut(inode_index).map(|inode| { *inode = Inode::make_inode( permissions, @@ -29,7 +93,6 @@ impl AyaFS { 0, ); }); - debug!("inode created"); inode_index }) } diff --git a/src/memory/inode_iter.rs b/src/memory/inode_iter.rs new file mode 100644 index 0000000..d5909bc --- /dev/null +++ b/src/memory/inode_iter.rs @@ -0,0 +1,233 @@ +use std::ffi::OsStr; +use std::os::unix::ffi::OsStrExt; +use libc::{c_int, ENOENT, ENOSPC}; +use crate::disk::block::{Block, DirectoryBlock, DirectoryEntry, DoubleIndirectBlock, IndirectBlock, TripleIndirectBlock}; +use crate::disk::inode::{Inode, DIRECT_NUMBER}; +use crate::{AyaFS, INODE_PER_BLOCK}; +use crate::memory::cached_block::CachedBlock; + +impl AyaFS { + pub(crate) fn access_block(&mut self, inode: &Inode, mut block_index_within_inode: usize) -> Option<&CachedBlock> { + // direct block + if block_index_within_inode < DIRECT_NUMBER { + let block_index = inode.direct[block_index_within_inode] as usize; + return self.get_block::(block_index); + } else { + block_index_within_inode -= DIRECT_NUMBER; + } + + // indirect block + let indirect_number = INODE_PER_BLOCK; + if block_index_within_inode < indirect_number { + return if let Some(indirect_block) = + self.get_block::(inode.single_indirect as usize) + { + let block_index = indirect_block.block.entries[block_index_within_inode] as usize; + self.get_block::(block_index) + } else { + None + }; + } else { + block_index_within_inode -= indirect_number; + } + + // double indirect block + let double_indirect_number = INODE_PER_BLOCK * INODE_PER_BLOCK; + if block_index_within_inode < double_indirect_number { + if let Some(double_indirect_block) = + self.get_block::(inode.double_indirect as usize) + { + // 取出 double indirect block + let indirect_block_index = double_indirect_block.block.indirect + [block_index_within_inode / INODE_PER_BLOCK] + as usize; + // 要找的 entry 在 double indirect block 中的第几个 indirect block + if let Some(indirect_block) = self.get_block::(indirect_block_index) + { + let block_index = indirect_block.block.entries + [block_index_within_inode % INODE_PER_BLOCK] + as usize; + // 拿到 DirectoryBlock 的 index + return self.get_block::(block_index); + } + } + return None; + } else { + block_index_within_inode -= double_indirect_number; + } + + // triple indirect block + if let Some(triple_indirect_block) = + self.get_block::(inode.triple_indirect as usize) + { + // 取出 triple indirect block + let double_indirect_block_index = triple_indirect_block.block.double_indirect + [block_index_within_inode / (INODE_PER_BLOCK * INODE_PER_BLOCK)] + as usize; + // 要找的 entry 在 triple indirect block 中的第几个 double indirect block + if let Some(double_indirect_block) = + self.get_block::(double_indirect_block_index) + { + // 取出 double indirect block + let indirect_block_index = double_indirect_block.block.indirect + [block_index_within_inode % (INODE_PER_BLOCK * INODE_PER_BLOCK) + / INODE_PER_BLOCK] as usize; + // 要找的 entry 在 double indirect block 中的第几个 indirect block + if let Some(indirect_block) = self.get_block::(indirect_block_index) + { + let block_index = indirect_block.block.entries + [block_index_within_inode % INODE_PER_BLOCK] + as usize; + // DirectoryBlock 的 index + return self.get_block::(block_index); + } + } + } + + None + } + + pub(crate) fn add_direntry( + &mut self, + parent_inode: &mut Inode, + child_inode_index: u32, + child_inode_name: &OsStr, + child_inode: &Inode, + ) -> Result { + let entry_index = parent_inode.size; + let block_index_within_inode = (entry_index / 15) as usize; + let entry_index_within_block = (entry_index % 15) as usize; + + // TODO 如果 block 内 offset 是 0 (或者访问到 block_index_within_inode 无效?)则为 Inode 分配新的 block + + // TODO 把新的 entry 写到对应位置 + + Err(ENOSPC) + } + pub(crate) fn get_direntry( + &mut self, + inode: &Inode, + entry_index: u32 + ) -> Option { + let block_index_within_inode = (entry_index / 15) as usize; + let entry_index_within_block = (entry_index % 15) as usize; + + self.access_block::(inode, block_index_within_inode) + .map(|directory_block| { + directory_block.block.entries[entry_index_within_block].clone() + }) + } + + // pub(crate) fn get_direntry( + // &mut self, + // inode: &Inode, + // entry_index: u32, + // ) -> Option { + // // 每个 DirectoryBlock 里有 15 个 entry, 先确定 block 再确定 offset + // let mut block_index_within_inode = (entry_index / 15) as usize; + // let entry_index_within_block = (entry_index % 15) as usize; + // + // // direct block + // if block_index_within_inode < DIRECT_NUMBER { + // let block_index = inode.direct[block_index_within_inode] as usize; + // return self + // .get_block::(block_index) + // .map(|inode_block| inode_block.block.entries[entry_index_within_block].clone()); + // } else { + // block_index_within_inode -= DIRECT_NUMBER; + // } + // + // // indirect block + // let indirect_number = INODE_PER_BLOCK; + // if block_index_within_inode < indirect_number { + // return if let Some(indirect_block) = + // self.get_block::(inode.single_indirect as usize) + // { + // let block_index = indirect_block.block.entries[block_index_within_inode] as usize; + // self.get_block::(block_index) + // .map(|inode_block| inode_block.block.entries[entry_index_within_block].clone()) + // } else { + // None + // }; + // } else { + // block_index_within_inode -= indirect_number; + // } + // + // // double indirect block + // let double_indirect_number = INODE_PER_BLOCK * INODE_PER_BLOCK; + // if block_index_within_inode < double_indirect_number { + // if let Some(double_indirect_block) = + // self.get_block::(inode.double_indirect as usize) + // { + // // 取出 double indirect block + // let indirect_block_index = double_indirect_block.block.indirect + // [block_index_within_inode / INODE_PER_BLOCK] + // as usize; + // // 要找的 entry 在 double indirect block 中的第几个 indirect block + // if let Some(indirect_block) = self.get_block::(indirect_block_index) + // { + // let block_index = indirect_block.block.entries + // [block_index_within_inode % INODE_PER_BLOCK] + // as usize; + // // 拿到 DirectoryBlock 的 index + // return self + // .get_block::(block_index) + // .map(|inode_block| { + // inode_block.block.entries[entry_index_within_block].clone() + // }); + // } + // } + // return None; + // } else { + // block_index_within_inode -= double_indirect_number; + // } + // + // // triple indirect block + // if let Some(triple_indirect_block) = + // self.get_block::(inode.triple_indirect as usize) + // { + // // 取出 triple indirect block + // let double_indirect_block_index = triple_indirect_block.block.double_indirect + // [block_index_within_inode / (INODE_PER_BLOCK * INODE_PER_BLOCK)] + // as usize; + // // 要找的 entry 在 triple indirect block 中的第几个 double indirect block + // if let Some(double_indirect_block) = + // self.get_block::(double_indirect_block_index) + // { + // // 取出 double indirect block + // let indirect_block_index = double_indirect_block.block.indirect + // [block_index_within_inode % (INODE_PER_BLOCK * INODE_PER_BLOCK) + // / INODE_PER_BLOCK] as usize; + // // 要找的 entry 在 double indirect block 中的第几个 indirect block + // if let Some(indirect_block) = self.get_block::(indirect_block_index) + // { + // let block_index = indirect_block.block.entries + // [block_index_within_inode % INODE_PER_BLOCK] + // as usize; + // // DirectoryBlock 的 index + // return self + // .get_block::(block_index) + // .map(|inode_block| { + // inode_block.block.entries[entry_index_within_block].clone() + // }); + // } + // } + // } + // None + // } + + // TODO 实现一个带 cache 的版本 + pub fn lookup_name(&mut self, parent_inode: &Inode, name: &OsStr) -> Result<(u32, Inode), c_int> { + let mut entry_index = 0; + while entry_index < parent_inode.size { + if let Some(entry) = self.get_direntry(parent_inode, entry_index) { + if entry.name() == name { + let inode = self.get_inode(entry.inode as usize).unwrap().clone(); + return Ok((entry.inode, inode)) + } + } + entry_index += 1; + } + Err(ENOENT) + } +} diff --git a/src/memory/mod.rs b/src/memory/mod.rs index 3380d0f..dce7c42 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -2,3 +2,4 @@ /// This is where the crucial block and inode methods presented to upper calls implemented. pub mod cached_block; pub mod cached_inode; +mod inode_iter; -- cgit v1.2.3-70-g09d2