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