Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions litebox/src/fs/composer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use super::errors::{
ChmodError, ChownError, FileStatusError, MkdirError, OpenError, PathError, ReadDirError,
ReadError, RmdirError, TruncateError, UnlinkError, WalkError, WriteError,
};
use super::inode_allocator::InodeAllocator;
use super::inode_allocator::{InodeAllocator, InodeAllocators};
use super::{DirEntry, FileStatus, FileType, Mode, NodeInfo, OFlags, UserInfo};
use crate::path::Arg;
use thiserror::Error;
Expand All @@ -37,7 +37,7 @@ pub struct Composer {
/// A [`Composer`] builder.
pub struct ComposerBuilder {
mounts: Vec<(Option<String>, Box<dyn Backend>)>,
next_backend_device_id: u64,
allocators: InodeAllocators,
}

/// A mounted backend.
Expand Down Expand Up @@ -70,7 +70,7 @@ impl Composer {
pub fn builder() -> ComposerBuilder {
ComposerBuilder {
mounts: vec![],
next_backend_device_id: 1,
allocators: InodeAllocators::starting_at(1),
}
}
}
Expand All @@ -79,16 +79,24 @@ impl ComposerBuilder {
/// Add a backend mounted at `path`.
#[must_use]
pub fn mount<B: Backend>(
mut self,
self,
path: impl Arg,
backend: impl FnOnce(InodeAllocator) -> B,
) -> Self {
let backend_device_id = self.next_backend_device_id;
self.mount_nestable(path, |allocators| backend(allocators.next()))
}

/// Add a backend mounted at `path`, which may draw an allocator per backend it is made of.
#[must_use]
pub fn mount_nestable<B: Backend>(
mut self,
path: impl Arg,
backend: impl FnOnce(&InodeAllocators) -> B,
) -> Self {
// TODO(jayb): Decide whether we need a fallible version of closure-based mount.
let backend = backend(InodeAllocator::for_device(backend_device_id));
let backend = backend(&self.allocators);
self.mounts
.push((path.as_rust_str().map(Into::into).ok(), Box::new(backend)));
self.next_backend_device_id = backend_device_id + 1;
self
}

Expand Down
28 changes: 24 additions & 4 deletions litebox/src/fs/inode_allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,27 @@ use core::sync::atomic::{AtomicU64, Ordering};

use super::NodeInfo;

/// Hands out [`InodeAllocator`]s, each with its own device id.
#[derive(Debug)]
pub struct InodeAllocators {
next_device_id: AtomicU64,
}

impl InodeAllocators {
/// Start handing out allocators, beginning at `first_device_id`.
pub(super) fn starting_at(first_device_id: u64) -> Self {
Self {
next_device_id: AtomicU64::new(first_device_id),
}
}

/// Hand out an allocator for one backend.
#[must_use]
pub fn next(&self) -> InodeAllocator {
InodeAllocator::for_device(self.next_device_id.fetch_add(1, Ordering::Relaxed))
}
}

/// Allocator for `(device_id, inode)` pairs scoped to one backend instance.
#[derive(Debug)]
pub struct InodeAllocator {
Expand All @@ -13,10 +34,9 @@ pub struct InodeAllocator {
}

impl InodeAllocator {
/// Construct an allocator for a specific `device_id`. The composer hands
/// out unique `device_id`s per mounted backend.
/// Construct an allocator for a specific `device_id`.
#[must_use]
pub fn for_device(device_id: u64) -> Self {
pub(super) fn for_device(device_id: u64) -> Self {
Self {
device_id,
counter: AtomicU64::new(1),
Expand All @@ -27,7 +47,7 @@ impl InodeAllocator {
///
/// This should (eventually) disappear once we have better device ID allocation setup.
#[must_use]
pub fn standalone() -> Self {
pub(crate) fn standalone() -> Self {
// `b"Stnd".hex()`
const STANDALONE_DEVICE_ID: u64 = 0x53746e64;
Self::for_device(STANDALONE_DEVICE_ID)
Expand Down
Loading