diff options
Diffstat (limited to 'src/memory')
-rw-r--r-- | src/memory/cached_inode.rs | 92 | ||||
-rw-r--r-- | src/memory/dir_entry.rs | 304 | ||||
-rw-r--r-- | src/memory/file_handle.rs | 19 | ||||
-rw-r--r-- | src/memory/mod.rs | 1 |
4 files changed, 307 insertions, 109 deletions
diff --git a/src/memory/cached_inode.rs b/src/memory/cached_inode.rs index aa4f5e3..a9c92f5 100644 --- a/src/memory/cached_inode.rs +++ b/src/memory/cached_inode.rs @@ -2,7 +2,7 @@ use crate::disk::block::{DirectoryBlock, DirectoryEntry, InodeBlock}; use crate::disk::inode::{Inode, INODE_SIZE}; use crate::{utils, AyaFS}; use and_then_some::BoolExt; -use libc::{c_int, EISDIR, ENOENT, ENOTDIR}; +use libc::{c_int, EISDIR, ENOENT, ENOTDIR, ENOTEMPTY}; impl AyaFS { pub(crate) fn create_file( @@ -27,41 +27,53 @@ impl AyaFS { uid: u32, gid: u32, flags: u32, - parent_inode_number: Option<u32>, + parent_inode_number: Option<usize>, ) -> 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::<DirectoryBlock>(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; + self.init_direntry_map(inode_index); + self.add_direntry(inode_index, &mut new_inode, inode_index, ".", 0x2) + .unwrap(); + self.add_direntry( + inode_index, + &mut new_inode, + parent_inode_number.unwrap_or(inode_index), + "..", + 0x2, + ) + .unwrap(); - // add dot dot entry - directory_block.block.entries[1] = DirectoryEntry { - inode: parent_inode_number.unwrap_or(inode_index as u32), - 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; - } + // // 分配第一个 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::<DirectoryBlock>(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: parent_inode_number.unwrap_or(inode_index as u32), + // 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; @@ -70,10 +82,9 @@ impl AyaFS { (inode_index, self.get_inode(inode_index).unwrap()) }) } - + pub(crate) fn remove_file(&mut self, inode_index: usize) -> Result<bool, c_int> { if self.inode_bitmap.query(inode_index) { - self.inode_bitmap.deallocate(inode_index); let (block_index, offset) = self.locate_inode(inode_index); if let Some(cached_block) = self.cached_inodes.get_block::<InodeBlock>(block_index) { let inode = cached_block.block.inodes[offset / INODE_SIZE].clone(); @@ -82,23 +93,32 @@ impl AyaFS { } self.deallocate_all_blocks_for(&inode).unwrap(); } + self.inode_bitmap.deallocate(inode_index); Ok(true) } else { Err(ENOENT) } } - + + // 要删除的 inode 一定得是空的 pub(crate) fn remove_dir(&mut self, inode_index: usize) -> Result<bool, c_int> { if self.inode_bitmap.query(inode_index) { - self.inode_bitmap.deallocate(inode_index); let (block_index, offset) = self.locate_inode(inode_index); if let Some(cached_block) = self.cached_inodes.get_block::<InodeBlock>(block_index) { - let inode = cached_block.block.inodes[offset / INODE_SIZE].clone(); + let inode = &cached_block.block.inodes[offset / INODE_SIZE].clone(); if !inode.is_dir() { + // 不是 dir -> ENOTDIR return Err(ENOTDIR); } - // TODO 递归删除所有下面的 direntry 里的 inode, 注意排除 . 和 .. + if inode.size > 2 { + // 有 . 和 .. 以外的 entry -> ENOTEMPTY + return Err(ENOTEMPTY); + } + // 销毁 inode 里的所有 block + self.deallocate_all_blocks_for(inode).unwrap(); } + // 销毁 inode + self.inode_bitmap.deallocate(inode_index); Ok(true) } else { Err(ENOENT) 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<OsString, DirectoryEntry> = 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<OsString, DirectoryEntry> = 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::<DirectoryBlock>(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<OsString, DirectoryEntry>, + ) -> 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::<DirectoryBlock>(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::<DirectoryBlock>(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::<DirectoryBlock>(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<T: AsRef<OsStr>>( &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<u32, c_int> { - // 找到第一个有空闲 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::<DirectoryBlock>(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::<DirectoryBlock>(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<DirectoryEntry> { - let block_index_within_inode = (entry_index / 15) as usize; - let entry_index_within_block = (entry_index % 15) as usize; - - self.access_block::<DirectoryBlock>(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<DirectoryEntry, c_int> { + 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::<DirectoryBlock>(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) } } diff --git a/src/memory/file_handle.rs b/src/memory/file_handle.rs new file mode 100644 index 0000000..0da2ed2 --- /dev/null +++ b/src/memory/file_handle.rs @@ -0,0 +1,19 @@ +use crate::AyaFS; +use std::sync::atomic::Ordering; + +impl AyaFS { + pub(crate) fn allocate_file_descriptor( + &mut self, + inode_index: usize, + read: bool, + write: bool, + ) -> u64 { + let fd = self.next_file_handle.fetch_add(1, Ordering::SeqCst); + self.file_handle_map.insert(fd, (inode_index, read, write)); + fd + } + + pub(crate) fn get_inode_from_fd(&self, file_descriptor: u64) -> Option<(usize, bool, bool)> { + self.file_handle_map.get(&file_descriptor).copied() + } +} diff --git a/src/memory/mod.rs b/src/memory/mod.rs index 4080114..d1f1ab8 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -3,3 +3,4 @@ pub mod cached_block; pub mod cached_inode; mod dir_entry; +mod file_handle; |