1use std::path::PathBuf;
8
9use anyhow::bail;
10use anyhow::Context;
11use anyhow::Result;
12use base::MappedRegion;
13use base::MemoryMapping;
14use base::MemoryMappingArena;
15use base::MemoryMappingBuilder;
16use base::Protection;
17use base::SharedMemory;
18
19use crate::arena::Arena;
20use crate::arena::FileMappingInfo;
21use crate::fs::Ext2;
22use crate::BLOCK_SIZE;
23
24pub struct Builder {
26 pub blocks_per_group: u32,
28 pub inodes_per_group: u32,
30 pub size: u32,
32 pub root_dir: Option<PathBuf>,
34}
35
36impl Default for Builder {
37 fn default() -> Self {
38 Self {
39 blocks_per_group: 4096,
40 inodes_per_group: 4096,
41 size: 4096 * 4096,
42 root_dir: None,
43 }
44 }
45}
46
47impl Builder {
48 fn validate(&mut self) -> Result<()> {
50 let block_group_size = BLOCK_SIZE as u32 * self.blocks_per_group;
51 if self.size < block_group_size {
52 bail!(
53 "memory size {} is too small to have a block group: block_size={}, block_per_group={}",
54 self.size,
55 BLOCK_SIZE,
56 block_group_size
57 );
58 }
59 if self.size % block_group_size != 0 {
60 self.size = self.size.next_multiple_of(block_group_size) - block_group_size
62 };
63 Ok(())
64 }
65
66 pub fn allocate_memory(mut self) -> Result<MemRegion> {
68 self.validate()
69 .context("failed to validate the ext2 config")?;
70 let mem = MemoryMappingBuilder::new(self.size as usize)
71 .build()
72 .context("failed to allocate memory for ext2")?;
73 Ok(MemRegion { cfg: self, mem })
74 }
75
76 pub fn build_on_shm(self, shm: &SharedMemory) -> Result<MemRegion> {
78 let mem = MemoryMappingBuilder::new(shm.size() as usize)
79 .from_shared_memory(shm)
80 .build()
81 .expect("failed to build MemoryMapping from shared memory");
82 Ok(MemRegion { cfg: self, mem })
83 }
84}
85
86pub struct MemRegion {
88 cfg: Builder,
89 mem: MemoryMapping,
90}
91
92impl MemRegion {
93 pub fn build_mmap_info(mut self) -> Result<MemRegionWithMappingInfo> {
95 let arena = Arena::new(BLOCK_SIZE, &mut self.mem).context("failed to allocate arena")?;
96 let mut ext2 = Ext2::new(&self.cfg, &arena).context("failed to create Ext2 struct")?;
97 if let Some(dir) = self.cfg.root_dir {
98 ext2.copy_dirtree(&arena, dir)
99 .context("failed to copy directory tree")?;
100 }
101 ext2.copy_backup_metadata(&arena)
102 .context("failed to copy metadata for backup")?;
103 let mapping_info = arena.into_mapping_info();
104
105 self.mem
106 .msync()
107 .context("failed to msyn of ext2's memory region")?;
108 Ok(MemRegionWithMappingInfo {
109 mem: self.mem,
110 mapping_info,
111 })
112 }
113}
114
115pub struct MemRegionWithMappingInfo {
117 mem: MemoryMapping,
118 pub mapping_info: Vec<FileMappingInfo>,
119}
120
121impl MemRegionWithMappingInfo {
122 pub fn do_mmap(self) -> Result<MemoryMappingArena> {
124 let mut mmap_arena = MemoryMappingArena::from(self.mem);
125 for FileMappingInfo {
126 mem_offset,
127 file,
128 length,
129 file_offset,
130 } in self.mapping_info
131 {
132 mmap_arena
133 .add_fd_mapping(
134 mem_offset,
135 length,
136 &file,
137 file_offset as u64, Protection::read(),
139 )
140 .context("failed mmaping an fd for ext2")?;
141 }
142
143 Ok(mmap_arena)
144 }
145}