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