145 lines
4.2 KiB
Rust
145 lines
4.2 KiB
Rust
//! Filesystem implementations
|
|
|
|
use core::ptr::NonNull;
|
|
|
|
use abi::{io::filesystem::FilesystemRequestVariant, path::Path};
|
|
use alloc::sync::Arc;
|
|
use ext2::Ext2Fs;
|
|
use libk::{
|
|
block,
|
|
fs::{devfs, sysfs},
|
|
vfs::{self, register_root, Filesystem, 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)
|
|
}
|
|
|
|
/// Global filesystem control request
|
|
pub fn global_control(option: u32, buffer: &mut [u8], len: usize) -> Result<usize, Error> {
|
|
let _ = buffer;
|
|
let _ = len;
|
|
|
|
let option = FilesystemRequestVariant::try_from(option)?;
|
|
match option {
|
|
FilesystemRequestVariant::FlushCache => {
|
|
block! {
|
|
let roots = vfs::filesystem_roots();
|
|
for root in roots.read().iter() {
|
|
if let Some(fs) = root.filesystem() {
|
|
if let Err(error) = fs.flush().await {
|
|
log::error!("{:?} flush: {error:?}", fs.display_name());
|
|
}
|
|
}
|
|
}
|
|
}?;
|
|
|
|
Ok(0)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Specific filesystem control request
|
|
pub fn filesystem_control(
|
|
fs: Arc<dyn Filesystem>,
|
|
option: u32,
|
|
buffer: &mut [u8],
|
|
len: usize,
|
|
) -> Result<usize, Error> {
|
|
let _ = buffer;
|
|
let _ = len;
|
|
|
|
if let Ok(option) = FilesystemRequestVariant::try_from(option) {
|
|
match option {
|
|
FilesystemRequestVariant::FlushCache => {
|
|
block!(fs.flush().await)??;
|
|
return Ok(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
todo!()
|
|
}
|