Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/ext2/src/builder.rs
5394 views
1
// Copyright 2024 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
//! Provides structs and logic to build ext2 file system with configurations.
6
7
use std::path::PathBuf;
8
9
use anyhow::bail;
10
use anyhow::Context;
11
use anyhow::Result;
12
use base::MappedRegion;
13
use base::MemoryMapping;
14
use base::MemoryMappingArena;
15
use base::MemoryMappingBuilder;
16
use base::Protection;
17
use base::SharedMemory;
18
19
use crate::arena::Arena;
20
use crate::arena::FileMappingInfo;
21
use crate::fs::Ext2;
22
use crate::BLOCK_SIZE;
23
24
/// A struct to represent the configuration of an ext2 filesystem.
25
pub struct Builder {
26
/// The number of blocks per group.
27
pub blocks_per_group: u32,
28
/// The number of inodes per group.
29
pub inodes_per_group: u32,
30
/// The size of the memory region.
31
pub size: u32,
32
/// The roof directory to be copied to the file system.
33
pub root_dir: Option<PathBuf>,
34
}
35
36
impl 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
47
impl Builder {
48
/// Validates field values and adjusts them if needed.
49
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
// Round down to the largest multiple of block_group_size that is smaller than self.size
61
self.size = self.size.next_multiple_of(block_group_size) - block_group_size
62
};
63
Ok(())
64
}
65
66
/// Allocates memory region with the given configuration.
67
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
/// Builds memory region on the given shared memory.
77
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
86
/// Memory region for ext2 with its config.
87
pub struct MemRegion {
88
cfg: Builder,
89
mem: MemoryMapping,
90
}
91
92
impl MemRegion {
93
/// Constructs an ext2 metadata by traversing `src_dir`.
94
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
115
/// Memory regions where ext2 metadata were written with information of mmap operations to be done.
116
pub struct MemRegionWithMappingInfo {
117
mem: MemoryMapping,
118
pub mapping_info: Vec<FileMappingInfo>,
119
}
120
121
impl MemRegionWithMappingInfo {
122
/// Do mmap and returns the memory region where ext2 was created.
123
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, /* fd_offset */
138
Protection::read(),
139
)
140
.context("failed mmaping an fd for ext2")?;
141
}
142
143
Ok(mmap_arena)
144
}
145
}
146
147