diff --git a/rcore-fs-fuse/src/main.rs b/rcore-fs-fuse/src/main.rs index 4e835f4..bc7ddb6 100644 --- a/rcore-fs-fuse/src/main.rs +++ b/rcore-fs-fuse/src/main.rs @@ -65,7 +65,7 @@ fn main() { .open(&opt.image) .expect("failed to open image"); let device = Mutex::new(file); - const MAX_SPACE: usize = 0x1000 * 0x1000 * 8; // 128MB (4K bitmap) + const MAX_SPACE: usize = 0x1000 * 0x1000 * 1024; // 1G match create { true => sfs::SimpleFileSystem::create(Arc::new(device), MAX_SPACE), false => sfs::SimpleFileSystem::open(Arc::new(device)).expect("failed to open sfs"), diff --git a/rcore-fs-sfs/src/lib.rs b/rcore-fs-sfs/src/lib.rs index f18400f..f301625 100644 --- a/rcore-fs-sfs/src/lib.rs +++ b/rcore-fs-sfs/src/lib.rs @@ -11,6 +11,7 @@ use alloc::{ string::String, sync::{Arc, Weak}, vec::Vec, + vec, }; use core::any::Any; use core::fmt::{Debug, Error, Formatter}; @@ -683,11 +684,14 @@ impl SimpleFileSystem { if !super_block.check() { return Err(FsError::WrongFs); } - let free_map = device.load_struct::<[u8; BLKSIZE]>(BLKN_FREEMAP).unwrap(); + let mut freemap_disk = vec![0u8; BLKSIZE * super_block.freemap_blocks as usize]; + for i in 0..super_block.freemap_blocks as usize { + device.read_block(BLKN_FREEMAP + i, 0, &mut freemap_disk[i * BLKSIZE..(i+1) *BLKSIZE])?; + } Ok(SimpleFileSystem { super_block: RwLock::new(Dirty::new(super_block)), - free_map: RwLock::new(Dirty::new(BitVec::from(free_map.as_ref()))), + free_map: RwLock::new(Dirty::new(BitVec::from(freemap_disk.as_slice()))), inodes: RwLock::new(BTreeMap::new()), device, self_ptr: Weak::default(), @@ -696,19 +700,21 @@ impl SimpleFileSystem { } /// Create a new SFS on blank disk pub fn create(device: Arc, space: usize) -> Arc { - let blocks = (space / BLKSIZE).min(BLKBITS); + let blocks = (space + BLKSIZE - 1) / BLKSIZE; + let freemap_blocks = (space + BLKBITS * BLKSIZE - 1) / BLKBITS / BLKSIZE; assert!(blocks >= 16, "space too small"); let super_block = SuperBlock { magic: MAGIC, blocks: blocks as u32, - unused_blocks: blocks as u32 - 3, + unused_blocks: (blocks - BLKN_FREEMAP - freemap_blocks) as u32, info: Str32::from(DEFAULT_INFO), + freemap_blocks: freemap_blocks as u32, }; let free_map = { - let mut bitset = BitVec::with_capacity(BLKBITS); - bitset.extend(core::iter::repeat(false).take(BLKBITS)); - for i in 3..blocks { + let mut bitset = BitVec::with_capacity(freemap_blocks * BLKBITS); + bitset.extend(core::iter::repeat(false).take(freemap_blocks * BLKBITS)); + for i in (BLKN_FREEMAP + freemap_blocks)..blocks { bitset.set(i, true); } bitset @@ -753,11 +759,16 @@ impl SimpleFileSystem { if let Some(block_id) = id { let mut super_block = self.super_block.write(); if super_block.unused_blocks == 0 { + let super_block = self.super_block.read(); + panic!("{:?}", super_block); free_map.set(block_id, true); return None; } super_block.unused_blocks -= 1; // will not underflow trace!("alloc block {:#x}", block_id); + } else { + let super_block = self.super_block.read(); + panic!("{:?}", super_block) } id } @@ -841,9 +852,12 @@ impl vfs::FileSystem for SimpleFileSystem { } let mut free_map = self.free_map.write(); if free_map.dirty() { - self.device - .write_at(BLKSIZE * BLKN_FREEMAP, free_map.as_buf()) - .unwrap(); + let data = free_map.as_buf(); + for i in 0..super_block.freemap_blocks as usize { + self.device + .write_at(BLKSIZE * (BLKN_FREEMAP + i), &data[i * BLKSIZE..(i+1) * BLKSIZE]) + .unwrap(); + } free_map.sync(); } self.flush_weak_inodes(); diff --git a/rcore-fs-sfs/src/structs.rs b/rcore-fs-sfs/src/structs.rs index a192db8..4fa9bc0 100644 --- a/rcore-fs-sfs/src/structs.rs +++ b/rcore-fs-sfs/src/structs.rs @@ -18,6 +18,8 @@ pub struct SuperBlock { pub unused_blocks: u32, /// information for sfs pub info: Str32, + /// number of freemap blocks + pub freemap_blocks: u32, } /// inode (on disk) @@ -186,9 +188,8 @@ pub const DEFAULT_INFO: &str = "simple file system"; pub const MAX_INFO_LEN: usize = 31; /// max length of filename pub const MAX_FNAME_LEN: usize = 255; -/// max file size in theory (48KB + 4MB + 4GB), but freemap is not large enough -/// max file size (128M), 128M = 8 * 4096 * 4096 -pub const MAX_FILE_SIZE: usize = 1024 * 1024 * 128; +/// max file size in theory (48KB + 4MB + 4GB) +pub const MAX_FILE_SIZE: usize = 48 * 1024 + 4 * 1024 * 1024 + 4 * 1024 * 1024 * 1024; /// block the superblock lives in pub const BLKN_SUPER: BlockId = 0; /// location of the root dir inode diff --git a/rcore-fs-sfs/src/tests.rs b/rcore-fs-sfs/src/tests.rs index fdbf54c..e2d195b 100644 --- a/rcore-fs-sfs/src/tests.rs +++ b/rcore-fs-sfs/src/tests.rs @@ -43,7 +43,7 @@ fn create_file() -> Result<()> { assert_eq!( file1.metadata()?, Metadata { - inode: 5, + inode: 8, size: 0, type_: FileType::File, mode: 0o777, @@ -102,7 +102,7 @@ fn resize_too_large_should_panic() -> Result<()> { let sfs = _create_new_sfs(); let root = sfs.root_inode(); let file1 = root.create("file1", FileType::File, 0o777)?; - assert!(file1.resize(1 << 28).is_err()); + assert!(file1.resize(1 << 40).is_err()); sfs.sync()?; Ok(()) @@ -261,16 +261,18 @@ fn test_double_indirect_blocks() -> Result<()> { file1.resize(MAX_NBLOCK_INDIRECT * BLKSIZE).unwrap(); // force usage of double indirect block file1.resize((MAX_NBLOCK_INDIRECT + 1) * BLKSIZE).unwrap(); - file1.resize(MAX_FILE_SIZE / 8).unwrap(); + file1.resize((MAX_NBLOCK_INDIRECT + 2) * BLKSIZE).unwrap(); // resize up and down file1.resize(0).unwrap(); + file1.resize((MAX_NBLOCK_INDIRECT + 2) * BLKSIZE).unwrap(); file1.resize(MAX_NBLOCK_DIRECT * BLKSIZE).unwrap(); file1.resize((MAX_NBLOCK_DIRECT + 1) * BLKSIZE).unwrap(); file1.resize(MAX_NBLOCK_DIRECT * BLKSIZE).unwrap(); file1.resize(0).unwrap(); file1.resize((MAX_NBLOCK_INDIRECT + 1) * BLKSIZE).unwrap(); file1.resize(MAX_NBLOCK_DIRECT * BLKSIZE).unwrap(); + file1.resize((MAX_NBLOCK_INDIRECT + 2) * BLKSIZE).unwrap(); file1.resize((MAX_NBLOCK_INDIRECT + 1) * BLKSIZE).unwrap(); file1.resize(0).unwrap();