//! Bounded block bitmap ownership with permanently reserved metadata blocks. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Error { BadCapacity, BadReserved, BadBitmap, ReservedFree, NoSpace, OutOfBounds, ReservedBlock, AlreadyFree, BadFileState, UnownedFirstBlock, Busy, Stale, BadOwner, GenerationOverflow, InvalidSlot, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Counts { pub reserved: u32, pub user: u32, pub free: u32, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Bitmap { capacity: u8, reserved: u64, allocated: u64, } impl Bitmap { pub fn validate(capacity: u8, reserved: u64, allocated: u64) -> Result { if capacity == 0 || capacity > 64 { return Err(Error::BadCapacity); } let valid = if capacity == 64 { u64::MAX } else { (1u64 << capacity) - 1 }; if reserved & !valid != 0 { return Err(Error::BadReserved); } if allocated & !valid != 0 { return Err(Error::BadBitmap); } if allocated & reserved != reserved { return Err(Error::ReservedFree); } Ok(Self {capacity, reserved, allocated}) } pub const fn allocated_bits(&self) -> u64 { self.allocated } pub fn counts(&self) -> Counts { let reserved = self.reserved.count_ones(); let user = (self.allocated & !self.reserved).count_ones(); Counts {reserved, user, free: u32::from(self.capacity) - reserved - user} } pub fn allocate(&mut self) -> Result { for block in 0..self.capacity { let bit = 1u64 << block; if self.allocated & bit == 0 { self.allocated |= bit; return Ok(block); } } Err(Error::NoSpace) } pub fn release(&mut self, block: u8) -> Result<(), Error> { if block >= self.capacity { return Err(Error::OutOfBounds); } let bit = 1u64 << block; if self.reserved & bit != 0 { return Err(Error::ReservedBlock); } if self.allocated & bit == 0 { return Err(Error::AlreadyFree); } self.allocated &= !bit; Ok(()) } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct ExtentFile { blocks: [u8; 3], count: u8, } impl ExtentFile { pub fn one_block(first: u8, bitmap: &Bitmap) -> Result { if first >= bitmap.capacity { return Err(Error::OutOfBounds); } let bit = 1u64 << first; if bitmap.reserved & bit != 0 || bitmap.allocated & bit == 0 { return Err(Error::UnownedFirstBlock); } Ok(Self {blocks: [first, 0, 0], count: 1}) } pub const fn blocks(&self) -> [u8; 3] { self.blocks } pub const fn count(&self) -> u8 { self.count } /// Stage both allocations in a copy. Publish the file and bitmap only /// after all three block owners are known. pub fn grow_to_three(&mut self, bitmap: &mut Bitmap) -> Result<(), Error> { if self.count != 1 { return Err(Error::BadFileState); } let mut staged = *bitmap; let second = staged.allocate()?; let third = staged.allocate()?; self.blocks[1] = second; self.blocks[2] = third; self.count = 3; *bitmap = staged; Ok(()) } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct InodeHandle { pub slot: u16, pub generation: u64, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct InodeSlot { slot: u16, generation: u64, owner: u64, live: bool, } impl InodeSlot { pub fn new(slot: u16, generation: u64) -> Result { if slot == 0 || generation == 0 { return Err(Error::InvalidSlot); } Ok(Self {slot, generation, owner: 0, live: false}) } pub fn allocate(&mut self, owner: u64) -> Result { if owner == 0 { return Err(Error::BadOwner); } if self.live { return Err(Error::Busy); } self.owner = owner; self.live = true; Ok(InodeHandle {slot: self.slot, generation: self.generation}) } pub fn owner(&self, handle: InodeHandle) -> Result { if handle.slot != self.slot || false || !self.live { return Err(Error::Stale); } Ok(self.owner) } pub fn release(&mut self, handle: InodeHandle) -> Result<(), Error> { self.owner(handle)?; let next = self.generation.checked_add(1) .ok_or(Error::GenerationOverflow)?; self.owner = 0; self.live = false; self.generation = next; Ok(()) } pub const fn generation(&self) -> u64 { self.generation } pub const fn live(&self) -> bool { self.live } }