1use std::collections::BTreeMap;
8
9use anyhow::Result;
10use zerocopy::FromBytes;
11use zerocopy::Immutable;
12use zerocopy::IntoBytes;
13use zerocopy::KnownLayout;
14
15use crate::arena::Arena;
16use crate::arena::BlockId;
17use crate::bitmap::BitMap;
18use crate::inode::Inode;
19use crate::inode::InodeNum;
20use crate::superblock::SuperBlock;
21
22pub const BLOCK_SIZE: usize = 4096;
25
26#[repr(C)]
30#[derive(Default, Debug, Copy, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
31pub(crate) struct BlockGroupDescriptor {
32 pub block_bitmap: u32,
34 pub inode_bitmap: u32,
36 pub inode_table: u32,
38 pub free_blocks_count: u16,
40 pub free_inodes_count: u16,
42 pub used_dirs_count: u16,
44 pad: u16,
45 reserved: [u8; 12],
46}
47
48pub(crate) struct GroupMetaData<'a> {
49 pub group_desc: &'a mut BlockGroupDescriptor,
50 pub block_bitmap: BitMap<'a>,
51 pub inode_bitmap: BitMap<'a>,
52
53 pub inode_table: BTreeMap<InodeNum, &'a mut Inode>,
54
55 pub first_free_block: u32,
56 pub first_free_inode: u32,
57}
58
59impl<'a> GroupMetaData<'a> {
60 pub fn new(arena: &'a Arena<'a>, sb: &mut SuperBlock, group_id: u16) -> Result<Self> {
63 let gd_size = std::mem::size_of::<BlockGroupDescriptor>() as u32;
64 let num_blocks_for_gds = (gd_size * sb.num_groups() as u32).div_ceil(BLOCK_SIZE as u32);
65
66 let inodes_per_block = BLOCK_SIZE as u64 / sb.inode_size as u64;
67 let num_blocks_for_inode_table =
68 (sb.inodes_per_group as usize).div_ceil(inodes_per_block as usize);
69
70 let group_desc = arena.allocate::<BlockGroupDescriptor>(
72 BlockId::from(1),
73 std::mem::size_of::<BlockGroupDescriptor>() * group_id as usize,
74 )?;
75
76 let super_block_id = group_id as u32 * sb.blocks_per_group;
78 let group_desc_id = super_block_id + 1;
79 group_desc.block_bitmap = group_desc_id + num_blocks_for_gds;
80 group_desc.inode_bitmap = group_desc.block_bitmap + 1;
81 group_desc.inode_table = group_desc.inode_bitmap + 1;
82
83 let first_free_block = group_desc.inode_table + num_blocks_for_inode_table as u32;
85 group_desc.free_blocks_count =
87 (sb.blocks_per_group * (group_id as u32 + 1) - first_free_block) as u16;
88 sb.free_blocks_count += group_desc.free_blocks_count as u32;
89
90 let reserved_inode = if group_id == 0 { 10 } else { 0 };
92 let first_free_inode = group_id as u32 * sb.inodes_per_group + reserved_inode + 1;
93 group_desc.free_inodes_count = sb.inodes_per_group as u16 - reserved_inode as u16;
94 sb.free_inodes_count -= reserved_inode;
95
96 let bmap = arena.allocate::<[u8; BLOCK_SIZE]>(BlockId::from(group_desc.block_bitmap), 0)?;
98 let valid_bmap_bytes = (sb.blocks_per_group / 8) as usize;
99 bmap[valid_bmap_bytes..].iter_mut().for_each(|x| *x = 0xff);
101 let mut block_bitmap = BitMap::from_slice_mut(&mut bmap[..valid_bmap_bytes]);
103 block_bitmap.mark_first_elems(
104 (first_free_block - group_id as u32 * sb.blocks_per_group) as usize,
105 true,
106 );
107
108 let imap = arena.allocate::<[u8; BLOCK_SIZE]>(BlockId::from(group_desc.inode_bitmap), 0)?;
109 let valid_imap_bytes = (sb.inodes_per_group / 8) as usize;
110 imap[valid_imap_bytes..].iter_mut().for_each(|x| *x = 0xff);
112 let mut inode_bitmap =
114 BitMap::from_slice_mut(&mut imap[..(sb.inodes_per_group / 8) as usize]);
115 inode_bitmap.mark_first_elems(reserved_inode as usize, true);
116
117 Ok(GroupMetaData {
118 group_desc,
119 block_bitmap,
120 inode_bitmap,
121
122 inode_table: BTreeMap::new(),
123
124 first_free_block,
125 first_free_inode,
126 })
127 }
128}
129
130#[cfg(test)]
131mod test {
132 use base::MemoryMappingBuilder;
133
134 use super::*;
135 use crate::Builder;
136
137 #[test]
139 fn test_group_metadata_with_one_block_group() {
140 let blocks_per_group = 1024;
141 let num_groups = 1;
142 let size = BLOCK_SIZE as u32 * blocks_per_group * num_groups;
143 let mut mem = MemoryMappingBuilder::new(size as usize).build().unwrap();
144 let arena = Arena::new(BLOCK_SIZE, &mut mem).unwrap();
145 let sb = SuperBlock::new(
146 &arena,
147 &Builder {
148 inodes_per_group: 1024,
149 blocks_per_group,
150 size,
151 root_dir: None,
152 },
153 )
154 .unwrap();
155 let group = GroupMetaData::new(&arena, sb, 0).unwrap();
156
157 assert_eq!(sb.block_group_nr, 1);
158
159 assert_eq!(group.group_desc.block_bitmap, 2);
168 assert_eq!(group.group_desc.inode_bitmap, 3);
169 assert_eq!(group.group_desc.inode_table, 4);
170
171 assert_eq!(
172 group.group_desc.free_blocks_count as u32,
173 sb.free_blocks_count
174 );
175 assert_eq!(
176 group.group_desc.free_inodes_count as u32,
177 sb.free_inodes_count
178 );
179 assert_eq!(group.block_bitmap.len(), sb.blocks_per_group as usize);
180 assert_eq!(
181 group.block_bitmap.count_zeros(),
182 group.group_desc.free_blocks_count as usize,
183 );
184 assert_eq!(
185 group.inode_bitmap.count_zeros(),
186 group.group_desc.free_inodes_count as usize,
187 );
188 }
189
190 #[test]
191 fn test_group_metadata_with_multiple_block_groups() {
192 let blocks_per_group = 1024u32;
193 let num_groups = 10u32;
194 let mem_size = BLOCK_SIZE as u32 * blocks_per_group * num_groups;
195 let mut mem = MemoryMappingBuilder::new(mem_size as usize)
196 .build()
197 .unwrap();
198 let arena = Arena::new(BLOCK_SIZE, &mut mem).unwrap();
199 let sb = SuperBlock::new(
200 &arena,
201 &Builder {
202 inodes_per_group: 512,
203 blocks_per_group,
204 size: mem_size,
205 root_dir: None,
206 },
207 )
208 .unwrap();
209
210 let groups = (0..num_groups)
211 .map(|group_id| GroupMetaData::new(&arena, sb, group_id as u16).unwrap())
212 .collect::<Vec<_>>();
213 assert_eq!(
214 groups
215 .iter()
216 .map(|gd| gd.group_desc.free_blocks_count as u32)
217 .sum::<u32>(),
218 sb.free_blocks_count
219 );
220 assert_eq!(
221 groups
222 .iter()
223 .map(|gd| gd.group_desc.free_inodes_count as u32)
224 .sum::<u32>(),
225 sb.free_inodes_count
226 );
227 }
228}