use alloc::sync::Arc; use spin::Mutex; use super::{ BlockDevice, Bitmap, SuperBlock, DiskInode, DiskInodeType, Inode, get_block_cache, }; use crate::BLOCK_SZ; pub struct EasyFileSystem { pub block_device: Arc, pub inode_bitmap: Bitmap, pub data_bitmap: Bitmap, inode_area_start_block: u32, data_area_start_block: u32, } type DataBlock = [u8; BLOCK_SZ]; impl EasyFileSystem { pub fn create( block_device: Arc, total_blocks: u32, inode_bitmap_blocks: u32, ) -> Arc> { // calculate block size of areas & create bitmaps let inode_bitmap = Bitmap::new(1, inode_bitmap_blocks as usize); let inode_num = inode_bitmap.maximum(); let inode_area_blocks = ((inode_num * core::mem::size_of::() + BLOCK_SZ - 1) / BLOCK_SZ) as u32; let inode_total_blocks = inode_bitmap_blocks + inode_area_blocks; let data_total_blocks = total_blocks - 1 - inode_total_blocks; let data_bitmap_blocks = (data_total_blocks + 4096) / 4097; let data_area_blocks = data_total_blocks - data_bitmap_blocks; let data_bitmap = Bitmap::new( (1 + inode_bitmap_blocks + inode_area_blocks) as usize, data_bitmap_blocks as usize, ); let mut efs = Self { block_device: Arc::clone(&block_device), inode_bitmap, data_bitmap, inode_area_start_block: 1 + inode_bitmap_blocks, data_area_start_block: 1 + inode_total_blocks + data_bitmap_blocks, }; // clear all blocks for i in 0..total_blocks { get_block_cache( i as usize, Arc::clone(&block_device) ) .lock() .modify(0, |data_block: &mut DataBlock| { for byte in data_block.iter_mut() { *byte = 0; } }); } // initialize SuperBlock get_block_cache(0, Arc::clone(&block_device)) .lock() .modify(0, |super_block: &mut SuperBlock| { super_block.initialize( total_blocks, inode_bitmap_blocks, inode_area_blocks, data_bitmap_blocks, data_area_blocks, ); }); // write back immediately // create a inode for root node "/" assert_eq!(efs.alloc_inode(), 0); let (root_inode_block_id, root_inode_offset) = efs.get_disk_inode_pos(0); get_block_cache( root_inode_block_id as usize, Arc::clone(&block_device) ) .lock() .modify(root_inode_offset, |disk_inode: &mut DiskInode| { disk_inode.initialize(DiskInodeType::Directory); }); Arc::new(Mutex::new(efs)) } pub fn open(block_device: Arc) -> Arc> { // read SuperBlock get_block_cache(0, Arc::clone(&block_device)) .lock() .read(0, |super_block: &SuperBlock| { assert!(super_block.is_valid(), "Error loading EFS!"); let inode_total_blocks = super_block.inode_bitmap_blocks + super_block.inode_area_blocks; let efs = Self { block_device, inode_bitmap: Bitmap::new( 1, super_block.inode_bitmap_blocks as usize ), data_bitmap: Bitmap::new( (1 + inode_total_blocks) as usize, super_block.data_bitmap_blocks as usize, ), inode_area_start_block: 1 + super_block.inode_bitmap_blocks, data_area_start_block: 1 + inode_total_blocks + super_block.data_bitmap_blocks, }; Arc::new(Mutex::new(efs)) }) } pub fn root_inode(efs: &Arc>) -> Inode { let block_device = Arc::clone(&efs.lock().block_device); // acquire efs lock temporarily let (block_id, block_offset) = efs.lock().get_disk_inode_pos(0); // release efs lock Inode::new( block_id, block_offset, Arc::clone(efs), block_device, ) } pub fn get_disk_inode_pos(&self, inode_id: u32) -> (u32, usize) { let inode_size = core::mem::size_of::(); let inodes_per_block = (BLOCK_SZ / inode_size) as u32; let block_id = self.inode_area_start_block + inode_id / inodes_per_block; (block_id, (inode_id % inodes_per_block) as usize * inode_size) } pub fn get_data_block_id(&self, data_block_id: u32) -> u32 { self.data_area_start_block + data_block_id } pub fn alloc_inode(&mut self) -> u32 { self.inode_bitmap.alloc(&self.block_device).unwrap() as u32 } /// Return a block ID not ID in the data area. pub fn alloc_data(&mut self) -> u32 { self.data_bitmap.alloc(&self.block_device).unwrap() as u32 + self.data_area_start_block } pub fn dealloc_data(&mut self, block_id: u32) { get_block_cache( block_id as usize, Arc::clone(&self.block_device) ) .lock() .modify(0, |data_block: &mut DataBlock| { data_block.iter_mut().for_each(|p| { *p = 0; }) }); self.data_bitmap.dealloc( &self.block_device, (block_id - self.data_area_start_block) as usize ) } }