//! Mount teardown refuses live open, lookup, and cache-pin leases. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Error { InvalidMount, Busy, NoSpace, Stale, Overflow } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Kind { Open, Lookup, CachePin } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Token {volume: u8, generation: u64} impl Token { pub const fn volume(self) -> u8 { self.volume } pub const fn generation(self) -> u64 { self.generation } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Lease {token: Token, id: u64, kind: Kind} #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Counts {pub open: u8, pub lookup: u8, pub cache_pins: u8} #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Mount { token: Token, mounted: bool, leases: [Option; 3], next_id: u64, } impl Mount { pub fn new(volume: u8, generation: u64) -> Result { if volume == 0 || generation == 0 { return Err(Error::InvalidMount); } Ok(Self {token: Token {volume, generation}, mounted: true, leases: [None; 3], next_id: 1}) } pub const fn token(&self) -> Token { self.token } pub const fn mounted(&self) -> bool { self.mounted } pub fn counts(&self) -> Counts { let mut counts = Counts {open: 0, lookup: 0, cache_pins: 0}; for lease in self.leases.iter().flatten() { match lease.kind { Kind::Open => counts.open += 1, Kind::Lookup => counts.lookup += 1, Kind::CachePin => counts.cache_pins += 1, } } counts } pub fn validate(&self, token: Token) -> Result<(), Error> { if !self.mounted || token != self.token { return Err(Error::Stale); } Ok(()) } pub fn acquire(&mut self, kind: Kind) -> Result { if !self.mounted { return Err(Error::Stale); } let slot = self.leases.iter().position(Option::is_none) .ok_or(Error::NoSpace)?; let next = self.next_id.checked_add(1).ok_or(Error::Overflow)?; let lease = Lease {token: self.token, id: self.next_id, kind}; self.leases[slot] = Some(lease); self.next_id = next; Ok(lease) } pub fn release(&mut self, lease: Lease) -> Result<(), Error> { if lease.token != self.token { return Err(Error::Stale); } let slot = self.leases.iter().position(|entry| *entry == Some(lease)) .ok_or(Error::Stale)?; self.leases[slot] = None; Ok(()) } pub fn unmount(&mut self) -> Result { if !self.mounted { return Err(Error::Stale); } let counts = self.counts(); if counts.open != 0 || counts.lookup != 0 || counts.cache_pins != 0 { return Err(Error::Busy); } let next = self.token.generation.checked_add(1) .ok_or(Error::Overflow)?; self.mounted = false; self.token.generation = next; Ok(next) } pub fn remount(&mut self) -> Result { if self.mounted { return Err(Error::Busy); } if self.leases.iter().any(Option::is_some) { return Err(Error::Busy); } self.mounted = true; Ok(self.token) } }