From ec2f349a648e4d87fba12d20e338b1cd6d8ef29a Mon Sep 17 00:00:00 2001 From: Chuyan Zhang Date: Mon, 27 Nov 2023 00:11:55 -0800 Subject: Fix directory stuff --- src/memory/dir_entry.rs | 304 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 231 insertions(+), 73 deletions(-) (limited to 'src/memory/dir_entry.rs') diff --git a/src/memory/dir_entry.rs b/src/memory/dir_entry.rs index 2d961db..08a82c5 100644 --- a/src/memory/dir_entry.rs +++ b/src/memory/dir_entry.rs @@ -1,117 +1,275 @@ use crate::disk::block::{DirectoryBlock, DirectoryEntry}; use crate::disk::inode::Inode; use crate::AyaFS; +use indexmap::IndexMap; use libc::{c_int, ENOENT, ENOSPC}; -use std::ffi::OsStr; +use log::debug; +use std::ffi::{OsStr, OsString}; use std::os::unix::ffi::OsStrExt; impl AyaFS { - /// 删除所有的 dir entry, 递归 - pub(crate) fn clear_direntry(&mut self, parent_inode: &mut Inode) -> Result<(), c_int> { - todo!() + pub(crate) fn init_direntry_map(&mut self, index: usize) { + let direntry_map: IndexMap = IndexMap::new(); + if let Some((old_inode_index, old_dir_entry_map)) = + self.dir_entry_map.push(index, direntry_map) + { + if let Some(old_inode) = self.get_inode(old_inode_index) { + let mut old_inode = old_inode.clone(); + self.write_back_direntry(old_inode_index, &mut old_inode, old_dir_entry_map) + .unwrap(); + self.update_inode(old_inode_index, old_inode); + } + } + } + + pub(crate) fn load_direntry_map(&mut self, index: usize, inode: &Inode) -> Result<(), c_int> { + if self.dir_entry_map.contains(&index) { + debug!("load_direntry_map(ino: {}) already in cache", index); + return Ok(()); + } + + debug!("load_direntry_map(ino: {}) loading", index); + let mut dir_entry_map: IndexMap = IndexMap::new(); + let mut entry_index: usize = 0; + loop { + let block_index_within_inode = entry_index / 15; + let entry_index_within_block = entry_index % 15; + + match self.access_block::(inode, block_index_within_inode) { + Some(directory_block) => { + if directory_block.block.query(entry_index_within_block) { + let dir_entry = &directory_block.block.entries[entry_index_within_block]; + let name = dir_entry.name(); + dir_entry_map.insert(name, dir_entry.clone()); + } else { + break; + } + } + None => break, + } + entry_index += 1; + } + + if let Some((old_inode_index, old_dir_entry_map)) = + self.dir_entry_map.push(index, dir_entry_map) + { + if let Some(old_inode) = self.get_inode(old_inode_index) { + let mut old_inode = old_inode.clone(); + self.write_back_direntry(old_inode_index, &mut old_inode, old_dir_entry_map)?; + self.update_inode(old_inode_index, old_inode); + } + } + + Ok(()) + } + + pub(crate) fn write_back_direntry( + &mut self, + _parent_index: usize, + parent_inode: &mut Inode, + dir_entry_map: IndexMap, + ) -> Result<(), c_int> { + for (entry_index, (_, dir_entry)) in dir_entry_map.into_iter().enumerate() { + let block_index_within_inode = entry_index / 15; + let entry_index_within_block = entry_index % 15; + // 不够就新分配 + if self + .get_block_index(parent_inode, block_index_within_inode) + .is_none() + { + match self.allocate_block_for(parent_inode) { + Some((_, block_index_within)) => { + assert_eq!(block_index_within, block_index_within_inode); + } + None => { + return Err(ENOSPC); + } + } + } + match self.access_block_mut::(parent_inode, block_index_within_inode) { + Some(directory_block) => { + directory_block.block.entries[entry_index_within_block] = dir_entry; + } + None => { + return Err(ENOENT); + } + } + } + Ok(()) } /// 删除第 entry_index 个 dir entry pub(crate) fn remove_direntry( &mut self, + parent_index: usize, parent_inode: &mut Inode, + name: &OsStr, entry_index: u32, ) -> Result<(), c_int> { - let block_index_within_inode = (entry_index / 15) as usize; - let entry_index_within_block = (entry_index % 15) as usize; - - match self.access_block_mut::(parent_inode, block_index_within_inode) { - Some(directory_block) => { - if directory_block.block.query(entry_index_within_block) { - directory_block.block.deallocate(entry_index_within_block); - directory_block.block.entries[entry_index_within_block] = - DirectoryEntry::default(); - Ok(()) - } else { - Err(ENOENT) - } + self.load_direntry_map(parent_index, parent_inode)?; + if let Some(dir_entry_map) = self.dir_entry_map.get_mut(&parent_index) { + debug!(" remove_direntry(ino: {}) using hashmap", parent_index); + if dir_entry_map.shift_remove(name).is_some() { + Ok(()) + } else { + Err(ENOENT) } - None => Err(ENOENT), + } else { + Err(ENOENT) + // let block_index_within_inode = (entry_index / 15) as usize; + // let entry_index_within_block = (entry_index % 15) as usize; + // + // match self.access_block_mut::(parent_inode, block_index_within_inode) { + // Some(directory_block) => { + // if directory_block.block.query(entry_index_within_block) { + // directory_block.block.deallocate(entry_index_within_block); + // // directory_block.block.entries[entry_index_within_block] = + // // DirectoryEntry::default(); + // Ok(()) + // } else { + // Err(ENOENT) + // } + // } + // None => Err(ENOENT), + // } } } - pub(crate) fn add_direntry( + pub(crate) fn add_direntry>( &mut self, + parent_index: usize, parent_inode: &mut Inode, child_inode_index: usize, - child_inode_name: &OsStr, - child_inode: &Inode, + child_inode_name: T, + file_type: u8, ) -> Result { - // 找到第一个有空闲 DirEntry 的块, 从中分配一个 entry - let mut block_index_within_inode: usize = 0; - loop { - // 所有已经分配的块都用完, 需要额外分配一个块了 - if block_index_within_inode as u32 == parent_inode.n_blocks { - if self.allocate_block_for(parent_inode).is_none() { - return Err(ENOSPC); - } - } - // 寻找当前块里有没有空闲空间 - if let Some(directory_block) = - self.access_block_mut::(parent_inode, block_index_within_inode) - { - if let Some(entry_index_within_block) = directory_block.block.allocate() { - // 如果有空闲空间, 可以分配一个块 - let name_len = child_inode_name.len() as u8; - let file_type = child_inode.mode.into(); - let mut name = [0u8; 256]; - name.copy_from_slice(child_inode_name.as_bytes()); + let child_inode_name = child_inode_name.as_ref(); + self.load_direntry_map(parent_index, parent_inode)?; + if let Some(dir_entry_map) = self.dir_entry_map.get_mut(&parent_index) { + let name_len = child_inode_name.len() as u8; + let mut name = [0u8; 256]; + (&mut name[0..child_inode_name.len()]).copy_from_slice(child_inode_name.as_bytes()); - let dir_entry = DirectoryEntry { - inode: child_inode_index as u32, - record_len: 264, - name_len, - file_type, - name, - }; - directory_block.block.entries[entry_index_within_block] = dir_entry; - let entry_index = block_index_within_inode * 15 + entry_index_within_block; - return Ok(entry_index as u32); - } - } - block_index_within_inode += 1; + let dir_entry = DirectoryEntry { + inode: child_inode_index as u32, + record_len: 264, + name_len, + file_type, + name, + }; + + let (entry_index, _) = + dir_entry_map.insert_full(child_inode_name.to_os_string(), dir_entry); + debug!( + " add_direntry(ino: {}) using hashmap, entry {}", + parent_index, entry_index + ); + parent_inode.size += 1; + Ok(entry_index as u32) + } else { + Err(ENOENT) } + // // 找到第一个有空闲 DirEntry 的块, 从中分配一个 entry + // let mut block_index_within_inode: usize = 0; + // loop { + // // 所有已经分配的块都用完, 需要额外分配一个块了 + // if block_index_within_inode as u32 == parent_inode.n_blocks { + // if self.allocate_block_for(parent_inode).is_none() { + // return Err(ENOSPC); + // } + // } + // // 寻找当前块里有没有空闲空间 + // if let Some(directory_block) = + // self.access_block_mut::(parent_inode, block_index_within_inode) + // { + // if let Some(entry_index_within_block) = directory_block.block.allocate() { + // // 如果有空闲空间, 可以分配一个块 + // let name_len = child_inode_name.len() as u8; + // let mut name = [0u8; 256]; + // (&mut name[0..name_len as usize]) + // .copy_from_slice(child_inode_name.as_bytes()); + // + // let dir_entry = DirectoryEntry { + // inode: child_inode_index as u32, + // record_len: 264, + // name_len, + // file_type, + // name, + // }; + // directory_block.block.entries[entry_index_within_block] = dir_entry; + // let entry_index = block_index_within_inode * 15 + entry_index_within_block; + // parent_inode.size += 1; + // return Ok(entry_index as u32); + // } + // } + // block_index_within_inode += 1; + // } } pub(crate) fn get_direntry( &mut self, + parent_index: usize, parent_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::(parent_inode, block_index_within_inode) - .and_then(|directory_block| { - if directory_block.block.query(entry_index_within_block) { - Some(directory_block.block.entries[entry_index_within_block].clone()) - } else { - None - } - }) + ) -> Result { + self.load_direntry_map(parent_index, parent_inode)?; + if let Some(dir_entry_map) = self.dir_entry_map.get(&parent_index) { + debug!( + " get_direntry(ino: {}, entry_index: {}) using hashmap", + parent_index, entry_index + ); + dir_entry_map + .iter() + .skip(entry_index as usize) + .next() + .map(|entry| entry.1.clone()) + .ok_or(ENOENT) + } else { + Err(ENOENT) + // let block_index_within_inode = (entry_index / 15) as usize; + // let entry_index_within_block = (entry_index % 15) as usize; + // + // match self.access_block::(parent_inode, block_index_within_inode) { + // Some(directory_block) => { + // if directory_block.block.query(entry_index_within_block) { + // Ok(directory_block.block.entries[entry_index_within_block].clone()) + // } else { + // Err(ENOENT) + // } + // } + // None => Err(ENOENT), + // } + } } // TODO 实现一个带 cache 的版本 /// 返回 inode_index, inode 在 parent 里的 index, inode 本身 pub fn lookup_name( &mut self, + parent_index: usize, parent_inode: &Inode, name: &OsStr, ) -> Result<(u32, 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, entry_index, inode)); + self.load_direntry_map(parent_index, parent_inode)?; + if let Some(dir_entry_map) = self.dir_entry_map.get(&parent_index) { + if let Some((entry_index, _, dir_entry)) = dir_entry_map.get_full(name) { + let inode_index = dir_entry.inode; + let inode = self.get_inode(inode_index as usize).unwrap().clone(); + Ok((inode_index, entry_index as u32, inode)) + } else { + Err(ENOENT) + } + } else { + let mut entry_index = 0; + while entry_index < parent_inode.size { + if let Ok(entry) = self.get_direntry(parent_index, parent_inode, entry_index) { + if entry.name() == name { + let inode = self.get_inode(entry.inode as usize).unwrap().clone(); + return Ok((entry.inode, entry_index, inode)); + } } + entry_index += 1; } - entry_index += 1; + Err(ENOENT) } - Err(ENOENT) } } -- cgit v1.2.3-70-g09d2