Skip to content

Commit 21c13c0

Browse files
ext2: read the BGDT and get the root inode
* read the BGDT (Block Group Descriptor Table) * get the root inode * read the inode table for ^^^ Signed-off-by: Andy-Python-Programmer <andypythonappdeveloper@gmail.com>
1 parent 24cfd4a commit 21c13c0

File tree

6 files changed

+294
-24
lines changed

6 files changed

+294
-24
lines changed

src/aero_kernel/src/fs/block/gpt.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
/*
2+
* Copyright (C) 2021-2022 The Aero Project Developers.
3+
*
4+
* This file is part of The Aero Project.
5+
*
6+
* Aero is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* Aero is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with Aero. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
120
use super::BlockDevice;
221
use core::mem::MaybeUninit;
322

src/aero_kernel/src/fs/block/mod.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
/*
2+
* Copyright (C) 2021-2022 The Aero Project Developers.
3+
*
4+
* This file is part of The Aero Project.
5+
*
6+
* Aero is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* Aero is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with Aero. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
120
mod gpt;
221

322
use gpt::Gpt;

src/aero_kernel/src/fs/cache.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ use spin::Once;
3939
use crate::fs::inode::{DirEntry, INodeInterface};
4040
use crate::utils::sync::Mutex;
4141

42+
use super::FileSystem;
43+
4244
pub(super) static INODE_CACHE: Once<Arc<INodeCache>> = Once::new();
4345
pub(super) static DIR_CACHE: Once<Arc<DirCache>> = Once::new();
4446

@@ -291,10 +293,13 @@ impl ops::Deref for CachedINode {
291293

292294
impl Cacheable<INodeCacheKey> for CachedINode {
293295
fn cache_key(&self) -> INodeCacheKey {
294-
(
295-
Weak::as_ptr(&self.weak_filesystem().unwrap()) as *const () as usize,
296-
self.metadata().unwrap().id,
297-
)
296+
INodeCacheItem::make_key(self.weak_filesystem().unwrap(), self.metadata().unwrap().id)
297+
}
298+
}
299+
300+
impl INodeCacheItem {
301+
pub fn make_key(fs: Weak<dyn FileSystem>, id: usize) -> INodeCacheKey {
302+
(Weak::as_ptr(&fs) as *const () as usize, id)
298303
}
299304
}
300305

src/aero_kernel/src/fs/ext2/mod.rs

Lines changed: 236 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,36 @@
1-
use alloc::{boxed::Box, sync::Arc};
1+
/*
2+
* Copyright (C) 2021-2022 The Aero Project Developers.
3+
*
4+
* This file is part of The Aero Project.
5+
*
6+
* Aero is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* Aero is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with Aero. If not, see <https://www.gnu.org/licenses/>.
18+
*/
219

3-
use super::{block::BlockDevice, FileSystem};
20+
use core::mem::MaybeUninit;
21+
22+
use alloc::boxed::Box;
23+
use alloc::sync::{Arc, Weak};
24+
25+
use crate::utils::CeilDiv;
26+
27+
use super::block::BlockDevice;
28+
29+
use super::cache;
30+
use super::cache::{CachedINode, DirCacheItem, INodeCacheItem};
31+
32+
use super::inode::{DirEntry, INodeInterface, Metadata};
33+
use super::FileSystem;
434

535
#[derive(Debug, Copy, Clone)]
636
#[repr(C, packed)]
@@ -61,26 +91,223 @@ pub struct SuperBlock {
6191
pub jnl_blocks: [u32; 17usize],
6292
}
6393

64-
pub struct Ext2 {}
94+
impl SuperBlock {
95+
const MAGIC: u16 = 0xef53;
96+
97+
/// Returns the size of a block in bytes.
98+
pub fn block_size(&self) -> usize {
99+
1024usize << self.log_block_size
100+
}
101+
102+
/// Returns the length of the BGDT.
103+
pub fn bgdt_len(&self) -> usize {
104+
self.blocks_count.ceil_div(self.blocks_per_group) as usize
105+
}
106+
107+
/// Returns the sector where the BGDT starts.
108+
pub fn bgdt_sector(&self) -> usize {
109+
// XXX: The block group descriptors are always located in the block immediately
110+
// following the superblock.
111+
match self.block_size() {
112+
1024 => 4,
113+
x if x > 1024 => x / 512,
114+
_ => unreachable!(),
115+
}
116+
}
117+
}
118+
119+
#[repr(C)]
120+
#[derive(Debug, Copy, Clone)]
121+
pub struct GroupDescriptor {
122+
pub block_bitmap: u32,
123+
pub inode_bitmap: u32,
124+
pub inode_table: u32,
125+
pub free_blocks_count: u16,
126+
pub free_inodes_count: u16,
127+
pub used_dirs_count: u16,
128+
pub pad: u16,
129+
pub reserved: [u8; 12usize],
130+
}
131+
132+
const_assert_eq!(core::mem::size_of::<GroupDescriptor>(), 32);
133+
134+
pub enum FileType {
135+
Fifo,
136+
CharDev,
137+
Directory,
138+
BlockDev,
139+
File,
140+
Symlink,
141+
Socket,
142+
Unknown,
143+
}
144+
145+
impl From<FileType> for super::inode::FileType {
146+
fn from(ty: FileType) -> Self {
147+
match ty {
148+
FileType::Symlink => Self::Symlink,
149+
FileType::Directory => Self::Directory,
150+
FileType::BlockDev | FileType::CharDev => Self::Device,
151+
152+
_ => Self::File,
153+
}
154+
}
155+
}
156+
157+
#[repr(C)]
158+
#[derive(Debug, Default, Copy, Clone)]
159+
pub struct DiskINode {
160+
type_and_perm: u16,
161+
pub user_id: u16,
162+
pub size_lower: u32,
163+
pub last_access: u32,
164+
pub creation_time: u32,
165+
pub last_modification: u32,
166+
pub deletion_time: u32,
167+
pub group_id: u16,
168+
pub hl_count: u16,
169+
pub sector_count: u32,
170+
pub flags: u32,
171+
pub os_specific: u32,
172+
pub data_ptr: [u32; 15],
173+
pub gen_number: u32,
174+
pub ext_attr_block: u32,
175+
pub size_or_acl: u32,
176+
pub fragment_address: u32,
177+
pub os_specific2: [u8; 12],
178+
}
179+
180+
impl DiskINode {
181+
pub fn file_type(&self) -> FileType {
182+
let ty = self.type_and_perm >> 12;
183+
184+
match ty {
185+
0x1 => FileType::Fifo,
186+
0x2 => FileType::CharDev,
187+
0x4 => FileType::Directory,
188+
0x6 => FileType::BlockDev,
189+
0x8 => FileType::File,
190+
0xa => FileType::Symlink,
191+
0xc => FileType::Socket,
192+
_ => FileType::Unknown,
193+
}
194+
}
195+
}
196+
197+
const_assert_eq!(core::mem::size_of::<DiskINode>(), 128);
198+
199+
struct INode {
200+
id: usize,
201+
fs: Weak<Ext2>,
202+
inode: Box<DiskINode>,
203+
}
204+
205+
impl INode {
206+
pub fn new(ext2: Weak<Ext2>, id: usize) -> Option<INodeCacheItem> {
207+
debug_assert!(id != 0);
208+
209+
let icache = cache::icache();
210+
211+
// Check if the inode is in the cache.
212+
if let Some(inode) = icache.get(INodeCacheItem::make_key(ext2.clone(), id)) {
213+
Some(inode)
214+
} else {
215+
let fs = ext2.upgrade()?;
216+
217+
let inode_block_group = (id - 1) / fs.superblock.inodes_per_group as usize;
218+
let inode_table_idx = (id - 1) % fs.superblock.inodes_per_group as usize;
219+
220+
let group_descriptor = &fs.bgdt[inode_block_group];
221+
let inode_size = core::mem::size_of::<DiskINode>(); // TODO: the inode size can be different
222+
223+
let table_offset = group_descriptor.inode_table as usize * fs.superblock.block_size();
224+
let inode_offset = table_offset + (inode_size * inode_table_idx);
225+
226+
let mut inode = Box::<DiskINode>::new_uninit();
227+
fs.block
228+
.device()
229+
.read(inode_offset / 512, inode.as_bytes_mut());
230+
231+
// SAFETY: We have initialized the inode above.
232+
let inode = unsafe { inode.assume_init() };
233+
234+
Some(icache.make_item_cached(CachedINode::new(Arc::new(Self {
235+
inode,
236+
id,
237+
fs: ext2,
238+
}))))
239+
}
240+
}
241+
}
242+
243+
impl INodeInterface for INode {
244+
fn weak_filesystem(&self) -> Option<Weak<dyn FileSystem>> {
245+
Some(self.fs.clone())
246+
}
247+
248+
fn metadata(&self) -> super::Result<Metadata> {
249+
Ok(Metadata {
250+
id: self.id,
251+
file_type: self.inode.file_type().into(),
252+
size: self.inode.size_lower as _,
253+
children_len: 0,
254+
})
255+
}
256+
}
257+
258+
pub struct Ext2 {
259+
superblock: Box<SuperBlock>,
260+
bgdt: Box<[GroupDescriptor]>,
261+
block: Arc<BlockDevice>,
262+
263+
sref: Weak<Self>,
264+
}
65265

66266
impl Ext2 {
67-
pub fn new(device: Arc<BlockDevice>) -> Option<Arc<Self>> {
267+
const ROOT_INODE_ID: usize = 2;
268+
269+
pub fn new(block: Arc<BlockDevice>) -> Option<Arc<Self>> {
68270
let mut superblock = Box::<SuperBlock>::new_uninit();
69-
device.device().read(2, superblock.as_bytes_mut())?;
271+
block.device().read(2, superblock.as_bytes_mut())?;
70272

71273
// SAFETY: We have initialized the superblock above.
72274
let superblock = unsafe { superblock.assume_init() };
73275

74-
if superblock.magic != 0xef53 {
276+
if superblock.magic != SuperBlock::MAGIC {
75277
return None;
76278
}
77279

78-
Some(Arc::new(Self {}))
280+
let bgdt_len = superblock.bgdt_len();
281+
let mut bgdt = Box::<[GroupDescriptor]>::new_uninit_slice(bgdt_len);
282+
283+
block.device().read(
284+
superblock.bgdt_sector(),
285+
MaybeUninit::slice_as_bytes_mut(&mut bgdt),
286+
)?;
287+
288+
// SAFETY: We have initialized the BGD (Block Group Descriptor Table) above.
289+
let bgdt = unsafe { bgdt.assume_init() };
290+
291+
Some(Arc::new_cyclic(|sref| Self {
292+
bgdt,
293+
superblock,
294+
block,
295+
296+
sref: sref.clone(),
297+
}))
298+
}
299+
300+
pub fn find_inode(&self, id: usize) -> Option<INodeCacheItem> {
301+
INode::new(self.sref.clone(), id)
79302
}
80303
}
81304

82305
impl FileSystem for Ext2 {
83-
fn root_dir(&self) -> super::cache::DirCacheItem {
84-
todo!()
306+
fn root_dir(&self) -> DirCacheItem {
307+
let inode = self
308+
.find_inode(Ext2::ROOT_INODE_ID)
309+
.expect("ext2: invalid filesystem (root inode not found)");
310+
311+
DirEntry::new_root(inode, String::from("/"))
85312
}
86313
}

src/aero_kernel/src/fs/inode.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -256,13 +256,7 @@ pub trait INodeInterface: Send + Sync {
256256
pub struct Metadata {
257257
pub id: usize,
258258
pub file_type: FileType,
259-
260-
/// The total size of the content that the inode holds. Set to `0x00` if
261-
/// the inode file type is *not* a file.
262259
pub size: usize,
263-
264-
/// The length of the children's map of the inode. Set to `0x00` if the inode
265-
/// has no children and if the file type of the inode is *not* a directory.
266260
pub children_len: usize,
267261
}
268262

@@ -330,15 +324,17 @@ pub enum FileType {
330324
Directory,
331325
Device,
332326
Socket,
327+
Symlink,
333328
}
334329

335330
impl From<FileType> for aero_syscall::SysFileType {
336331
fn from(file: FileType) -> Self {
337332
match file {
338333
FileType::File => aero_syscall::SysFileType::File,
339334
FileType::Directory => aero_syscall::SysFileType::Directory,
340-
FileType::Device => aero_syscall::SysFileType::Device,
335+
FileType::Device => aero_syscall::SysFileType::CharDevice, // FIXME: determine if it is a character or block device.
341336
FileType::Socket => aero_syscall::SysFileType::Socket,
337+
FileType::Symlink => aero_syscall::SysFileType::Symlink,
342338
}
343339
}
344340
}

src/aero_syscall/src/lib.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,14 @@ pub fn syscall_as_str(syscall: usize) -> &'static str {
241241
#[derive(Debug)]
242242
#[repr(usize)]
243243
pub enum SysFileType {
244-
File,
245-
Directory,
246-
Device,
247-
Socket,
244+
Unknown = 0,
245+
Fifo = 1,
246+
CharDevice = 2,
247+
Directory = 4,
248+
BlockDevice = 6,
249+
File = 8,
250+
Symlink = 10,
251+
Socket = 12,
248252
}
249253

250254
#[repr(C, packed)]

0 commit comments

Comments
 (0)