From 1eac97eea4ec0bcef0be061a2cba93a584355283 Mon Sep 17 00:00:00 2001 From: Chuyan Zhang Date: Thu, 30 Nov 2023 02:15:06 -0800 Subject: Add real disk i/o, add mkfs.aya (not yet implemented) --- ayafs/src/main.rs | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 ayafs/src/main.rs (limited to 'ayafs/src/main.rs') diff --git a/ayafs/src/main.rs b/ayafs/src/main.rs new file mode 100644 index 0000000..db4a017 --- /dev/null +++ b/ayafs/src/main.rs @@ -0,0 +1,171 @@ +mod block_device; +mod disk; +mod filesystem; +mod memory; +mod tests; +mod utils; + +use clap::Parser; +use fuser::MountOption; +use indexmap::IndexMap; +use log::{debug, LevelFilter}; +use lru::LruCache; +use std::collections::HashMap; +use std::ffi::OsString; +use std::num::NonZeroUsize; +use std::path::PathBuf; +use std::sync::atomic::AtomicU64; +use std::sync::Arc; +use std::time::Duration; + +use crate::disk::block::{DirectoryEntry, InodeBlock}; +use crate::memory::cached_block::BlockCache; +use block_device::{memory_disk::MemoryDisk, 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::block_device::disk::Disk; + +#[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, +} + +const TTL: Duration = Duration::new(0, 0); +const INODE_PER_BLOCK: usize = BLOCK_SIZE / INODE_SIZE; + +/// The design of MyFS is rather simple: +/// +-------------------+ +/// | Super Block | +/// +-------------------+ +/// | Inode Bitmap | +/// +-------------------+ +/// | ... | +/// +-------------------+ +/// | Data Block Bitmap | +/// +-------------------+ +/// | ... | +/// +-------------------+ +/// | Inode Block | +/// +-------------------+ +/// | ... | +/// +-------------------+ +/// | Data Block | +/// +-------------------+ +/// With each block 4KiB, each Inode entry 128B + +#[repr(C)] +struct AyaFS { + device: Arc, + data_bitmap: Bitmap, + inode_bitmap: Bitmap, + inode_start_block: usize, + data_start_block: usize, + + next_file_handle: AtomicU64, + // file descriptor -> (inode index, read, write) + file_handle_map: HashMap, + + // inode index -> (index aware) hashmap that maps dir entry name to inode index + dir_entry_map: LruCache>, + + cached_inodes: BlockCache, + cached_blocks: BlockCache, +} + +impl AyaFS { + fn new(device: Arc, total_block_number: usize) -> 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; + + let blocks_remaining = + total_block_number - inode_block_number - inode_bitmap_block_number - 1; + // let number of data blocks be x, the remaining block number be C, + // the corresponding data bitmap length should be ceil(x / BLK_SIZE), + // thus we have BLK_SIZE * (C-1) / (BLK_SIZE+1) <= x <= BLK_SIZE * C / (BLK_SIZE+1) + // the difference of the two bounds is less than 1, + // meaning only 1 integer could be in between. + // Thus we have x = floor(BLK_SIZE * C / (BLK_SIZE + 1)) + let data_block_number = BLOCK_SIZE * blocks_remaining / (BLOCK_SIZE + 1); + let data_bitmap_block_number = blocks_remaining - data_block_number; + 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!( + "sum: {}", + 1 + data_bitmap_block_number + + inode_bitmap_block_number + + inode_block_number + + data_block_number + ); + + 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: 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, + + 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), + }; + + fs.create_directory(0o755, get_current_uid(), get_current_gid(), 0, None); + + fs + } +} + +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(Disk::new(PathBuf::from("/dev/nvme0n1p4"))); + // let disk = Arc::new(MemoryDisk::new(16384)); + let filesystem = AyaFS::new(disk, 7864320); + + fuser::mount2(filesystem, mount_point, &options).unwrap(); +} -- cgit v1.2.3-70-g09d2