summaryrefslogtreecommitdiff
path: root/ayafs/src/main.rs
diff options
context:
space:
mode:
authorChuyan Zhang <me@zcy.moe>2023-11-30 02:15:06 -0800
committerChuyan Zhang <me@zcy.moe>2023-11-30 02:15:06 -0800
commit1eac97eea4ec0bcef0be061a2cba93a584355283 (patch)
treed98fb1f6e3811286a0733c9df21e467590635ad2 /ayafs/src/main.rs
parentb3db8a5a710aa0890c80241ffb3fd9792bf1cbe7 (diff)
downloadmyfs-1eac97eea4ec0bcef0be061a2cba93a584355283.tar.gz
myfs-1eac97eea4ec0bcef0be061a2cba93a584355283.zip
Add real disk i/o, add mkfs.aya (not yet implemented)
Diffstat (limited to 'ayafs/src/main.rs')
-rw-r--r--ayafs/src/main.rs171
1 files changed, 171 insertions, 0 deletions
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<String>,
+ #[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<dyn BlockDevice>,
+ 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<u64, (usize, bool, bool)>,
+
+ // inode index -> (index aware) hashmap that maps dir entry name to inode index
+ dir_entry_map: LruCache<usize, IndexMap<OsString, DirectoryEntry>>,
+
+ cached_inodes: BlockCache<InodeBlock>,
+ cached_blocks: BlockCache<DataBlock>,
+}
+
+impl AyaFS {
+ fn new(device: Arc<dyn BlockDevice>, 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();
+}