xref: /aosp_15_r20/external/crosvm/ext2/src/superblock.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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 //! Defines the superblock structure.
6*bb4ee6a4SAndroid Build Coastguard Worker 
7*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Result;
8*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::AsBytes;
9*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy_derive::FromBytes;
10*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy_derive::FromZeroes;
11*bb4ee6a4SAndroid Build Coastguard Worker 
12*bb4ee6a4SAndroid Build Coastguard Worker use crate::arena::Arena;
13*bb4ee6a4SAndroid Build Coastguard Worker use crate::arena::BlockId;
14*bb4ee6a4SAndroid Build Coastguard Worker use crate::blockgroup::BLOCK_SIZE;
15*bb4ee6a4SAndroid Build Coastguard Worker use crate::builder::Builder;
16*bb4ee6a4SAndroid Build Coastguard Worker use crate::inode::Inode;
17*bb4ee6a4SAndroid Build Coastguard Worker 
18*bb4ee6a4SAndroid Build Coastguard Worker /// A struct to represent the configuration of an ext2 filesystem.
19*bb4ee6a4SAndroid Build Coastguard Worker 
20*bb4ee6a4SAndroid Build Coastguard Worker /// The ext2 superblock.
21*bb4ee6a4SAndroid Build Coastguard Worker ///
22*bb4ee6a4SAndroid Build Coastguard Worker /// The field names are based on [the specification](https://www.nongnu.org/ext2-doc/ext2.html#superblock).
23*bb4ee6a4SAndroid Build Coastguard Worker /// Note that this struct only holds the fields at the beginning of the superblock. All fields after
24*bb4ee6a4SAndroid Build Coastguard Worker /// the fields supported by this structure are filled with zeros.
25*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
26*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Default, Debug, Copy, Clone, FromZeroes, FromBytes, AsBytes)]
27*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) struct SuperBlock {
28*bb4ee6a4SAndroid Build Coastguard Worker     pub inodes_count: u32,
29*bb4ee6a4SAndroid Build Coastguard Worker     pub blocks_count: u32,
30*bb4ee6a4SAndroid Build Coastguard Worker     _r_blocks_count: u32,
31*bb4ee6a4SAndroid Build Coastguard Worker     pub free_blocks_count: u32,
32*bb4ee6a4SAndroid Build Coastguard Worker     pub free_inodes_count: u32,
33*bb4ee6a4SAndroid Build Coastguard Worker     _first_data_block: u32,
34*bb4ee6a4SAndroid Build Coastguard Worker     _log_block_size: u32,
35*bb4ee6a4SAndroid Build Coastguard Worker     log_frag_size: u32,
36*bb4ee6a4SAndroid Build Coastguard Worker     pub blocks_per_group: u32,
37*bb4ee6a4SAndroid Build Coastguard Worker     frags_per_group: u32,
38*bb4ee6a4SAndroid Build Coastguard Worker     pub inodes_per_group: u32,
39*bb4ee6a4SAndroid Build Coastguard Worker     mtime: u32,
40*bb4ee6a4SAndroid Build Coastguard Worker     wtime: u32,
41*bb4ee6a4SAndroid Build Coastguard Worker     _mnt_count: u16,
42*bb4ee6a4SAndroid Build Coastguard Worker     _max_mnt_count: u16,
43*bb4ee6a4SAndroid Build Coastguard Worker     magic: u16,
44*bb4ee6a4SAndroid Build Coastguard Worker     state: u16,
45*bb4ee6a4SAndroid Build Coastguard Worker     errors: u16,
46*bb4ee6a4SAndroid Build Coastguard Worker     _minor_rev_level: u16,
47*bb4ee6a4SAndroid Build Coastguard Worker     _lastcheck: u32,
48*bb4ee6a4SAndroid Build Coastguard Worker     _checkinterval: u32,
49*bb4ee6a4SAndroid Build Coastguard Worker     _creator_os: u32,
50*bb4ee6a4SAndroid Build Coastguard Worker     rev_level: u32,
51*bb4ee6a4SAndroid Build Coastguard Worker     _def_resuid: u16,
52*bb4ee6a4SAndroid Build Coastguard Worker     _def_resgid: u16,
53*bb4ee6a4SAndroid Build Coastguard Worker     first_ino: u32,
54*bb4ee6a4SAndroid Build Coastguard Worker     pub inode_size: u16,
55*bb4ee6a4SAndroid Build Coastguard Worker     pub block_group_nr: u16,
56*bb4ee6a4SAndroid Build Coastguard Worker     feature_compat: u32,
57*bb4ee6a4SAndroid Build Coastguard Worker     feature_incompat: u32,
58*bb4ee6a4SAndroid Build Coastguard Worker     _feature_ro_compat: u32,
59*bb4ee6a4SAndroid Build Coastguard Worker     uuid: [u8; 16],
60*bb4ee6a4SAndroid Build Coastguard Worker     // Add more fields if needed.
61*bb4ee6a4SAndroid Build Coastguard Worker }
62*bb4ee6a4SAndroid Build Coastguard Worker 
63*bb4ee6a4SAndroid Build Coastguard Worker impl SuperBlock {
new<'a>(arena: &'a Arena<'a>, cfg: &Builder) -> Result<&'a mut SuperBlock>64*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new<'a>(arena: &'a Arena<'a>, cfg: &Builder) -> Result<&'a mut SuperBlock> {
65*bb4ee6a4SAndroid Build Coastguard Worker         const EXT2_MAGIC_NUMBER: u16 = 0xEF53;
66*bb4ee6a4SAndroid Build Coastguard Worker         const COMPAT_EXT_ATTR: u32 = 0x8;
67*bb4ee6a4SAndroid Build Coastguard Worker 
68*bb4ee6a4SAndroid Build Coastguard Worker         let num_groups = cfg.size / (cfg.blocks_per_group * BLOCK_SIZE as u32);
69*bb4ee6a4SAndroid Build Coastguard Worker         let blocks_per_group = cfg.blocks_per_group;
70*bb4ee6a4SAndroid Build Coastguard Worker         let inodes_per_group = cfg.inodes_per_group;
71*bb4ee6a4SAndroid Build Coastguard Worker 
72*bb4ee6a4SAndroid Build Coastguard Worker         let log_block_size = 2; // (1024 << log_block_size) = 4K bytes
73*bb4ee6a4SAndroid Build Coastguard Worker 
74*bb4ee6a4SAndroid Build Coastguard Worker         let now = std::time::SystemTime::now()
75*bb4ee6a4SAndroid Build Coastguard Worker             .duration_since(std::time::UNIX_EPOCH)?
76*bb4ee6a4SAndroid Build Coastguard Worker             .as_secs() as u32;
77*bb4ee6a4SAndroid Build Coastguard Worker 
78*bb4ee6a4SAndroid Build Coastguard Worker         let uuid = uuid::Uuid::new_v4().into_bytes();
79*bb4ee6a4SAndroid Build Coastguard Worker         let inodes_count = inodes_per_group * num_groups;
80*bb4ee6a4SAndroid Build Coastguard Worker         let blocks_count = blocks_per_group * num_groups;
81*bb4ee6a4SAndroid Build Coastguard Worker 
82*bb4ee6a4SAndroid Build Coastguard Worker         // Reserve 10 inodes. Usually inode 11 is used for the lost+found directory.
83*bb4ee6a4SAndroid Build Coastguard Worker         // <https://docs.kernel.org/filesystems/ext4/special_inodes.html>.
84*bb4ee6a4SAndroid Build Coastguard Worker         let first_ino = 11;
85*bb4ee6a4SAndroid Build Coastguard Worker 
86*bb4ee6a4SAndroid Build Coastguard Worker         // Superblock is located at 1024 bytes in the first block.
87*bb4ee6a4SAndroid Build Coastguard Worker         let sb = arena.allocate::<SuperBlock>(BlockId::from(0), 1024)?;
88*bb4ee6a4SAndroid Build Coastguard Worker         *sb = Self {
89*bb4ee6a4SAndroid Build Coastguard Worker             inodes_count,
90*bb4ee6a4SAndroid Build Coastguard Worker             blocks_count,
91*bb4ee6a4SAndroid Build Coastguard Worker             free_blocks_count: 0, //blocks_count, // All blocks are free
92*bb4ee6a4SAndroid Build Coastguard Worker             free_inodes_count: inodes_count, // All inodes are free
93*bb4ee6a4SAndroid Build Coastguard Worker             _log_block_size: log_block_size,
94*bb4ee6a4SAndroid Build Coastguard Worker             log_frag_size: log_block_size,
95*bb4ee6a4SAndroid Build Coastguard Worker             blocks_per_group,
96*bb4ee6a4SAndroid Build Coastguard Worker             frags_per_group: blocks_per_group,
97*bb4ee6a4SAndroid Build Coastguard Worker             inodes_per_group,
98*bb4ee6a4SAndroid Build Coastguard Worker             mtime: now,
99*bb4ee6a4SAndroid Build Coastguard Worker             wtime: now,
100*bb4ee6a4SAndroid Build Coastguard Worker             magic: EXT2_MAGIC_NUMBER,
101*bb4ee6a4SAndroid Build Coastguard Worker             state: 1,     // clean
102*bb4ee6a4SAndroid Build Coastguard Worker             errors: 1,    // continue on errors
103*bb4ee6a4SAndroid Build Coastguard Worker             rev_level: 1, // Rev 1 for variable inode sizes
104*bb4ee6a4SAndroid Build Coastguard Worker             first_ino,
105*bb4ee6a4SAndroid Build Coastguard Worker             inode_size: Inode::INODE_RECORD_SIZE as u16,
106*bb4ee6a4SAndroid Build Coastguard Worker             block_group_nr: 1, // super block is in block group 1
107*bb4ee6a4SAndroid Build Coastguard Worker             feature_compat: COMPAT_EXT_ATTR,
108*bb4ee6a4SAndroid Build Coastguard Worker             feature_incompat: 0x2, // Directory entries contain a type field
109*bb4ee6a4SAndroid Build Coastguard Worker             uuid,
110*bb4ee6a4SAndroid Build Coastguard Worker             ..Default::default()
111*bb4ee6a4SAndroid Build Coastguard Worker         };
112*bb4ee6a4SAndroid Build Coastguard Worker 
113*bb4ee6a4SAndroid Build Coastguard Worker         Ok(sb)
114*bb4ee6a4SAndroid Build Coastguard Worker     }
115*bb4ee6a4SAndroid Build Coastguard Worker 
116*bb4ee6a4SAndroid Build Coastguard Worker     #[inline]
num_groups(&self) -> u16117*bb4ee6a4SAndroid Build Coastguard Worker     pub fn num_groups(&self) -> u16 {
118*bb4ee6a4SAndroid Build Coastguard Worker         (self.inodes_count / self.inodes_per_group) as u16
119*bb4ee6a4SAndroid Build Coastguard Worker     }
120*bb4ee6a4SAndroid Build Coastguard Worker }
121