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