use std::path::PathBuf;
use anyhow::bail;
use anyhow::Context;
use anyhow::Result;
use base::MappedRegion;
use base::MemoryMapping;
use base::MemoryMappingArena;
use base::MemoryMappingBuilder;
use base::Protection;
use base::SharedMemory;
use crate::arena::Arena;
use crate::arena::FileMappingInfo;
use crate::fs::Ext2;
use crate::BLOCK_SIZE;
pub struct Builder {
pub blocks_per_group: u32,
pub inodes_per_group: u32,
pub size: u32,
pub root_dir: Option<PathBuf>,
}
impl Default for Builder {
fn default() -> Self {
Self {
blocks_per_group: 4096,
inodes_per_group: 4096,
size: 4096 * 4096,
root_dir: None,
}
}
}
impl Builder {
fn validate(&mut self) -> Result<()> {
let block_group_size = BLOCK_SIZE as u32 * self.blocks_per_group;
if self.size < block_group_size {
bail!(
"memory size {} is too small to have a block group: block_size={}, block_per_group={}",
self.size,
BLOCK_SIZE,
block_group_size
);
}
if self.size % block_group_size != 0 {
self.size = self.size.next_multiple_of(block_group_size) - block_group_size
};
Ok(())
}
pub fn allocate_memory(mut self) -> Result<MemRegion> {
self.validate()
.context("failed to validate the ext2 config")?;
let mem = MemoryMappingBuilder::new(self.size as usize)
.build()
.context("failed to allocate memory for ext2")?;
Ok(MemRegion { cfg: self, mem })
}
pub fn build_on_shm(self, shm: &SharedMemory) -> Result<MemRegion> {
let mem = MemoryMappingBuilder::new(shm.size() as usize)
.from_shared_memory(shm)
.build()
.expect("failed to build MemoryMapping from shared memory");
Ok(MemRegion { cfg: self, mem })
}
}
pub struct MemRegion {
cfg: Builder,
mem: MemoryMapping,
}
impl MemRegion {
pub fn build_mmap_info(mut self) -> Result<MemRegionWithMappingInfo> {
let arena = Arena::new(BLOCK_SIZE, &mut self.mem).context("failed to allocate arena")?;
let mut ext2 = Ext2::new(&self.cfg, &arena).context("failed to create Ext2 struct")?;
if let Some(dir) = self.cfg.root_dir {
ext2.copy_dirtree(&arena, dir)
.context("failed to copy directory tree")?;
}
ext2.copy_backup_metadata(&arena)
.context("failed to copy metadata for backup")?;
let mapping_info = arena.into_mapping_info();
self.mem
.msync()
.context("failed to msyn of ext2's memory region")?;
Ok(MemRegionWithMappingInfo {
mem: self.mem,
mapping_info,
})
}
}
pub struct MemRegionWithMappingInfo {
mem: MemoryMapping,
pub mapping_info: Vec<FileMappingInfo>,
}
impl MemRegionWithMappingInfo {
pub fn do_mmap(self) -> Result<MemoryMappingArena> {
let mut mmap_arena = MemoryMappingArena::from(self.mem);
for FileMappingInfo {
mem_offset,
file,
length,
file_offset,
} in self.mapping_info
{
mmap_arena
.add_fd_mapping(
mem_offset,
length,
&file,
file_offset as u64, Protection::read(),
)
.context("failed mmaping an fd for ext2")?;
}
Ok(mmap_arena)
}
}