From cc464c4ec3ad704a42a5b313412aaec68b86db70 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Thu, 4 Aug 2022 17:03:44 +0300 Subject: [PATCH] VFS+Ext2: many simplifications and filesystem initialisation --- ableos/src/filesystem/errors.rs | 1 + ableos/src/filesystem/ext2.rs | 93 ++++++++++++------- ableos/src/filesystem/mod.rs | 153 +++++--------------------------- ableos/src/handle.rs | 2 + ableos/src/kernel_state.rs | 23 +++-- ableos/src/kmain.rs | 11 ++- ableos/src/lib.rs | 4 + ext2-rs/src/fs/sync.rs | 2 - 8 files changed, 116 insertions(+), 173 deletions(-) diff --git a/ableos/src/filesystem/errors.rs b/ableos/src/filesystem/errors.rs index 49a08b05..d0ce762e 100644 --- a/ableos/src/filesystem/errors.rs +++ b/ableos/src/filesystem/errors.rs @@ -4,6 +4,7 @@ * SPDX-License-Identifier: MPL-2.0 */ +#[derive(Copy, Clone, Debug)] pub enum FsError { EndOfFile, InodeNotFound, diff --git a/ableos/src/filesystem/ext2.rs b/ableos/src/filesystem/ext2.rs index d0163a7e..7e8e44b1 100644 --- a/ableos/src/filesystem/ext2.rs +++ b/ableos/src/filesystem/ext2.rs @@ -4,16 +4,17 @@ * SPDX-License-Identifier: MPL-2.0 */ -use alloc::sync::Weak; +use alloc::sync::{Arc, Weak}; use ext2::fs::{sync::Synced, Ext2}; use ext2::sector::SectorSize; use ext2::sys::inode::TypePerm; use ext2::volume::Volume; -use crate::handle::Handle; +use crate::handle::{Handle, HandleResource}; use super::errors::FsError; -use super::{DirectoryEntry, FsFlags, FsNode, FsResult as Result, StorageDevice}; +use super::vfs::{add_fs_node, find_fs_node, DirectoryEntry, FsFlags}; +use super::{FsNode, FsResult as Result, StorageDevice}; pub struct Ext2StorageDevice where @@ -22,6 +23,7 @@ where { fs: Synced>, device_handle: Handle, + root: Arc, } impl Ext2StorageDevice @@ -29,10 +31,24 @@ where S: SectorSize, V: Volume, { - pub fn new(volume: V, device_handle: Handle) -> Result { - Ok(Self { - fs: Synced::new(volume).map_err(|e| e.into())?, + pub fn new(volume: V) -> Result { + let fs = Synced::new(volume).map_err(|e| e.into())?; + let root_inode = fs.root_inode(); + let device_handle = Handle::new(HandleResource::StorageDevice); + let root = Arc::new(FsNode::new( + FsFlags::DIRECTORY, + root_inode.size(), + 2, device_handle, + Weak::new(), + )); + + add_fs_node(root.clone()); + + Ok(Self { + fs, + device_handle, + root, }) } } @@ -45,7 +61,7 @@ where fn read(&self, node: &FsNode, offset: usize, size: usize, buffer: &mut Vec) -> Result<()> { let inode = self .fs - .inode_nth(node.inode as usize) + .inode_nth(node.inode() as usize) .ok_or_else(|| FsError::InodeNotFound)?; // FIXME: I don't really know how Ext2 works, so for now we don't @@ -66,21 +82,38 @@ where fn read_dir(&self, node: &FsNode, index: usize) -> Result { let inode = self .fs - .inode_nth(node.inode as usize) + .inode_nth(node.inode() as usize) .ok_or_else(|| FsError::InodeNotFound)?; let mut dir = inode.directory().ok_or_else(|| FsError::NotADirectory)?; let entry = dir .nth(index) .ok_or_else(|| FsError::InodeNotFound)? .map_err(|e| e.into())?; + let entry_inode = self + .fs + .inode_nth(entry.inode) + .ok_or_else(|| FsError::InodeNotFound)?; + let entry_node_handle = + find_fs_node(entry.inode, self.device_handle).unwrap_or_else(|| { + add_fs_node(Arc::new(FsNode::new( + ext2_type_to_fs_flags(entry_inode.type_perm()), + inode.size(), + entry.inode, + self.device_handle, + Weak::new(), + ))) + }); - Ok(DirectoryEntry::new(entry.file_name_string(), entry.inode)) + Ok(DirectoryEntry::new( + entry.file_name_string(), + entry_node_handle, + )) } - fn find_dir(&self, node: &FsNode, name: &str) -> Result { + fn find_dir(&self, node: &FsNode, name: &str) -> Result { let inode = self .fs - .inode_nth(node.inode as usize) + .inode_nth(node.inode() as usize) .ok_or_else(|| FsError::InodeNotFound)?; let dir = inode.directory().ok_or_else(|| FsError::NotADirectory)?; let mut found_node = Err(FsError::NotFound); @@ -91,23 +124,30 @@ where let entry = entry.unwrap(); if entry.file_name_string() == name { - let inode = self - .fs - .inode_nth(entry.inode as usize) - .ok_or_else(|| FsError::InodeNotFound)?; - let flags = ext2_type_to_fs_flags(inode.type_perm()); - found_node = Ok(FsNode::new( - flags, - inode.size(), - entry.inode, - self.device_handle, - Weak::new(), - )) + found_node = Ok( + find_fs_node(entry.inode, self.device_handle).unwrap_or_else(|| { + add_fs_node(Arc::new(FsNode::new( + ext2_type_to_fs_flags(inode.type_perm()), + inode.size(), + entry.inode, + self.device_handle, + Weak::new(), + ))) + }), + ); } } found_node } + + fn root_node(&self) -> Arc { + self.root.clone() + } + + fn device_handle(&self) -> Handle { + self.device_handle + } } fn ext2_type_to_fs_flags(type_perm: TypePerm) -> FsFlags { @@ -127,13 +167,6 @@ fn ext2_type_to_fs_flags(type_perm: TypePerm) -> FsFlags { t | s } -// fn load_fs() -> Arc>>> { -// let mut volume = Vec::new(); -// volume.extend_from_slice(include_bytes!("../../../userland/root_fs/ext2.img")); - -// Arc::>::new(volume).unwrap() -// } - // pub fn walk>( // fs: &Synced>, // inode: Inode, diff --git a/ableos/src/filesystem/mod.rs b/ableos/src/filesystem/mod.rs index 6a37f5fa..284f226c 100644 --- a/ableos/src/filesystem/mod.rs +++ b/ableos/src/filesystem/mod.rs @@ -6,15 +6,18 @@ pub mod errors; pub mod ext2; +pub mod vfs; -use core::cmp; - -use alloc::sync::{Arc, Weak}; -use bitflags::bitflags; +use ::ext2::sector::Size1024; +use alloc::sync::Arc; use crate::{handle::Handle, KERNEL_STATE}; -use self::errors::FsError; +use self::{ + errors::FsError, + ext2::Ext2StorageDevice, + vfs::{DirectoryEntry, FsNode}, +}; use FsResult as Result; pub type FsResult = core::result::Result; @@ -27,138 +30,22 @@ where fn read(&self, node: &FsNode, offset: usize, size: usize, buffer: &mut Vec) -> Result<()>; fn write(&self, node: &FsNode, offset: usize, buffer: &[u8]) -> Result<()>; fn read_dir(&self, node: &FsNode, index: usize) -> Result; - fn find_dir(&self, node: &FsNode, name: &str) -> Result; + fn find_dir(&self, node: &FsNode, name: &str) -> Result; // TODO: flush to disk + + fn root_node(&self) -> Arc; + fn device_handle(&self) -> Handle; } -/// A VFS node, that can either be a file or a directory. -/// -/// VFS nodes are created whenever a file that doesn't have an open VFS node is -/// opened. When there are no open file descriptors to a file, the associated -/// VFS node is dropped. -#[derive(Debug)] -pub struct FsNode { - flags: FsFlags, - length: usize, // in bytes - inode: usize, // implementation specific identifier for the node - device_handle: Handle, // uniquely assigned device handle - ptr: Weak, // used by mountpoints and symlinks - // TODO: permissions mask - // TODO: owning user/group +pub fn init() -> Result<()> { + let mut state = KERNEL_STATE.lock(); + state.add_storage_device(load_fs()?); + Ok(()) } -impl FsNode { - pub fn new( - flags: FsFlags, - length: usize, - inode: usize, - device_handle: Handle, - ptr: Weak, - ) -> Self { - Self { - flags, - length, - inode, - device_handle, - ptr, - } - } +fn load_fs() -> Result>> { + let mut volume = Vec::new(); + volume.extend_from_slice(include_bytes!("../../../userland/root_fs/ext2.img")); - /// This method opens a new file descriptor for this VFS node. - // TODO: make this take flags - pub fn open(self: Arc) -> Result { - let mut state = KERNEL_STATE.lock(); - let handle = state.open_file_descriptor(self); - - Ok(handle) - } - - /// This method reads from the VFS node without opening a new file - /// descriptor. This is intended to be used internally, if you're trying to - /// read a file then you probably want to read from a file descriptor. - pub fn read(&self, offset: usize, size: usize, buffer: &mut Vec) -> Result { - let state = KERNEL_STATE.lock(); - let device = state - .get_storage_device(self.device_handle) - .ok_or_else(|| FsError::InvalidDevice)?; - - if self.is_dir() { - Err(FsError::IsDirectory)?; - } - - if offset > self.length { - Err(FsError::EndOfFile)?; - } - - let readable_size = cmp::min(size, self.length - offset); - device.read(self, offset, readable_size, buffer)?; - Ok(readable_size) - } - - /// This method writes to the VFS node without opening a new file - /// descriptor. This is intended to be used internally, if you're trying to - /// write to a file then you probably want to write to a file descriptor. - pub fn write(&self, offset: usize, buffer: &[u8]) -> Result<()> { - let state = KERNEL_STATE.lock(); - let device = state - .get_storage_device(self.device_handle) - .ok_or_else(|| FsError::InvalidDevice)?; - - device.write(self, offset, buffer) - } - - pub fn read_dir(&self, index: usize) -> Result { - let state = KERNEL_STATE.lock(); - let device = state - .get_storage_device(self.device_handle) - .ok_or_else(|| FsError::InvalidDevice)?; - - device.read_dir(self, index) - } - - pub fn find_dir(&self, name: &str) -> Result { - let state = KERNEL_STATE.lock(); - let device = state - .get_storage_device(self.device_handle) - .ok_or_else(|| FsError::InvalidDevice)?; - - device.find_dir(self, name) - } - - pub fn is_dir(&self) -> bool { - (self.flags & FsFlags::DIRECTORY) == FsFlags::DIRECTORY - } -} - -impl Drop for FsNode { - fn drop(&mut self) { - trace!("dropping VFS node: {self:#?}"); - // TODO: flush to disk here - } -} - -bitflags! { - /// Flags associated with VFS nodes and file descriptors - /// - /// 0x00000MST \ - /// T is set to 0 for files, 1 for directories \ - /// S is set when the file is a symbolic link \ - /// M is set if the file is an active mount point - pub struct FsFlags: u8 { - const FILE = 0b00000000; - const DIRECTORY = 0b00000001; - const SYMBOLIC_LINK = 0b00000010; - const MOUNT_POINT = 0b00000100; - } -} - -pub struct DirectoryEntry { - name: String, - inode: usize, -} - -impl DirectoryEntry { - fn new(name: String, inode: usize) -> Self { - Self { name, inode } - } + Ext2StorageDevice::new(volume) } diff --git a/ableos/src/handle.rs b/ableos/src/handle.rs index fb9f31db..4c30c730 100644 --- a/ableos/src/handle.rs +++ b/ableos/src/handle.rs @@ -23,6 +23,7 @@ pub enum HandleResource { BinaryData, StorageDevice, FileDescriptor, + FsNode, } #[derive(Debug, Eq, Hash, PartialEq, Clone, Copy)] @@ -40,6 +41,7 @@ impl Display for Handle { HandleResource::Socket => write!(f, "-Socket")?, HandleResource::StorageDevice => write!(f, "-StorageDevice")?, HandleResource::FileDescriptor => write!(f, "-FileDescriptor")?, + HandleResource::FsNode => write!(f, "-FsNode")?, } Ok(()) diff --git a/ableos/src/kernel_state.rs b/ableos/src/kernel_state.rs index 9d1236fe..3a7736da 100644 --- a/ableos/src/kernel_state.rs +++ b/ableos/src/kernel_state.rs @@ -1,9 +1,15 @@ +/* + * Copyright (c) 2022, Umut İnan Erdoğan + * + * SPDX-License-Identifier: MPL-2.0 + */ + use alloc::sync::Arc; use hashbrown::HashMap; use spin::Lazy; use crate::{ - filesystem::{FsNode, StorageDevice}, + filesystem::{vfs::FsNode, StorageDevice}, handle::{Handle, HandleResource}, }; @@ -32,13 +38,12 @@ impl KernelInternalState { self.hostname = hostname; } - pub fn add_storage_device(&mut self, device: impl StorageDevice + Send + 'static) -> Handle { - let handle = Handle::new(HandleResource::StorageDevice); - self.storage_devices.insert(handle, Box::new(device)); - handle + pub fn add_storage_device(&mut self, device: impl StorageDevice + Send + 'static) { + let device = Box::new(device); + self.storage_devices.insert(device.device_handle(), device); } - pub fn get_storage_device(&self, handle: Handle) -> Option<&dyn StorageDevice> { + pub fn storage_device(&self, handle: Handle) -> Option<&dyn StorageDevice> { self.storage_devices.get(&handle).map(|d| &**d) } @@ -49,7 +54,7 @@ impl KernelInternalState { handle } - pub fn get_file_descriptor(&self, handle: Handle) -> Option<&FileTableEntry> { + pub fn file_descriptor(&self, handle: Handle) -> Option<&FileTableEntry> { self.file_table.get(&handle) } @@ -83,4 +88,8 @@ impl FileTableEntry { fn new(fs_node: Arc) -> Self { Self { fs_node } } + + pub fn fs_node(&self) -> Arc { + self.fs_node.clone() + } } diff --git a/ableos/src/kmain.rs b/ableos/src/kmain.rs index 9a4cc1d2..0115208a 100644 --- a/ableos/src/kmain.rs +++ b/ableos/src/kmain.rs @@ -1,13 +1,19 @@ +/* + * Copyright (c) 2022, Umut İnan Erdoğan + * + * SPDX-License-Identifier: MPL-2.0 + */ + #![allow(clippy::empty_loop)] use core::sync::atomic::AtomicU64; use crate::arch::{drivers::sysinfo::master, init, sloop}; -use crate::hardware; use crate::relib::network::socket::{SimpleSock, Socket}; use crate::{ boot_conf::KernelConfig, scratchpad, systeminfo::RELEASE_TYPE, TERM, }; +use crate::{filesystem, hardware}; use kernel::KERNEL_VERSION; use spin::Lazy; @@ -36,6 +42,9 @@ pub fn kernel_main() -> ! { x86_64::instructions::interrupts::without_interrupts(|| { hardware::init_mouse(); }); + + filesystem::init().unwrap(); + /* // println!("abc"); diff --git a/ableos/src/lib.rs b/ableos/src/lib.rs index 2ab6915a..201ece87 100644 --- a/ableos/src/lib.rs +++ b/ableos/src/lib.rs @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, Able + * Copyright (c) 2022, Umut İnan Erdoğan * * SPDX-License-Identifier: MPL-2.0 */ @@ -25,6 +26,9 @@ #[macro_use] pub extern crate log; +#[macro_use] +pub extern crate bitflags; + pub extern crate alloc; pub extern crate externc_libm as libm; diff --git a/ext2-rs/src/fs/sync.rs b/ext2-rs/src/fs/sync.rs index a5fc5584..25e01e15 100644 --- a/ext2-rs/src/fs/sync.rs +++ b/ext2-rs/src/fs/sync.rs @@ -393,8 +393,6 @@ impl> Inode { } /// Determine if an inode is a directory pub fn is_dir(&self) -> bool { - use sys::inode::TypePerm; - { self.inner.type_perm }.contains(TypePerm::DIRECTORY) // self.inner.type_perm.contains(TypePerm::DIRECTORY) }