98 lines
2.9 KiB
Rust

//! Filesystem implementations
use core::ptr::NonNull;
use abi::path::Path;
use ext2::Ext2Fs;
use libk::{
block,
fs::{devfs, sysfs},
vfs::{self, register_root, FilesystemMountOption, IoContext, NodeRef},
};
use libk_mm::{
address::{PhysicalAddress, Virtualize},
phys,
};
use libk_util::OneTimeInit;
use memfs::block::{self, BlockAllocator};
// use memfs::block::{self, BlockAllocator};
use static_assertions::const_assert_eq;
use yggdrasil_abi::{error::Error, io::MountOptions};
pub use pseudo::add_pseudo_devices;
pub mod pseudo;
// pub mod sysfs;
/// Describes in-memory filesystem image used as initial root
pub struct Initrd {
/// Page-aligned start address of the initrd
pub phys_page_start: PhysicalAddress,
/// Page-aligned length
pub phys_page_len: usize,
/// Safe reference to the initrd data slice
pub data: &'static [u8],
}
/// Holds reference to the data of initrd as well as its page-aligned physical memory region
pub static INITRD_DATA: OneTimeInit<Initrd> = OneTimeInit::new();
/// Implementation of [memfs::block::BlockAllocator] for the kernel
pub struct FileBlockAllocator;
const_assert_eq!(block::SIZE, 4096);
unsafe impl BlockAllocator for FileBlockAllocator {
fn alloc() -> Result<NonNull<u8>, Error> {
let page = phys::alloc_page()?;
Ok(unsafe { NonNull::new_unchecked(page.virtualize() as *mut _) })
}
unsafe fn dealloc(block: NonNull<u8>) {
let page = block.as_ptr() as usize;
let physical = PhysicalAddress::from_virtualized(page);
phys::free_page(physical);
}
}
/// Mounts an instance of a filesystem for given set of [MountOptions].
pub fn mount_filesystem(ioctx: &mut IoContext, options: &MountOptions) -> Result<(), Error> {
let Some(fs_name) = options.filesystem else {
log::warn!("TODO: mount without filesystem type/fs probing not yet implemented");
return Err(Error::NotImplemented);
};
let source = options.source.map(|path| {
let path = Path::from_str(path);
if !path.is_absolute() {
todo!();
}
ioctx.find(None, path, true)
});
let target = options.target;
let options = vfs::parse_mount_options(options.options);
ioctx.mount(target, move || create_filesystem(fs_name, source, options))
}
fn create_filesystem<'a, I: IntoIterator<Item = FilesystemMountOption<'a>>>(
fs_name: &str,
source: Option<Result<NodeRef, Error>>,
options: I,
) -> Result<NodeRef, Error> {
let root = match fs_name {
"devfs" => devfs::root().clone(),
"sysfs" => sysfs::root().clone(),
"ext2" if let Some(source) = source => {
let source = source?;
let device = source.as_block_device()?;
block!(Ext2Fs::create(device.clone(), options).await)??
}
_ => return Err(Error::InvalidArgument),
};
register_root(root.clone());
Ok(root)
}