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