From 4c34414b26bf71e747ea3ecb2586645bab4aba52 Mon Sep 17 00:00:00 2001 From: Chuyan Zhang Date: Fri, 1 Dec 2023 19:42:13 -0800 Subject: Multiple bugfix, it works! --- ayafs-core/src/bin/main.rs | 9 +-- ayafs-core/src/bin/mem_run.rs | 43 +++++++++++ ayafs-core/src/block_device/disk.rs | 10 ++- ayafs-core/src/disk/allocation.rs | 14 +++- ayafs-core/src/disk/bitmap.rs | 40 ++++++++++- ayafs-core/src/disk/block.rs | 44 ++++++------ ayafs-core/src/disk/inode.rs | 17 +---- ayafs-core/src/filesystem/trait_impl.rs | 100 ++++++++++++++------------ ayafs-core/src/lib.rs | 124 ++++++++++++++++++++++++++++---- ayafs-core/src/memory/cached_block.rs | 79 +++++++++++++++----- ayafs-core/src/memory/cached_inode.rs | 8 ++- ayafs-core/src/memory/dir_entry.rs | 14 +++- ayafs-core/src/tests/common/mod.rs | 3 +- ayafs-core/src/tests/mod.rs | 1 - ayafs-core/src/utils/constants.rs | 1 - ayafs-core/src/utils/mod.rs | 15 +--- 16 files changed, 382 insertions(+), 140 deletions(-) create mode 100644 ayafs-core/src/bin/mem_run.rs delete mode 100644 ayafs-core/src/utils/constants.rs (limited to 'ayafs-core/src') diff --git a/ayafs-core/src/bin/main.rs b/ayafs-core/src/bin/main.rs index 25504b9..a2d838c 100644 --- a/ayafs-core/src/bin/main.rs +++ b/ayafs-core/src/bin/main.rs @@ -9,6 +9,7 @@ use aya::block_device::disk::Disk; #[derive(Parser, Debug)] #[command(author, version, about)] struct Args { + device_path: Option, mount_point: Option, #[arg(short, action = clap::ArgAction::Count)] verbosity: u8, @@ -20,6 +21,7 @@ struct Args { fn main() { let args = Args::parse(); + let device_path = args.device_path.unwrap(); let mount_point = args.mount_point.unwrap(); let verbosity = args.verbosity; let log_level = match verbosity { @@ -36,9 +38,8 @@ fn main() { MountOption::AutoUnmount, MountOption::AllowRoot, ]; - let disk = Arc::new(Disk::new(PathBuf::from("/dev/nvme0n1p4"))); - // let disk = Arc::new(MemoryDisk::new(16384)); - let filesystem = AyaFS::new(disk, 7864320); - + let disk = Arc::new(Disk::new(PathBuf::from(device_path))); + let filesystem = AyaFS::load(disk); + fuser::mount2(filesystem, mount_point, &options).unwrap(); } \ No newline at end of file diff --git a/ayafs-core/src/bin/mem_run.rs b/ayafs-core/src/bin/mem_run.rs new file mode 100644 index 0000000..7ba6f4e --- /dev/null +++ b/ayafs-core/src/bin/mem_run.rs @@ -0,0 +1,43 @@ +use std::sync::Arc; +use clap::Parser; +use fuser::MountOption; +use log::LevelFilter; +use users::{get_current_gid, get_current_uid}; +use aya::AyaFS; +use aya::block_device::memory_disk::MemoryDisk; + +#[derive(Parser, Debug)] +#[command(author, version, about)] +struct Args { + mount_point: Option, + #[arg(short, action = clap::ArgAction::Count)] + verbosity: u8, + #[arg(long)] + auto_unmount: bool, + #[arg(long)] + allow_root: bool, +} + +fn main() { + let args = Args::parse(); + let mount_point = args.mount_point.unwrap(); + let verbosity = args.verbosity; + let log_level = match verbosity { + 0 => LevelFilter::Error, + 1 => LevelFilter::Warn, + 2 => LevelFilter::Info, + 3 => LevelFilter::Debug, + _ => LevelFilter::Trace, + }; + env_logger::builder().filter_level(log_level).init(); + let options = vec![ + // MountOption::RO, + MountOption::FSName("hello".to_string()), + MountOption::AutoUnmount, + MountOption::AllowRoot, + ]; + let disk = Arc::new(MemoryDisk::new(16384)); + let filesystem = AyaFS::new(disk, 16384, get_current_uid(), get_current_gid()); + + fuser::mount2(filesystem, mount_point, &options).unwrap(); +} \ No newline at end of file diff --git a/ayafs-core/src/block_device/disk.rs b/ayafs-core/src/block_device/disk.rs index d2beee9..9e9b6bc 100644 --- a/ayafs-core/src/block_device/disk.rs +++ b/ayafs-core/src/block_device/disk.rs @@ -2,22 +2,22 @@ use crate::block_device::{BlockDevice, BLOCK_SIZE}; use std::cell::RefCell; use std::fs::File; use std::io::{Read, Seek, SeekFrom, Write}; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; +use log::debug; pub struct Disk { + #[allow(unused)] disk_path: PathBuf, device: RefCell, } impl Disk { pub fn new(disk_path: PathBuf) -> Self { - let device = File::options() .read(true) .write(true) .open(disk_path.as_path()) .unwrap(); - // let device = File::open(disk_path.as_path()).unwrap(); Self { disk_path, device: RefCell::new(device), @@ -27,6 +27,7 @@ impl Disk { impl BlockDevice for Disk { fn read(&self, block_id: usize, buffer: &mut [u8]) { + assert_eq!(buffer.len(), BLOCK_SIZE); let mut device = self.device.borrow_mut(); device .seek(SeekFrom::Start((block_id * BLOCK_SIZE) as u64)) @@ -34,9 +35,11 @@ impl BlockDevice for Disk { device .read_exact(buffer) .expect("Failed to read 4096 bytes!"); + debug!("disk::read block {}", block_id); } fn write(&self, block_id: usize, buffer: &[u8]) { + assert_eq!(buffer.len(), BLOCK_SIZE); let mut device = self.device.borrow_mut(); device .seek(SeekFrom::Start((block_id * BLOCK_SIZE) as u64)) @@ -44,5 +47,6 @@ impl BlockDevice for Disk { device .write_all(buffer) .expect("Unable to write 4096 bytes!"); + debug!("disk::write block {}", block_id); } } diff --git a/ayafs-core/src/disk/allocation.rs b/ayafs-core/src/disk/allocation.rs index a187fad..6b7167a 100644 --- a/ayafs-core/src/disk/allocation.rs +++ b/ayafs-core/src/disk/allocation.rs @@ -255,6 +255,7 @@ impl AyaFS { Ok(()) } + #[allow(unused)] /// 从 inode 中删去最后一个 block pub(crate) fn deallocate_block_for(&mut self, inode: &mut Inode) -> Option { // 如果 triple indirect 块存在, 则尝试从中销毁一个块 @@ -300,6 +301,7 @@ impl AyaFS { None } + #[allow(unused)] fn deallocate_from_triple_indirect(&mut self, triple_indirect_entry: u32) -> Option { let triple_indirect_entry = triple_indirect_entry as usize; if let Some(triple_indirect_block) = self @@ -339,6 +341,7 @@ impl AyaFS { None } + #[allow(unused)] fn deallocate_from_double_indirect(&mut self, double_indirect_entry: u32) -> Option { let double_indirect_entry = double_indirect_entry as usize; if let Some(double_indirect_block) = self @@ -373,6 +376,7 @@ impl AyaFS { None } + #[allow(unused)] fn deallocate_from_indirect(&mut self, indirect_entry: u32) -> Option { let indirect_entry = indirect_entry as usize; if let Some(indirect_block) = self @@ -521,6 +525,11 @@ impl AyaFS { ) -> Option<&CachedBlock> { self.get_block_index(inode, block_index_within_inode) .map(|block_index| { + debug!( + "access_block(index: {}) found with global index {}", + block_index_within_inode, + block_index, + ); self.get_block::(block_index).unwrap() // 可以 unwrap 吧这里 ?? }) } @@ -533,8 +542,9 @@ impl AyaFS { self.get_block_index(inode, block_index_within_inode) .map(|block_index| { debug!( - "access_block_mut(index: {}) found", - block_index_within_inode + "access_block_mut(index: {}) found with global index {}", + block_index_within_inode, + block_index, ); self.get_block_mut::(block_index).unwrap() // 可以 unwrap 吧这里 ?? }) diff --git a/ayafs-core/src/disk/bitmap.rs b/ayafs-core/src/disk/bitmap.rs index b68c341..cf7eae5 100644 --- a/ayafs-core/src/disk/bitmap.rs +++ b/ayafs-core/src/disk/bitmap.rs @@ -6,22 +6,59 @@ pub struct Bitmap { pub length: usize, pub device: Arc, pub data: Vec, + pub count: u64, } impl Bitmap { - pub(crate) fn new(starting_block: usize, length: usize, device: Arc) -> Self { + pub(crate) fn new(starting_block: usize, length: usize, device: Arc, count: u64) -> Self { Self { starting_block, length, device, data: vec![0u8; length * BLOCK_SIZE], + count, } } + + pub(crate) fn load(starting_block: usize, length: usize, device: Arc, count: u64) -> Self { + let mut data = vec![0u8; length * BLOCK_SIZE]; + for id in 0 .. length { + let block_id = starting_block + id; + device.read(block_id, &mut data[id * BLOCK_SIZE .. (id + 1) * BLOCK_SIZE]); + } + Self { + starting_block, + length, + device, + data, + count, + } + } + + pub(crate) fn write_back(&self) { + for id in 0 .. self.length { + let block_id = self.starting_block + id; + self.device.write(block_id, &self.data[id * BLOCK_SIZE .. (id + 1) * BLOCK_SIZE]); + } + } + + // Allocate, but doesn't modify self. + pub(crate) fn peek(&self) -> Option { + for (i, byte) in self.data.iter().enumerate() { + let leading_ones = byte.leading_ones(); + if leading_ones != 8 { + return Some(i * 8 + leading_ones as usize); + } + } + None + } + pub(crate) fn allocate(&mut self) -> Option { 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.count += 1; return Some(i * 8 + leading_ones as usize); } } @@ -39,6 +76,7 @@ impl Bitmap { pub(crate) fn deallocate(&mut self, index: usize) -> bool { if self.query(index) { let mask = !(1u8 << (7 - index % 8)); + self.count -= 1; self.data[index / 8] &= mask; true } else { diff --git a/ayafs-core/src/disk/block.rs b/ayafs-core/src/disk/block.rs index 76769b9..e48385d 100644 --- a/ayafs-core/src/disk/block.rs +++ b/ayafs-core/src/disk/block.rs @@ -10,7 +10,10 @@ pub struct SuperBlock { pub(crate) inode_bitmap_block_number: u64, pub(crate) inode_block_number: u64, pub(crate) data_block_number: u64, - padding: [u8; 4064], + pub(crate) total_block_number: u64, + pub(crate) used_inode_number: u64, + pub(crate) used_block_number: u64, + padding: [u8; 4040], } impl SuperBlock { @@ -19,13 +22,19 @@ impl SuperBlock { inode_bitmap_block_number: usize, inode_block_number: usize, data_block_number: usize, + total_block_number: usize, + used_inode_number: u64, + used_block_number: u64, ) -> Self { Self { data_bitmap_block_number: data_bitmap_block_number as u64, inode_bitmap_block_number: inode_bitmap_block_number as u64, inode_block_number: inode_block_number as u64, data_block_number: data_block_number as u64, - padding: [0; 4064], + total_block_number: total_block_number as u64, + used_inode_number, + used_block_number, + padding: [0; 4040], } } } @@ -155,11 +164,6 @@ impl Default for DirectoryBlock { } impl DirectoryBlock { - #[allow(unused)] - pub(crate) fn is_full(&self) -> bool { - self.occupancy[0] == 0xFF && self.occupancy[1] == 0xFF - } - pub(crate) fn query(&self, mut index: usize) -> bool { if index < 7 { // 0-6, first u8 @@ -196,20 +200,12 @@ impl DirectoryBlock { } } - // pub(crate) fn allocate(&mut self) -> Option { - // if self.occupancy[0] != 0xFF { - // let leading_ones = self.occupancy[0].leading_ones(); - // self.occupancy[0] |= (1 << (7 - leading_ones)) as u8; - // Some(leading_ones as usize) - // } else if self.occupancy[1] != 0xFF { - // let leading_ones = self.occupancy[1].leading_ones(); - // self.occupancy[1] |= (1 << (7 - leading_ones)) as u8; - // Some(7 + leading_ones as usize) - // } else { - // None - // } - // } + pub(crate) fn reset(&mut self) { + self.occupancy[0] = 0x80; + self.occupancy[1] = 0x00; + } + #[allow(unused)] pub(crate) fn deallocate(&mut self, mut index: usize) { if index < 7 { index = index + 1; @@ -269,3 +265,11 @@ impl Default for TripleIndirectBlock { } impl Block for TripleIndirectBlock {} + +const_assert_eq!(std::mem::size_of::(), 4096); +const_assert_eq!(std::mem::size_of::(), 4096); +const_assert_eq!(std::mem::size_of::(), 4096); +const_assert_eq!(std::mem::size_of::(), 4096); +const_assert_eq!(std::mem::size_of::(), 4096); +const_assert_eq!(std::mem::size_of::(), 4096); +const_assert_eq!(std::mem::size_of::(), 4096); \ No newline at end of file diff --git a/ayafs-core/src/disk/inode.rs b/ayafs-core/src/disk/inode.rs index d94b795..eccebd4 100644 --- a/ayafs-core/src/disk/inode.rs +++ b/ayafs-core/src/disk/inode.rs @@ -3,7 +3,8 @@ use crate::utils; use bitflags::bitflags; use fuser::FileType; -pub const DIRECT_NUMBER: usize = 15; +pub(crate) const DIRECT_NUMBER: usize = 15; +pub(crate) const INODE_PER_BLOCK: usize = BLOCK_SIZE / INODE_SIZE; #[derive(Debug, Clone, Copy)] pub struct InodeMode(pub u16); @@ -128,7 +129,7 @@ impl From for u8 { pub struct Inode { pub mode: InodeMode, pub uid: u32, - pub size: u32, + pub size: u64, pub atime: u32, // access time, in seconds pub ctime: u32, // change time, in seconds pub mtime: u32, // modify time, in seconds @@ -141,7 +142,6 @@ pub struct Inode { pub single_indirect: u32, pub double_indirect: u32, pub triple_indirect: u32, - pub generation: u32, pub file_acl: u32, pub dir_acl: u32, // TODO do we have to implement ACL......? } @@ -153,7 +153,6 @@ impl Inode { gid: u32, time: u32, flags: u32, - generation: u32, file_acl: u32, dir_acl: u32, ) -> Self { @@ -173,7 +172,6 @@ impl Inode { single_indirect: 0, double_indirect: 0, triple_indirect: 0, - generation, file_acl, dir_acl, } @@ -187,7 +185,6 @@ impl Inode { gid: u32, time: u32, flags: u32, - generation: u32, file_acl: u32, dir_acl: u32, ) -> Self { @@ -197,7 +194,6 @@ impl Inode { gid, time, flags, - generation, file_acl, dir_acl, ) @@ -209,7 +205,6 @@ impl Inode { gid: u32, time: u32, flags: u32, - generation: u32, file_acl: u32, dir_acl: u32, ) -> Self { @@ -219,7 +214,6 @@ impl Inode { gid, time, flags, - generation, file_acl, dir_acl, ) @@ -231,7 +225,6 @@ impl Inode { gid: u32, time: u32, flags: u32, - generation: u32, file_acl: u32, dir_acl: u32, ) -> Self { @@ -241,7 +234,6 @@ impl Inode { gid, time, flags, - generation, file_acl, dir_acl, ) @@ -253,7 +245,6 @@ impl Inode { gid: u32, time: u32, flags: u32, - generation: u32, file_acl: u32, dir_acl: u32, ) -> Self { @@ -263,7 +254,6 @@ impl Inode { gid, time, flags, - generation, file_acl, dir_acl, ) @@ -302,7 +292,6 @@ impl Inode { single_indirect: 0, double_indirect: 0, triple_indirect: 0, - generation: 0, file_acl: 0, dir_acl: 0, } diff --git a/ayafs-core/src/filesystem/trait_impl.rs b/ayafs-core/src/filesystem/trait_impl.rs index b551cf7..78673ba 100644 --- a/ayafs-core/src/filesystem/trait_impl.rs +++ b/ayafs-core/src/filesystem/trait_impl.rs @@ -1,17 +1,14 @@ use crate::block_device::BLOCK_SIZE; use crate::disk::block::DataBlock; -use crate::disk::inode::InodeMode; +use crate::disk::inode::{INODE_PER_BLOCK, InodeMode}; use crate::utils::permissions::{check_access, clear_suid_sgid, get_groups}; use crate::utils::{from_filetype, from_systime, time_now, to_fileattr, to_filetype}; use crate::{AyaFS, TTL}; use fuser::TimeOrNow::{Now, SpecificTime}; -use fuser::{ - FileType, Filesystem, KernelConfig, ReplyAttr, ReplyData, ReplyDirectory, ReplyEmpty, - ReplyEntry, ReplyOpen, ReplyStatfs, ReplyWrite, ReplyXattr, Request, TimeOrNow, -}; +use fuser::{FileType, Filesystem, KernelConfig, ReplyAttr, ReplyData, ReplyDirectory, ReplyEmpty, ReplyEntry, ReplyOpen, ReplyWrite, Request, TimeOrNow, ReplyStatfs}; use libc::{ c_int, EACCES, EBADF, EEXIST, EINVAL, EIO, EISDIR, ENAMETOOLONG, ENOENT, ENOSPC, ENOTDIR, - ENOTEMPTY, EPERM, IPOPT_OFFSET, O_ACCMODE, O_RDONLY, O_RDWR, O_WRONLY, RENAME_EXCHANGE, + ENOTEMPTY, EPERM, O_ACCMODE, O_RDONLY, O_RDWR, O_WRONLY, RENAME_EXCHANGE, RENAME_NOREPLACE, R_OK, S_ISGID, S_ISUID, S_IXGRP, S_IXOTH, S_IXUSR, W_OK, }; use log::debug; @@ -25,13 +22,13 @@ impl AyaFS {} impl Filesystem for AyaFS { fn init(&mut self, _req: &Request<'_>, _config: &mut KernelConfig) -> Result<(), c_int> { - debug!("`init()"); + debug!("init()"); Ok(()) } fn destroy(&mut self) { debug!("destroy()"); - // TODO 写回 + self.write_back(); } fn lookup(&mut self, req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEntry) { @@ -66,8 +63,24 @@ impl Filesystem for AyaFS { } } + // fn getxattr(&mut self, _req: &Request<'_>, ino: u64, name: &OsStr, size: u32, reply: ReplyXattr) { + // if let Some(inode) = self.get_inode(ino as usize) { + // debug!( + // "getattr(ino: {}, incoming_uid: {}, inode_uid: {})", + // ino, _req.uid(), inode.uid, + // ); + // reply.error(ENOENT); + // } else { + // reply.error(ENOENT); + // } + // } + fn getattr(&mut self, _req: &Request<'_>, ino: u64, reply: ReplyAttr) { if let Some(inode) = self.get_inode(ino as usize) { + debug!( + "getattr(ino: {}, incoming_uid: {}, inode_uid: {})", + ino, _req.uid(), inode.uid, + ); reply.attr(&TTL, &to_fileattr(ino as usize, inode)); } else { reply.error(ENOENT); @@ -172,7 +185,7 @@ impl Filesystem for AyaFS { if !write { reply.error(EACCES); } else { - inode.size = size as u32; + inode.size = size; reply.attr(&TTL, &to_fileattr(*inode_index, &inode)); self.update_inode(*inode_index, inode); } @@ -180,7 +193,7 @@ impl Filesystem for AyaFS { if !check_access(req.uid(), req.gid(), inode.uid, inode.gid, inode.mode, W_OK) { reply.error(EACCES); } else { - inode.size = size as u32; + inode.size = size; reply.attr(&TTL, &to_fileattr(ino as usize, &inode)); } } @@ -689,7 +702,7 @@ impl Filesystem for AyaFS { self.create_symlink(0o777, req.uid(), req.gid(), 0) { let mut child_inode = child_inode.clone(); - child_inode.size = target.len() as u32; + child_inode.size = target.len() as u64; if target.len() < 60 { debug!("create_symlink: target length < 60, allocating in 'direct' section."); let target_path = target.as_bytes(); @@ -805,7 +818,7 @@ impl Filesystem for AyaFS { let mut parent_inode = parent_inode.clone(); match self.lookup_name(parent, &parent_inode, name) { - Ok((inode_index, entry_index, inode)) => { + Ok((_inode_index, entry_index, _inode)) => { if let Some(new_parent_inode) = self.get_inode(new_parent) { if !check_access( req.uid(), @@ -825,7 +838,7 @@ impl Filesystem for AyaFS { let mut new_parent_inode = new_parent_inode.clone(); match self.lookup_name(new_parent, &new_parent_inode, new_name) { - Ok((new_inode_index, new_entry_index, new_inode)) => { + Ok((_new_inode_index, new_entry_index, _new_inode)) => { // 新文件存在 if flags & RENAME_NOREPLACE != 0 { // 指定 noreplace 之后不允许覆盖文件 @@ -993,7 +1006,7 @@ impl Filesystem for AyaFS { } debug!("reading inode {:#x} (offset {} size {})", ino, offset, size); - if offset as u32 >= inode.size { + if offset as u64 >= inode.size { // offset 在 EOF 后面, 直接返回一个 0 长度的空 buffer reply.data(&Vec::new()); return; @@ -1001,10 +1014,12 @@ impl Filesystem for AyaFS { // let read_length = size.min(inode.size.saturating_sub(offset as u32)) as usize; // 这和下面那个是等同的但是不利于让人看懂…… - let read_length = if offset as u32 + size <= inode.size { + + let size = size as u64; + let read_length = if size.checked_add_signed(offset).unwrap() <= inode.size { size // 没有越过 EOF, 读取 size 个 byte } else { - inode.size - offset as u32 // 越过了 EOF, 读取 inode.size - offset 个 byte + inode.size - offset as u64 // 越过了 EOF, 读取 inode.size - offset 个 byte } as usize; let mut read_buffer = vec![0u8; read_length]; @@ -1094,7 +1109,7 @@ impl Filesystem for AyaFS { "writing {} bytes in block {} within inode", write_length_within_block, current_block_index ); - (block.block.0[current_offset..current_offset + write_length_within_block]) + block.block.0[current_offset..current_offset + write_length_within_block] .copy_from_slice(&data[write_ptr..write_ptr + write_length_within_block]); write_ptr += write_length_within_block; } else { @@ -1107,7 +1122,7 @@ impl Filesystem for AyaFS { let block = self .access_block_mut::(&inode, block_index_within_inode) .unwrap(); - (block.block.0[current_offset..current_offset + write_length_within_block]) + block.block.0[current_offset..current_offset + write_length_within_block] .copy_from_slice( &data[write_ptr..write_ptr + write_length_within_block], ); @@ -1119,7 +1134,7 @@ impl Filesystem for AyaFS { } } - inode.size = inode.size.max(offset as u32 + write_length as u32); + inode.size = inode.size.max(offset as u64 + write_length as u64); self.update_inode(ino as usize, inode); reply.written(write_length as u32); } else { @@ -1127,30 +1142,6 @@ impl Filesystem for AyaFS { } } - // fn getxattr( - // &mut self, - // _req: &Request<'_>, - // ino: u64, - // name: &OsStr, - // size: u32, - // reply: ReplyXattr, - // ) { - // todo!() - // } - // - // fn setxattr( - // &mut self, - // _req: &Request<'_>, - // ino: u64, - // name: &OsStr, - // _value: &[u8], - // flags: i32, - // position: u32, - // reply: ReplyEmpty, - // ) { - // todo!() - // } - fn release( &mut self, _req: &Request<'_>, @@ -1284,9 +1275,25 @@ impl Filesystem for AyaFS { } } - // fn statfs(&mut self, _req: &Request<'_>, _ino: u64, reply: ReplyStatfs) { - // todo!() - // } + fn statfs(&mut self, _req: &Request<'_>, ino: u64, reply: ReplyStatfs) { + if let Some(_) = self.get_inode(ino as usize) { + self.super_block.used_inode_number = self.inode_bitmap.count; + self.super_block.used_block_number = self.data_bitmap.count; + + reply.statfs( + self.super_block.used_block_number, + self.super_block.data_block_number - self.super_block.used_block_number, + self.super_block.data_block_number - self.super_block.used_block_number, + self.super_block.used_inode_number, + self.super_block.inode_block_number * INODE_PER_BLOCK as u64 - self.super_block.used_inode_number, + BLOCK_SIZE as u32, + 255, + BLOCK_SIZE as u32, + ); + } else { + reply.error(ENOENT); + } + } fn access(&mut self, req: &Request<'_>, ino: u64, mask: i32, reply: ReplyEmpty) { // mask: @@ -1295,6 +1302,7 @@ impl Filesystem for AyaFS { debug!("Filesystem::access(ino: {}, mask: {})", ino, mask); if let Some(inode) = self.get_inode(ino as usize) { + debug!(" uid: {}, gid: {}, incoming_uid: {}, incoming_gid: {}, mask: {}", inode.uid, inode.gid, req.uid(), req.gid(), mask); if mask == libc::F_OK // 只要检查是否存在 || check_access(req.uid(), req.gid(), inode.uid, inode.gid, inode.mode, mask) // 需要检查 rwx 权限 diff --git a/ayafs-core/src/lib.rs b/ayafs-core/src/lib.rs index 5ec118a..db3ac28 100644 --- a/ayafs-core/src/lib.rs +++ b/ayafs-core/src/lib.rs @@ -1,3 +1,6 @@ +#[macro_use] +extern crate static_assertions; + pub mod block_device; pub mod disk; pub mod filesystem; @@ -15,17 +18,17 @@ use std::num::NonZeroUsize; use std::sync::atomic::AtomicU64; use std::sync::Arc; use std::time::Duration; +use libc::{gid_t, uid_t}; use crate::disk::block::{DirectoryEntry, InodeBlock, SuperBlock}; use crate::memory::cached_block::BlockCache; use block_device::{BlockDevice, BLOCK_SIZE}; use disk::bitmap::Bitmap; use disk::block::DataBlock; -use disk::inode::INODE_SIZE; -use users::{get_current_gid, get_current_uid}; +use crate::disk::inode::INODE_PER_BLOCK; + const TTL: Duration = Duration::new(0, 0); -const INODE_PER_BLOCK: usize = BLOCK_SIZE / INODE_SIZE; /// The design of MyFS is rather simple: /// +-------------------+ @@ -69,7 +72,7 @@ pub struct AyaFS { } impl AyaFS { - pub fn new(device: Arc, total_block_number: usize) -> Self { + pub fn new(device: Arc, total_block_number: usize, uid: uid_t, gid: gid_t) -> Self { let max_inode_number: usize = 16384; // TODO: remove hard-coded magic number let inode_block_number = max_inode_number / INODE_PER_BLOCK; // == 128 let inode_bitmap_block_number = (inode_block_number + BLOCK_SIZE - 1) / BLOCK_SIZE; @@ -101,40 +104,135 @@ impl AyaFS { inode_bitmap_block_number, inode_block_number, data_block_number, + total_block_number, + 0, + 0 ); - let mut data_bitmap = Bitmap::new(1, data_bitmap_block_number, device.clone()); + let mut data_bitmap = Bitmap::new(1, data_bitmap_block_number, device.clone(), 0); 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(), + 0, ); let _ = inode_bitmap.allocate().unwrap(); // inode block 0 is not usable + let inode_start_block = data_bitmap_block_number + inode_bitmap_block_number + 1; + let data_start_block = inode_start_block + inode_block_number; + let mut fs = Self { device: device.clone(), data_bitmap, inode_bitmap, - inode_start_block: data_bitmap_block_number + inode_bitmap_block_number + 1, - data_start_block: data_bitmap_block_number - + inode_bitmap_block_number - + inode_block_number - + 1, + inode_start_block, + data_start_block, next_file_handle: AtomicU64::new(3), // 0,1,2 are stdin, stdout and stderr file_handle_map: HashMap::new(), dir_entry_map: LruCache::new(NonZeroUsize::new(1024).unwrap()), - cached_inodes: BlockCache::new(device.clone(), 1024), - cached_blocks: BlockCache::new(device.clone(), 8192), + cached_inodes: BlockCache::new(device.clone(), 8192, inode_start_block), + cached_blocks: BlockCache::new(device.clone(), 16384, data_start_block), super_block, }; - fs.create_directory(0o755, get_current_uid(), get_current_gid(), 0, None); + fs.create_directory(0o755, uid, gid, 0, None); fs } + + pub fn load(device: Arc) -> Self { + let mut buffer = [0u8; 4096]; + device.read(0, &mut buffer); + + let super_block: SuperBlock = unsafe { + std::mem::transmute_copy(&buffer) + }; + let data_bitmap_block_number = super_block.data_bitmap_block_number as usize; + let inode_bitmap_block_number = super_block.inode_bitmap_block_number as usize; + let inode_block_number = super_block.inode_block_number as usize; + let data_block_number = super_block.data_block_number as usize; + debug!("data_bitmap_block_number: {}", data_bitmap_block_number); + debug!("inode_bitmap_block_number: {}", inode_bitmap_block_number); + debug!("inode_block_number: {}", inode_block_number); + debug!("data_block_number: {}", data_block_number); + debug!("total_block_number: {}", super_block.total_block_number); + debug!( + "sum: {}", + 1 + data_bitmap_block_number + + inode_bitmap_block_number + + inode_block_number + + data_block_number + ); + + let data_bitmap = Bitmap::load( + 1, + data_bitmap_block_number, + device.clone(), + super_block.used_block_number, + ); + debug!("data_bitmap starting from: {:?}", data_bitmap.peek()); + + let inode_bitmap = Bitmap::load( + data_bitmap_block_number + 1, + inode_bitmap_block_number, + device.clone(), + super_block.used_inode_number, + ); + debug!("inode_bitmap starting from: {:?}", inode_bitmap.peek()); + + let inode_start_block = data_bitmap_block_number + inode_bitmap_block_number + 1; + let data_start_block = inode_start_block + inode_block_number; + + Self { + device: device.clone(), + data_bitmap, + inode_bitmap, + inode_start_block, + data_start_block, + + next_file_handle: AtomicU64::new(3), // 0,1,2 are stdin, stdout and stderr + file_handle_map: HashMap::new(), + + dir_entry_map: LruCache::new(NonZeroUsize::new(1024).unwrap()), + + cached_inodes: BlockCache::new(device.clone(), 1024, inode_start_block), + cached_blocks: BlockCache::new(device.clone(), 8192, data_start_block), + + super_block, + } + } + + pub fn write_back(&mut self) { + self.super_block.used_inode_number = self.inode_bitmap.count; + self.super_block.used_block_number = self.data_bitmap.count; + let super_block_buffer = unsafe { + let ptr = &self.super_block as *const SuperBlock as *const u8; + std::slice::from_raw_parts(ptr, std::mem::size_of::()) + }; + self.device.write(0, super_block_buffer); + + while let Some((inode_index, dir_entry_map)) = self.dir_entry_map.pop_lru() { + debug!("writing back direntry map for inode {}", inode_index); + let mut inode = self.get_inode(inode_index).unwrap().clone(); + self.write_back_direntry( + inode_index, + &mut inode, + dir_entry_map, + ).unwrap(); + self.update_inode(inode_index, inode); + } // dir entry 的 write back 是写回到 block / inode cache 里, 所以要在前面 + + debug!("data_bitmap stopping at: {:?}", self.data_bitmap.peek()); + debug!("inode_bitmap stopping at: {:?}", self.inode_bitmap.peek()); + self.data_bitmap.write_back(); + self.inode_bitmap.write_back(); + + self.cached_blocks.write_back(); + self.cached_inodes.write_back(); + } } diff --git a/ayafs-core/src/memory/cached_block.rs b/ayafs-core/src/memory/cached_block.rs index c3d0338..24f08c0 100644 --- a/ayafs-core/src/memory/cached_block.rs +++ b/ayafs-core/src/memory/cached_block.rs @@ -4,6 +4,7 @@ use crate::AyaFS; use lru::LruCache; use std::num::NonZeroUsize; use std::sync::Arc; +use log::debug; #[derive(Clone)] pub struct CachedBlock { @@ -27,20 +28,37 @@ pub fn convert(input_block: &CachedBlock) -> &CachedBlock pub(crate) struct BlockCache { device: Arc, cache: LruCache>, + pub global_offset: usize, } impl BlockCache { - pub(crate) fn new(device: Arc, cache_size: usize) -> Self { + pub(crate) fn new(device: Arc, cache_size: usize, global_offset: usize) -> Self { Self { device, cache: LruCache::new(NonZeroUsize::new(cache_size).unwrap()), + global_offset, + } + } + + pub(crate) fn write_back(&self) { + for (_, cached_block) in self.cache.iter() { + if cached_block.dirty { + debug!("write_back: dirty block {}", self.global_offset + cached_block.index); + let block_buffer = unsafe { + let block_ptr = &cached_block.block as *const T as *const u8; + std::slice::from_raw_parts(block_ptr, std::mem::size_of::()) + }; + self.device.write(self.global_offset + cached_block.index, block_buffer); + } else { + debug!("write_back: clean block {}", self.global_offset + cached_block.index); + } } } pub(crate) fn load_block(&mut self, index: usize) -> bool { if self.cache.contains(&index) == false { let mut buffer = [0u8; BLOCK_SIZE]; - self.device.read(index, &mut buffer); + self.device.read(self.global_offset + index, &mut buffer); let block: T = unsafe { std::mem::transmute_copy(&buffer) }; let cached_block = CachedBlock { block, @@ -50,10 +68,12 @@ impl BlockCache { if let Some((old_index, old_block)) = self.cache.push(index, cached_block) { assert_ne!(old_index, index); // 只有 block 不在 cache 里的时候才会插入 if old_block.dirty { - let old_block_ptr = &old_block.block as *const T 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); + debug!("write_back: evicted dirty block {} while loading {}", self.global_offset + old_block.index, self.global_offset + index); + let old_block_buffer = unsafe { + let old_block_ptr = &old_block.block as *const T as *mut u8; + std::slice::from_raw_parts(old_block_ptr, BLOCK_SIZE) + }; + self.device.write(self.global_offset + old_block.index, old_block_buffer); } } } @@ -64,21 +84,43 @@ impl BlockCache { /// 这个函数不应该返回 None pub(crate) fn get_block(&mut self, index: usize) -> Option<&CachedBlock> { if !self.cache.contains(&index) { + debug!("get_block(global_block_id: {}) loading from disk", index + self.global_offset); self.load_block(index); } - self.cache.get(&index).map(convert::) + + if let Some(block) = self.cache.get(&index) { + debug!("get_block(global_block_id: {}) found", index + self.global_offset); + Some(convert::(block)) + } else { + debug!("get_block(global_block_id: {}) not found", index + self.global_offset); + None + } + // debug!("get_block(global_block_id: {}) found", index + self.global_offset); + // self.cache.get(&index).map(convert::) } /// 从 LRU cache 里获取一个 block 的可变引用, 如果没有在 cache 中会加载. /// 这个函数不应该返回 None pub(crate) fn get_block_mut(&mut self, index: usize) -> Option<&mut CachedBlock> { if !self.cache.contains(&index) { + debug!("get_block_mut(global_block_id: {}) loading from disk", index + self.global_offset); self.load_block(index); } - self.cache.get_mut(&index).map(|block| { + + if let Some(block) = self.cache.get_mut(&index) { + debug!("get_block_mut(global_block_id: {}) found", index + self.global_offset); block.dirty = true; - convert_mut::(block) - }) + Some(convert_mut::(block)) + } else { + debug!("get_block_mut(global_block_id: {}) not found", index + self.global_offset); + None + } + + // self.cache.get_mut(&index).map(|block| { + // debug!("get_block_mut(global_block_id: {}) found", index + self.global_offset); + // block.dirty = true; + // convert_mut::(block) + // }) } /// 向 LRU cache 中插入一个全新初始化的 block @@ -94,7 +136,7 @@ impl BlockCache { let old_block_ptr = &old_block.block as *const T 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); + self.device.write(self.global_offset + old_index, old_block_buffer); } } } @@ -115,15 +157,18 @@ impl BlockCache { if self.cache.contains(&block.index) { let mut data_block = convert::(&block).clone(); data_block.dirty = true; // TODO 需要把显式写回的都标记为 dirty 吗 - self.cache.push(block.index, data_block); + let (entry, _value) = self.cache.push(block.index, data_block).unwrap(); + assert_eq!(entry, block.index); + debug!("update_block(global_block_id: {})", block.index + self.global_offset); true } else { false } } - fn pop(&mut self, entry: &usize) -> Option> { - self.cache.pop(entry) + fn pop(&mut self, entry: usize) -> Option> { + debug!("pop_block(global_block_id: {})", entry + self.global_offset); + self.cache.pop(&entry) } } @@ -134,9 +179,11 @@ impl AyaFS { pub(crate) fn get_block(&mut self, index: usize) -> Option<&CachedBlock> { if self.data_bitmap.query(index) { + debug!("get_block(block_id: {}) found", index); Some(self.cached_blocks.get_block::(index).unwrap()) } else { - self.cached_blocks.pop(&index); + debug!("get_block(block_id: {}) not exist", index); + self.cached_blocks.pop(index); None } // self.data_bitmap @@ -149,7 +196,7 @@ impl AyaFS { if self.data_bitmap.query(index) { Some(self.cached_blocks.get_block_mut::(index).unwrap()) } else { - self.cached_blocks.pop(&index); + self.cached_blocks.pop(index); None } // self.data_bitmap diff --git a/ayafs-core/src/memory/cached_inode.rs b/ayafs-core/src/memory/cached_inode.rs index 2f26dde..70579c7 100644 --- a/ayafs-core/src/memory/cached_inode.rs +++ b/ayafs-core/src/memory/cached_inode.rs @@ -15,7 +15,7 @@ impl AyaFS { ) -> 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 = Inode::file(permissions, uid, gid, utils::time_now(), flags, 0, 0); }); (inode_index, self.get_inode(inode_index).unwrap()) }) @@ -30,7 +30,7 @@ impl AyaFS { ) -> Option<(usize, &Inode)> { self.inode_bitmap.allocate().map(|inode_index| { self.get_inode_mut(inode_index).map(|inode| { - *inode = Inode::symlink(permissions, uid, gid, utils::time_now(), flags, 0, 0, 0); + *inode = Inode::symlink(permissions, uid, gid, utils::time_now(), flags, 0, 0); }); (inode_index, self.get_inode(inode_index).unwrap()) }) @@ -48,7 +48,7 @@ impl AyaFS { self.inode_bitmap.allocate().map(|inode_index| { // 创建 Inode let mut new_inode = - Inode::directory(permissions, uid, gid, utils::time_now(), flags, 0, 0, 0); + Inode::directory(permissions, uid, gid, utils::time_now(), flags, 0, 0); self.init_direntry_map(inode_index); self.add_direntry(inode_index, &mut new_inode, inode_index, ".", 0x2) .unwrap(); @@ -85,6 +85,7 @@ impl AyaFS { _ => return Err(EIO), } } + // self.update_inode(inode_index, Inode::empty()); self.inode_bitmap.deallocate(inode_index); Ok(true) } else { @@ -123,6 +124,7 @@ impl AyaFS { if let Some(cached_block) = self.cached_inodes.get_block_mut::(block_index) { cached_block.block.inodes[offset / INODE_SIZE] = inode; + cached_block.dirty = true; } true } else { diff --git a/ayafs-core/src/memory/dir_entry.rs b/ayafs-core/src/memory/dir_entry.rs index 55c67bd..3880f61 100644 --- a/ayafs-core/src/memory/dir_entry.rs +++ b/ayafs-core/src/memory/dir_entry.rs @@ -38,9 +38,11 @@ impl AyaFS { match self.access_block::(inode, block_index_within_inode) { Some(directory_block) => { + debug!("bitmap for block is {:#b} {:#b}", directory_block.block.occupancy[0], directory_block.block.occupancy[1]); 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(); + debug!("loaded entry({:?}) for inode {}", name.as_os_str(), index); dir_entry_map.insert(name, dir_entry.clone()); } else { break; @@ -70,7 +72,7 @@ impl AyaFS { parent_inode: &mut Inode, dir_entry_map: IndexMap, ) -> Result<(), c_int> { - for (entry_index, (_, dir_entry)) in dir_entry_map.into_iter().enumerate() { + for (entry_index, (name, 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; // 不够就新分配 @@ -89,7 +91,13 @@ impl AyaFS { } match self.access_block_mut::(parent_inode, block_index_within_inode) { Some(directory_block) => { + if entry_index_within_block == 0 { + directory_block.block.reset(); + } + directory_block.dirty = true; + debug!("entry {} (block {} offset {}) for inode {}, name {:?}", entry_index, block_index_within_inode, entry_index_within_block, _parent_index, name); directory_block.block.allocate(entry_index_within_block); + debug!("bitmap for block is {:#b} {:#b}", directory_block.block.occupancy[0], directory_block.block.occupancy[1]); directory_block.block.entries[entry_index_within_block] = dir_entry; } None => { @@ -291,10 +299,10 @@ impl AyaFS { } 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 let Ok(entry) = self.get_direntry(parent_index, parent_inode, entry_index as u32) { if entry.name() == name { let inode = self.get_inode(entry.inode as usize).unwrap().clone(); - return Ok((entry.inode, entry_index, inode)); + return Ok((entry.inode, entry_index as u32, inode)); } } entry_index += 1; diff --git a/ayafs-core/src/tests/common/mod.rs b/ayafs-core/src/tests/common/mod.rs index 3abfcb4..134c84a 100644 --- a/ayafs-core/src/tests/common/mod.rs +++ b/ayafs-core/src/tests/common/mod.rs @@ -1,9 +1,10 @@ use crate::block_device::memory_disk::MemoryDisk; use crate::AyaFS; use std::sync::Arc; +use users::{get_current_gid, get_current_uid}; #[allow(unused)] pub(crate) fn setup() -> AyaFS { let mem_disk = Arc::new(MemoryDisk::new(1059715)); - AyaFS::new(mem_disk, 1059715) + AyaFS::new(mem_disk, 1059715, get_current_uid(), get_current_gid()) } diff --git a/ayafs-core/src/tests/mod.rs b/ayafs-core/src/tests/mod.rs index df442c1..98984ff 100644 --- a/ayafs-core/src/tests/mod.rs +++ b/ayafs-core/src/tests/mod.rs @@ -1,6 +1,5 @@ #[cfg(test)] mod bitmap; mod common; - #[cfg(test)] mod block_cache; diff --git a/ayafs-core/src/utils/constants.rs b/ayafs-core/src/utils/constants.rs deleted file mode 100644 index 8b13789..0000000 --- a/ayafs-core/src/utils/constants.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/ayafs-core/src/utils/mod.rs b/ayafs-core/src/utils/mod.rs index 468ebdb..d73cb3e 100644 --- a/ayafs-core/src/utils/mod.rs +++ b/ayafs-core/src/utils/mod.rs @@ -1,4 +1,3 @@ -mod constants; pub mod permissions; use crate::block_device::BLOCK_SIZE; @@ -7,6 +6,8 @@ use crate::{AyaFS, INODE_PER_BLOCK}; use fuser::{FileAttr, FileType}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; +// pub(crate) const ANON_INODE_FS_MAGIC: libc::__fsword_t = 0x09041934; + pub(crate) fn time_now() -> u32 { SystemTime::now() .duration_since(UNIX_EPOCH) @@ -25,16 +26,6 @@ pub(crate) fn to_systime(time: u32) -> SystemTime { UNIX_EPOCH + Duration::from_secs(time as u64) } -// File type code, one of: -// 0x0 Unknown. -// 0x1 Regular file. -// 0x2 Directory. -// 0x3 Character device file. -// 0x4 Block device file. -// 0x5 FIFO. -// 0x6 Socket. -// 0x7 Symbolic link. - pub(crate) fn from_filetype(file_type: FileType) -> u8 { match file_type { FileType::NamedPipe => 0x5, @@ -85,7 +76,7 @@ impl AyaFS { /// 输入 inode 编号, 返回它对应的 block number 和 block 内 offset pub(crate) 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; + 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) } -- cgit v1.2.3-70-g09d2