1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2024 The ChromiumOS Authors 2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file. 4*bb4ee6a4SAndroid Build Coastguard Worker 5*bb4ee6a4SAndroid Build Coastguard Worker //! Provides structs and logic to build ext2 file system with configurations. 6*bb4ee6a4SAndroid Build Coastguard Worker 7*bb4ee6a4SAndroid Build Coastguard Worker use std::path::PathBuf; 8*bb4ee6a4SAndroid Build Coastguard Worker 9*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::bail; 10*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context; 11*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Result; 12*bb4ee6a4SAndroid Build Coastguard Worker use base::MappedRegion; 13*bb4ee6a4SAndroid Build Coastguard Worker use base::MemoryMapping; 14*bb4ee6a4SAndroid Build Coastguard Worker use base::MemoryMappingArena; 15*bb4ee6a4SAndroid Build Coastguard Worker use base::MemoryMappingBuilder; 16*bb4ee6a4SAndroid Build Coastguard Worker use base::Protection; 17*bb4ee6a4SAndroid Build Coastguard Worker use base::SharedMemory; 18*bb4ee6a4SAndroid Build Coastguard Worker 19*bb4ee6a4SAndroid Build Coastguard Worker use crate::arena::Arena; 20*bb4ee6a4SAndroid Build Coastguard Worker use crate::arena::FileMappingInfo; 21*bb4ee6a4SAndroid Build Coastguard Worker use crate::fs::Ext2; 22*bb4ee6a4SAndroid Build Coastguard Worker use crate::BLOCK_SIZE; 23*bb4ee6a4SAndroid Build Coastguard Worker 24*bb4ee6a4SAndroid Build Coastguard Worker /// A struct to represent the configuration of an ext2 filesystem. 25*bb4ee6a4SAndroid Build Coastguard Worker pub struct Builder { 26*bb4ee6a4SAndroid Build Coastguard Worker /// The number of blocks per group. 27*bb4ee6a4SAndroid Build Coastguard Worker pub blocks_per_group: u32, 28*bb4ee6a4SAndroid Build Coastguard Worker /// The number of inodes per group. 29*bb4ee6a4SAndroid Build Coastguard Worker pub inodes_per_group: u32, 30*bb4ee6a4SAndroid Build Coastguard Worker /// The size of the memory region. 31*bb4ee6a4SAndroid Build Coastguard Worker pub size: u32, 32*bb4ee6a4SAndroid Build Coastguard Worker /// The roof directory to be copied to the file system. 33*bb4ee6a4SAndroid Build Coastguard Worker pub root_dir: Option<PathBuf>, 34*bb4ee6a4SAndroid Build Coastguard Worker } 35*bb4ee6a4SAndroid Build Coastguard Worker 36*bb4ee6a4SAndroid Build Coastguard Worker impl Default for Builder { default() -> Self37*bb4ee6a4SAndroid Build Coastguard Worker fn default() -> Self { 38*bb4ee6a4SAndroid Build Coastguard Worker Self { 39*bb4ee6a4SAndroid Build Coastguard Worker blocks_per_group: 4096, 40*bb4ee6a4SAndroid Build Coastguard Worker inodes_per_group: 4096, 41*bb4ee6a4SAndroid Build Coastguard Worker size: 4096 * 4096, 42*bb4ee6a4SAndroid Build Coastguard Worker root_dir: None, 43*bb4ee6a4SAndroid Build Coastguard Worker } 44*bb4ee6a4SAndroid Build Coastguard Worker } 45*bb4ee6a4SAndroid Build Coastguard Worker } 46*bb4ee6a4SAndroid Build Coastguard Worker 47*bb4ee6a4SAndroid Build Coastguard Worker impl Builder { 48*bb4ee6a4SAndroid Build Coastguard Worker /// Validates field values and adjusts them if needed. validate(&mut self) -> Result<()>49*bb4ee6a4SAndroid Build Coastguard Worker fn validate(&mut self) -> Result<()> { 50*bb4ee6a4SAndroid Build Coastguard Worker let block_group_size = BLOCK_SIZE as u32 * self.blocks_per_group; 51*bb4ee6a4SAndroid Build Coastguard Worker if self.size < block_group_size { 52*bb4ee6a4SAndroid Build Coastguard Worker bail!( 53*bb4ee6a4SAndroid Build Coastguard Worker "memory size {} is too small to have a block group: block_size={}, block_per_group={}", 54*bb4ee6a4SAndroid Build Coastguard Worker self.size, 55*bb4ee6a4SAndroid Build Coastguard Worker BLOCK_SIZE, 56*bb4ee6a4SAndroid Build Coastguard Worker block_group_size 57*bb4ee6a4SAndroid Build Coastguard Worker ); 58*bb4ee6a4SAndroid Build Coastguard Worker } 59*bb4ee6a4SAndroid Build Coastguard Worker if self.size % block_group_size != 0 { 60*bb4ee6a4SAndroid Build Coastguard Worker // Round down to the largest multiple of block_group_size that is smaller than self.size 61*bb4ee6a4SAndroid Build Coastguard Worker self.size = self.size.next_multiple_of(block_group_size) - block_group_size 62*bb4ee6a4SAndroid Build Coastguard Worker }; 63*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 64*bb4ee6a4SAndroid Build Coastguard Worker } 65*bb4ee6a4SAndroid Build Coastguard Worker 66*bb4ee6a4SAndroid Build Coastguard Worker /// Allocates memory region with the given configuration. allocate_memory(mut self) -> Result<MemRegion>67*bb4ee6a4SAndroid Build Coastguard Worker pub fn allocate_memory(mut self) -> Result<MemRegion> { 68*bb4ee6a4SAndroid Build Coastguard Worker self.validate() 69*bb4ee6a4SAndroid Build Coastguard Worker .context("failed to validate the ext2 config")?; 70*bb4ee6a4SAndroid Build Coastguard Worker let mem = MemoryMappingBuilder::new(self.size as usize) 71*bb4ee6a4SAndroid Build Coastguard Worker .build() 72*bb4ee6a4SAndroid Build Coastguard Worker .context("failed to allocate memory for ext2")?; 73*bb4ee6a4SAndroid Build Coastguard Worker Ok(MemRegion { cfg: self, mem }) 74*bb4ee6a4SAndroid Build Coastguard Worker } 75*bb4ee6a4SAndroid Build Coastguard Worker 76*bb4ee6a4SAndroid Build Coastguard Worker /// Builds memory region on the given shared memory. build_on_shm(self, shm: &SharedMemory) -> Result<MemRegion>77*bb4ee6a4SAndroid Build Coastguard Worker pub fn build_on_shm(self, shm: &SharedMemory) -> Result<MemRegion> { 78*bb4ee6a4SAndroid Build Coastguard Worker let mem = MemoryMappingBuilder::new(shm.size() as usize) 79*bb4ee6a4SAndroid Build Coastguard Worker .from_shared_memory(shm) 80*bb4ee6a4SAndroid Build Coastguard Worker .build() 81*bb4ee6a4SAndroid Build Coastguard Worker .expect("failed to build MemoryMapping from shared memory"); 82*bb4ee6a4SAndroid Build Coastguard Worker Ok(MemRegion { cfg: self, mem }) 83*bb4ee6a4SAndroid Build Coastguard Worker } 84*bb4ee6a4SAndroid Build Coastguard Worker } 85*bb4ee6a4SAndroid Build Coastguard Worker 86*bb4ee6a4SAndroid Build Coastguard Worker /// Memory region for ext2 with its config. 87*bb4ee6a4SAndroid Build Coastguard Worker pub struct MemRegion { 88*bb4ee6a4SAndroid Build Coastguard Worker cfg: Builder, 89*bb4ee6a4SAndroid Build Coastguard Worker mem: MemoryMapping, 90*bb4ee6a4SAndroid Build Coastguard Worker } 91*bb4ee6a4SAndroid Build Coastguard Worker 92*bb4ee6a4SAndroid Build Coastguard Worker impl MemRegion { 93*bb4ee6a4SAndroid Build Coastguard Worker /// Constructs an ext2 metadata by traversing `src_dir`. build_mmap_info(mut self) -> Result<MemRegionWithMappingInfo>94*bb4ee6a4SAndroid Build Coastguard Worker pub fn build_mmap_info(mut self) -> Result<MemRegionWithMappingInfo> { 95*bb4ee6a4SAndroid Build Coastguard Worker let arena = Arena::new(BLOCK_SIZE, &mut self.mem).context("failed to allocate arena")?; 96*bb4ee6a4SAndroid Build Coastguard Worker let mut ext2 = Ext2::new(&self.cfg, &arena).context("failed to create Ext2 struct")?; 97*bb4ee6a4SAndroid Build Coastguard Worker if let Some(dir) = self.cfg.root_dir { 98*bb4ee6a4SAndroid Build Coastguard Worker ext2.copy_dirtree(&arena, dir) 99*bb4ee6a4SAndroid Build Coastguard Worker .context("failed to copy directory tree")?; 100*bb4ee6a4SAndroid Build Coastguard Worker } 101*bb4ee6a4SAndroid Build Coastguard Worker ext2.copy_backup_metadata(&arena) 102*bb4ee6a4SAndroid Build Coastguard Worker .context("failed to copy metadata for backup")?; 103*bb4ee6a4SAndroid Build Coastguard Worker let mapping_info = arena.into_mapping_info(); 104*bb4ee6a4SAndroid Build Coastguard Worker 105*bb4ee6a4SAndroid Build Coastguard Worker self.mem 106*bb4ee6a4SAndroid Build Coastguard Worker .msync() 107*bb4ee6a4SAndroid Build Coastguard Worker .context("failed to msyn of ext2's memory region")?; 108*bb4ee6a4SAndroid Build Coastguard Worker Ok(MemRegionWithMappingInfo { 109*bb4ee6a4SAndroid Build Coastguard Worker mem: self.mem, 110*bb4ee6a4SAndroid Build Coastguard Worker mapping_info, 111*bb4ee6a4SAndroid Build Coastguard Worker }) 112*bb4ee6a4SAndroid Build Coastguard Worker } 113*bb4ee6a4SAndroid Build Coastguard Worker } 114*bb4ee6a4SAndroid Build Coastguard Worker 115*bb4ee6a4SAndroid Build Coastguard Worker /// Memory regions where ext2 metadata were written with information of mmap operations to be done. 116*bb4ee6a4SAndroid Build Coastguard Worker pub struct MemRegionWithMappingInfo { 117*bb4ee6a4SAndroid Build Coastguard Worker mem: MemoryMapping, 118*bb4ee6a4SAndroid Build Coastguard Worker pub mapping_info: Vec<FileMappingInfo>, 119*bb4ee6a4SAndroid Build Coastguard Worker } 120*bb4ee6a4SAndroid Build Coastguard Worker 121*bb4ee6a4SAndroid Build Coastguard Worker impl MemRegionWithMappingInfo { 122*bb4ee6a4SAndroid Build Coastguard Worker /// Do mmap and returns the memory region where ext2 was created. do_mmap(self) -> Result<MemoryMappingArena>123*bb4ee6a4SAndroid Build Coastguard Worker pub fn do_mmap(self) -> Result<MemoryMappingArena> { 124*bb4ee6a4SAndroid Build Coastguard Worker let mut mmap_arena = MemoryMappingArena::from(self.mem); 125*bb4ee6a4SAndroid Build Coastguard Worker for FileMappingInfo { 126*bb4ee6a4SAndroid Build Coastguard Worker mem_offset, 127*bb4ee6a4SAndroid Build Coastguard Worker file, 128*bb4ee6a4SAndroid Build Coastguard Worker length, 129*bb4ee6a4SAndroid Build Coastguard Worker file_offset, 130*bb4ee6a4SAndroid Build Coastguard Worker } in self.mapping_info 131*bb4ee6a4SAndroid Build Coastguard Worker { 132*bb4ee6a4SAndroid Build Coastguard Worker mmap_arena 133*bb4ee6a4SAndroid Build Coastguard Worker .add_fd_mapping( 134*bb4ee6a4SAndroid Build Coastguard Worker mem_offset, 135*bb4ee6a4SAndroid Build Coastguard Worker length, 136*bb4ee6a4SAndroid Build Coastguard Worker &file, 137*bb4ee6a4SAndroid Build Coastguard Worker file_offset as u64, /* fd_offset */ 138*bb4ee6a4SAndroid Build Coastguard Worker Protection::read(), 139*bb4ee6a4SAndroid Build Coastguard Worker ) 140*bb4ee6a4SAndroid Build Coastguard Worker .context("failed mmaping an fd for ext2")?; 141*bb4ee6a4SAndroid Build Coastguard Worker } 142*bb4ee6a4SAndroid Build Coastguard Worker 143*bb4ee6a4SAndroid Build Coastguard Worker Ok(mmap_arena) 144*bb4ee6a4SAndroid Build Coastguard Worker } 145*bb4ee6a4SAndroid Build Coastguard Worker } 146