diff --git a/doc/filesystem.md b/doc/filesystem.md index 98ba58455..a69f57da7 100644 --- a/doc/filesystem.md +++ b/doc/filesystem.md @@ -10,9 +10,9 @@ A hard drive is separated in blocks of 512 bytes, grouped into 4 areas: +------------+ | Superblock | (2 blocks) +------------+ - | Bitmap | (n / (8 * 512) blocks) + | Bitmap | (n blocks) +------------+ - | Data | (n blocks) + | Data | (n * 512 * 8 blocks) +------------+ The first area contains the bootloader and the kernel, the second is a diff --git a/src/sys/fs/bitmap_block.rs b/src/sys/fs/bitmap_block.rs index e74009477..08da93569 100644 --- a/src/sys/fs/bitmap_block.rs +++ b/src/sys/fs/bitmap_block.rs @@ -42,6 +42,10 @@ impl BitmapBlock { pub fn next_free_addr() -> Option { let sb = SuperBlock::read(); + if sb.alloc_count() == sb.block_count() { + return None; + } + let n = sb.block_size(); let m = sb.block_count() / n / 8; for i in 0..m { diff --git a/src/sys/fs/dir.rs b/src/sys/fs/dir.rs index b7951fc43..c5e0fe926 100644 --- a/src/sys/fs/dir.rs +++ b/src/sys/fs/dir.rs @@ -120,15 +120,18 @@ impl Dir { if entry_len > space_left { match entries.block.alloc_next() { None => return None, // Disk is full - Some(new_block) => { - entries.block = new_block; + Some(block) => { + entries.block = block; entries.block_offset = 0; } } } // Create a new entry - let entry_block = LinkedBlock::alloc().unwrap(); + let entry_block = match LinkedBlock::alloc() { + None => return None, + Some(block) => block, + }; let entry_kind = kind as u8; let entry_addr = entry_block.addr(); let entry_size = 0u32; diff --git a/src/sys/fs/mod.rs b/src/sys/fs/mod.rs index a55a17361..992d9c6c9 100644 --- a/src/sys/fs/mod.rs +++ b/src/sys/fs/mod.rs @@ -26,7 +26,7 @@ use super_block::SuperBlock; use alloc::string::{String, ToString}; -pub const VERSION: u8 = 1; +pub const VERSION: u8 = 2; // TODO: Move that to API #[derive(Clone, Copy)] @@ -157,11 +157,11 @@ pub fn canonicalize(path: &str) -> Result { } pub fn disk_size() -> usize { - (SuperBlock::read().block_count as usize) * BLOCK_SIZE + (SuperBlock::read().block_count() as usize) * BLOCK_SIZE } pub fn disk_used() -> usize { - (SuperBlock::read().alloc_count as usize) * BLOCK_SIZE + (SuperBlock::read().alloc_count() as usize) * BLOCK_SIZE } pub fn disk_free() -> usize { diff --git a/src/sys/fs/super_block.rs b/src/sys/fs/super_block.rs index 011b29d95..9b3b0f56e 100644 --- a/src/sys/fs/super_block.rs +++ b/src/sys/fs/super_block.rs @@ -12,8 +12,8 @@ pub struct SuperBlock { signature: &'static [u8; 8], version: u8, block_size: u32, - pub block_count: u32, - pub alloc_count: u32, + block_count: u32, + alloc_count: u32, } impl SuperBlock { @@ -27,13 +27,18 @@ impl SuperBlock { pub fn new() -> Option { if let Some(ref dev) = *super::block_device::BLOCK_DEVICE.lock() { - Some(Self { + let mut sb = Self { signature: SIGNATURE, version: super::VERSION, block_size: dev.block_size() as u32, block_count: dev.block_count() as u32, alloc_count: 0, - }) + }; + + // Reserved blocks + sb.alloc_count = sb.data_area(); + + Some(sb) } else { None } @@ -78,16 +83,33 @@ impl SuperBlock { self.block_count } + pub fn alloc_count(&self) -> u32 { + self.alloc_count + } + pub fn bitmap_area(&self) -> u32 { SUPERBLOCK_ADDR + 2 } pub fn data_area(&self) -> u32 { - let bs = super::BITMAP_SIZE as u32; - let total = self.block_count; - let offset = self.bitmap_area(); - let rest = (total - offset) * bs / (bs + 1); - self.bitmap_area() + rest / bs + let s = self.block_size * 8; + let n = self.block_count; + let a = self.bitmap_area(); + + if self.version == 1 { + a + ((n - a) / (s + 1)) // Incorrect formula fixed in v2 + } else { + let mut p; // Previous bitmap count + let mut b = 0; // Bitmap count + loop { + p = b; + b = (n - (a + b) + s - 1) / s; + if b == p { + break; + } + } + a + b + } } } @@ -99,6 +121,6 @@ pub fn inc_alloc_count() { pub fn dec_alloc_count() { let mut sb = SuperBlock::read(); - sb.alloc_count -= 1; + sb.alloc_count -= 1; // FIXME: Use saturating substraction sb.write(); }