Implement multiple freemap blocks

master
Jiajie Chen 6 years ago
parent 807a5d3dac
commit 9c0aeb1e66

@ -65,7 +65,7 @@ fn main() {
.open(&opt.image) .open(&opt.image)
.expect("failed to open image"); .expect("failed to open image");
let device = Mutex::new(file); 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 { match create {
true => sfs::SimpleFileSystem::create(Arc::new(device), MAX_SPACE), true => sfs::SimpleFileSystem::create(Arc::new(device), MAX_SPACE),
false => sfs::SimpleFileSystem::open(Arc::new(device)).expect("failed to open sfs"), false => sfs::SimpleFileSystem::open(Arc::new(device)).expect("failed to open sfs"),

@ -11,6 +11,7 @@ use alloc::{
string::String, string::String,
sync::{Arc, Weak}, sync::{Arc, Weak},
vec::Vec, vec::Vec,
vec,
}; };
use core::any::Any; use core::any::Any;
use core::fmt::{Debug, Error, Formatter}; use core::fmt::{Debug, Error, Formatter};
@ -683,11 +684,14 @@ impl SimpleFileSystem {
if !super_block.check() { if !super_block.check() {
return Err(FsError::WrongFs); 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 { Ok(SimpleFileSystem {
super_block: RwLock::new(Dirty::new(super_block)), 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()), inodes: RwLock::new(BTreeMap::new()),
device, device,
self_ptr: Weak::default(), self_ptr: Weak::default(),
@ -696,19 +700,21 @@ impl SimpleFileSystem {
} }
/// Create a new SFS on blank disk /// Create a new SFS on blank disk
pub fn create(device: Arc<Device>, space: usize) -> Arc<Self> { pub fn create(device: Arc<Device>, space: usize) -> Arc<Self> {
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"); assert!(blocks >= 16, "space too small");
let super_block = SuperBlock { let super_block = SuperBlock {
magic: MAGIC, magic: MAGIC,
blocks: blocks as u32, blocks: blocks as u32,
unused_blocks: blocks as u32 - 3, unused_blocks: (blocks - BLKN_FREEMAP - freemap_blocks) as u32,
info: Str32::from(DEFAULT_INFO), info: Str32::from(DEFAULT_INFO),
freemap_blocks: freemap_blocks as u32,
}; };
let free_map = { let free_map = {
let mut bitset = BitVec::with_capacity(BLKBITS); let mut bitset = BitVec::with_capacity(freemap_blocks * BLKBITS);
bitset.extend(core::iter::repeat(false).take(BLKBITS)); bitset.extend(core::iter::repeat(false).take(freemap_blocks * BLKBITS));
for i in 3..blocks { for i in (BLKN_FREEMAP + freemap_blocks)..blocks {
bitset.set(i, true); bitset.set(i, true);
} }
bitset bitset
@ -753,11 +759,16 @@ impl SimpleFileSystem {
if let Some(block_id) = id { if let Some(block_id) = id {
let mut super_block = self.super_block.write(); let mut super_block = self.super_block.write();
if super_block.unused_blocks == 0 { if super_block.unused_blocks == 0 {
let super_block = self.super_block.read();
panic!("{:?}", super_block);
free_map.set(block_id, true); free_map.set(block_id, true);
return None; return None;
} }
super_block.unused_blocks -= 1; // will not underflow super_block.unused_blocks -= 1; // will not underflow
trace!("alloc block {:#x}", block_id); trace!("alloc block {:#x}", block_id);
} else {
let super_block = self.super_block.read();
panic!("{:?}", super_block)
} }
id id
} }
@ -841,9 +852,12 @@ impl vfs::FileSystem for SimpleFileSystem {
} }
let mut free_map = self.free_map.write(); let mut free_map = self.free_map.write();
if free_map.dirty() { if free_map.dirty() {
self.device let data = free_map.as_buf();
.write_at(BLKSIZE * BLKN_FREEMAP, free_map.as_buf()) for i in 0..super_block.freemap_blocks as usize {
.unwrap(); self.device
.write_at(BLKSIZE * (BLKN_FREEMAP + i), &data[i * BLKSIZE..(i+1) * BLKSIZE])
.unwrap();
}
free_map.sync(); free_map.sync();
} }
self.flush_weak_inodes(); self.flush_weak_inodes();

@ -18,6 +18,8 @@ pub struct SuperBlock {
pub unused_blocks: u32, pub unused_blocks: u32,
/// information for sfs /// information for sfs
pub info: Str32, pub info: Str32,
/// number of freemap blocks
pub freemap_blocks: u32,
} }
/// inode (on disk) /// inode (on disk)
@ -186,9 +188,8 @@ pub const DEFAULT_INFO: &str = "simple file system";
pub const MAX_INFO_LEN: usize = 31; pub const MAX_INFO_LEN: usize = 31;
/// max length of filename /// max length of filename
pub const MAX_FNAME_LEN: usize = 255; pub const MAX_FNAME_LEN: usize = 255;
/// max file size in theory (48KB + 4MB + 4GB), but freemap is not large enough /// max file size in theory (48KB + 4MB + 4GB)
/// max file size (128M), 128M = 8 * 4096 * 4096 pub const MAX_FILE_SIZE: usize = 48 * 1024 + 4 * 1024 * 1024 + 4 * 1024 * 1024 * 1024;
pub const MAX_FILE_SIZE: usize = 1024 * 1024 * 128;
/// block the superblock lives in /// block the superblock lives in
pub const BLKN_SUPER: BlockId = 0; pub const BLKN_SUPER: BlockId = 0;
/// location of the root dir inode /// location of the root dir inode

@ -43,7 +43,7 @@ fn create_file() -> Result<()> {
assert_eq!( assert_eq!(
file1.metadata()?, file1.metadata()?,
Metadata { Metadata {
inode: 5, inode: 8,
size: 0, size: 0,
type_: FileType::File, type_: FileType::File,
mode: 0o777, mode: 0o777,
@ -102,7 +102,7 @@ fn resize_too_large_should_panic() -> Result<()> {
let sfs = _create_new_sfs(); let sfs = _create_new_sfs();
let root = sfs.root_inode(); let root = sfs.root_inode();
let file1 = root.create("file1", FileType::File, 0o777)?; let file1 = root.create("file1", FileType::File, 0o777)?;
assert!(file1.resize(1 << 28).is_err()); assert!(file1.resize(1 << 40).is_err());
sfs.sync()?; sfs.sync()?;
Ok(()) Ok(())
@ -261,16 +261,18 @@ fn test_double_indirect_blocks() -> Result<()> {
file1.resize(MAX_NBLOCK_INDIRECT * BLKSIZE).unwrap(); file1.resize(MAX_NBLOCK_INDIRECT * BLKSIZE).unwrap();
// force usage of double indirect block // force usage of double indirect block
file1.resize((MAX_NBLOCK_INDIRECT + 1) * BLKSIZE).unwrap(); 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 // resize up and down
file1.resize(0).unwrap(); file1.resize(0).unwrap();
file1.resize((MAX_NBLOCK_INDIRECT + 2) * BLKSIZE).unwrap();
file1.resize(MAX_NBLOCK_DIRECT * BLKSIZE).unwrap(); file1.resize(MAX_NBLOCK_DIRECT * BLKSIZE).unwrap();
file1.resize((MAX_NBLOCK_DIRECT + 1) * BLKSIZE).unwrap(); file1.resize((MAX_NBLOCK_DIRECT + 1) * BLKSIZE).unwrap();
file1.resize(MAX_NBLOCK_DIRECT * BLKSIZE).unwrap(); file1.resize(MAX_NBLOCK_DIRECT * BLKSIZE).unwrap();
file1.resize(0).unwrap(); file1.resize(0).unwrap();
file1.resize((MAX_NBLOCK_INDIRECT + 1) * BLKSIZE).unwrap(); file1.resize((MAX_NBLOCK_INDIRECT + 1) * BLKSIZE).unwrap();
file1.resize(MAX_NBLOCK_DIRECT * 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((MAX_NBLOCK_INDIRECT + 1) * BLKSIZE).unwrap();
file1.resize(0).unwrap(); file1.resize(0).unwrap();

Loading…
Cancel
Save