fs: remove old vfs

This commit is contained in:
Mark Poliakov 2023-11-27 14:56:11 +02:00
parent 6eef11a4e4
commit cc816920b0
20 changed files with 524 additions and 2037 deletions

View File

@ -1,348 +1,348 @@
//! In-memory filesystem driver
#![no_std]
#![warn(missing_docs)]
#![allow(clippy::new_without_default)]
#![feature(
const_mut_refs,
maybe_uninit_uninit_array,
const_maybe_uninit_uninit_array,
maybe_uninit_array_assume_init
)]
use core::{
any::Any,
cell::{Ref, RefCell},
marker::PhantomData,
};
use alloc::{boxed::Box, rc::Rc};
use block::BlockAllocator;
use vfs::{BlockDevice, CreateInfo, Filesystem, Vnode, VnodeKind, VnodeRef};
use yggdrasil_abi::{error::Error, io::FileMode, path};
use crate::{bvec::BVec, dir::DirectoryNode, file::FileNode, tar::TarIterator};
#[cfg(test)]
extern crate std;
extern crate alloc;
#[cfg(test)]
macro_rules! test_allocator_with_counter {
($counter:ident, $allocator:ident) => {
static $counter: core::sync::atomic::AtomicUsize = core::sync::atomic::AtomicUsize::new(0);
struct $allocator;
unsafe impl $crate::block::BlockAllocator for $allocator {
fn alloc() -> Result<core::ptr::NonNull<u8>, yggdrasil_abi::error::Error> {
let b = std::boxed::Box::into_raw(std::boxed::Box::new([0; $crate::block::SIZE]));
$counter.fetch_add(1, core::sync::atomic::Ordering::Release);
Ok(unsafe { core::ptr::NonNull::new_unchecked(b as _) })
}
unsafe fn dealloc(block: core::ptr::NonNull<u8>) {
$counter.fetch_sub(1, core::sync::atomic::Ordering::Release);
drop(std::boxed::Box::from_raw(
block.as_ptr() as *mut [u8; $crate::block::SIZE]
));
}
}
};
}
pub mod block;
pub mod bvec;
mod dir;
mod file;
mod tar;
const DEFAULT_FILE_MODE: FileMode = FileMode::new(0o644);
const DEFAULT_DIR_MODE: FileMode = FileMode::new(0o755);
/// In-memory read/write filesystem
pub struct MemoryFilesystem<A: BlockAllocator> {
root: RefCell<Option<VnodeRef>>,
_pd: PhantomData<A>,
}
impl<A: BlockAllocator> Filesystem for MemoryFilesystem<A> {
fn dev(self: Rc<Self>) -> Option<&'static dyn BlockDevice> {
todo!()
}
fn data(&self) -> Option<Ref<dyn Any>> {
todo!()
}
fn root(self: Rc<Self>) -> Result<VnodeRef, Error> {
Ok(self.root.borrow().clone().unwrap())
}
}
impl<A: BlockAllocator> MemoryFilesystem<A> {
fn make_path(
self: &Rc<Self>,
at: &VnodeRef,
path: &str,
kind: VnodeKind,
create: bool,
) -> Result<VnodeRef, Error> {
if path.is_empty() {
return Ok(at.clone());
}
let (element, rest) = path::split_left(path);
assert!(!element.is_empty());
let node = at.lookup(element);
let node = match node {
Some(node) => node,
None => {
if !create {
return Err(Error::DoesNotExist);
}
let node = self.create_node_initial(element, kind);
// TODO require .tar's to have all the directories present to extract their metadata?
if kind == VnodeKind::Directory {
node.set_data(Box::new(DirectoryNode::<A>::new(0, 0, DEFAULT_DIR_MODE)));
}
at.add_child(node.clone());
node
}
};
if rest.is_empty() {
Ok(node)
} else {
assert!(node.is_directory());
self.make_path(&node, rest, kind, create)
}
}
fn create_node_initial(self: &Rc<Self>, name: &str, kind: VnodeKind) -> VnodeRef {
assert!(!name.is_empty());
assert!(!name.contains('/'));
let node = Vnode::new(name, kind);
node.set_fs(self.clone());
// match kind {
// VnodeKind::Directory => node.set_data(Box::new(DirectoryNode::<A>::new(
// info.uid, info.gid, info.mode,
// ))),
// VnodeKind::Regular => {}
// _ => todo!(),
// }
node
}
fn from_slice_internal(self: &Rc<Self>, tar_data: &'static [u8]) -> Result<VnodeRef, Error> {
let root = Vnode::new("", VnodeKind::Directory);
root.set_fs(self.clone());
root.set_data(Box::new(DirectoryNode::<A>::new(0, 0, DEFAULT_DIR_MODE)));
// 1. Create paths in tar
for item in TarIterator::new(tar_data) {
let Ok((hdr, _)) = item else {
return Err(Error::InvalidArgument);
};
let path = hdr.name.as_str()?.trim_matches('/');
let (dirname, filename) = path::split_right(path);
let parent = self.make_path(&root, dirname, VnodeKind::Directory, true)?;
let node = self.create_node_initial(filename, hdr.node_kind());
parent.add_child(node);
}
// 2. Associate files with their data
for item in TarIterator::new(tar_data) {
let Ok((hdr, data)) = item else {
panic!("Unreachable");
};
let path = hdr.name.as_str()?.trim_matches('/');
let node = self.make_path(&root, path, VnodeKind::Directory, false)?;
assert_eq!(node.kind(), hdr.node_kind());
if hdr.node_kind() == VnodeKind::Regular {
let uid = usize::from(&hdr.uid).try_into().unwrap();
let gid = usize::from(&hdr.gid).try_into().unwrap();
let mode = convert_mode(usize::from(&hdr.mode))?;
let data = data.unwrap();
let bvec = BVec::<A>::try_from(data)?;
assert_eq!(bvec.size(), data.len());
node.set_data(Box::new(FileNode {
uid,
gid,
mode,
data: RefCell::new(bvec),
}));
}
}
Ok(root)
}
/// Constructs a filesystem tree from a tar image in memory
pub fn from_slice(tar_data: &'static [u8]) -> Result<Rc<Self>, Error> {
let fs = Rc::new(Self {
root: RefCell::new(None),
_pd: PhantomData,
});
let root = fs.from_slice_internal(tar_data)?;
fs.root.replace(Some(root));
Ok(fs)
}
/// Constructs an empty memory filesystem
pub fn empty() -> Rc<Self> {
let fs = Rc::new(Self {
root: RefCell::new(None),
_pd: PhantomData,
});
let root = Vnode::new("", VnodeKind::Directory);
root.set_data(Box::new(DirectoryNode::<A>::new(0, 0, DEFAULT_DIR_MODE)));
root.set_fs(fs.clone());
fs.root.replace(Some(root));
fs
}
}
fn convert_mode(mode: usize) -> Result<FileMode, Error> {
Ok(FileMode::new(mode as u32 & 0o777))
}
#[cfg(test)]
mod tests {
use core::sync::atomic::Ordering;
use std::rc::Rc;
use vfs::{Filesystem, IoContext, Read, Seek, VnodeKind, Write};
use yggdrasil_abi::io::{FileMode, OpenOptions, SeekFrom};
use crate::MemoryFilesystem;
#[repr(C)]
struct AlignedTo<Align, Bytes: ?Sized> {
_align: [Align; 0],
bytes: Bytes,
}
static TEST_IMAGE: &'static AlignedTo<u64, [u8]> = &AlignedTo {
_align: [],
bytes: *include_bytes!("../test/test_image.tar"),
};
#[test]
fn test_memfs_construction() {
fn check_file(ioctx: &IoContext, path: &str, expected_data: &str) {
let node = ioctx.find(None, path, false, false).unwrap();
assert_eq!(node.kind(), VnodeKind::Regular);
assert_eq!(node.size().unwrap(), expected_data.len() as u64);
let file = node.open(OpenOptions::READ).unwrap();
let mut buf = [0; 512];
assert_eq!(
file.borrow_mut().read(&mut buf).unwrap(),
expected_data.len()
);
assert_eq!(&buf[..expected_data.len()], expected_data.as_bytes());
}
test_allocator_with_counter!(A_COUNTER, A);
let fs = MemoryFilesystem::<A>::from_slice(&TEST_IMAGE.bytes).unwrap();
let root = fs.root().unwrap();
// Files are small, so no indirect blocks allocated
assert_eq!(A_COUNTER.load(Ordering::Acquire), 0);
let ioctx = IoContext::new(root.clone());
assert!(Rc::ptr_eq(
&root,
&ioctx.find(None, "/", false, false).unwrap()
));
let old_data = include_str!("../test/test1.txt");
check_file(&ioctx, "/test1.txt", old_data);
// Write to the file
{
let node = ioctx.find(None, "/test1.txt", false, false).unwrap();
let file = node.open(OpenOptions::WRITE).unwrap();
assert_eq!(file.borrow_mut().write(b"Hello").unwrap(), 5);
}
assert_eq!(A_COUNTER.load(Ordering::Acquire), 1);
// Read back
{
let node = ioctx.find(None, "/test1.txt", false, false).unwrap();
let file = node.open(OpenOptions::READ).unwrap();
let mut buf = [0; 512];
assert_eq!(file.borrow_mut().read(&mut buf).unwrap(), old_data.len());
assert_eq!(&buf[..5], b"Hello");
assert_eq!(&buf[5..old_data.len()], &old_data.as_bytes()[5..]);
}
}
// #[test]
// fn test_memfs_create_and_write() {
// test_allocator_with_counter!(A_COUNTER, A);
// let fs = MemoryFilesystem::<A>::empty();
// let root = fs.root().unwrap();
// let ioctx = IoContext::new(root.clone());
// // Create, write, seek and read file
// {
// // TODO CREATE option handling
// root.create("test1.txt", VnodeKind::Regular).unwrap();
// let file = ioctx
// .open(
// None,
// "/test1.txt",
// OpenOptions::WRITE | OpenOptions::READ,
// FileMode::empty(),
// )
// .unwrap();
// let write_data = [1, 2, 3, 4];
// let mut read_data = [0; 512];
// let mut file = file.borrow_mut();
// assert_eq!(file.write(&write_data).unwrap(), write_data.len());
// assert_eq!(file.seek(SeekFrom::Start(0)).unwrap(), 0);
// assert_eq!(file.read(&mut read_data).unwrap(), write_data.len());
// assert_eq!(&read_data[..write_data.len()], &write_data[..]);
// }
// // Create a directory
// {
// // TODO read directory
// root.create("dir1", VnodeKind::Directory).unwrap();
// let dir1 = ioctx.find(None, "/dir1", false, false).unwrap();
// let node = dir1.create("file1.txt", VnodeKind::Regular).unwrap();
// assert!(Rc::ptr_eq(
// &ioctx.find(None, "/dir1/file1.txt", false, false).unwrap(),
// &node
// ));
// }
// }
}
// #![warn(missing_docs)]
// #![allow(clippy::new_without_default)]
// #![feature(
// const_mut_refs,
// maybe_uninit_uninit_array,
// const_maybe_uninit_uninit_array,
// maybe_uninit_array_assume_init
// )]
//
// use core::{
// any::Any,
// cell::{Ref, RefCell},
// marker::PhantomData,
// };
//
// use alloc::{boxed::Box, rc::Rc};
// use block::BlockAllocator;
// use vfs::{BlockDevice, CreateInfo, Filesystem, Vnode, VnodeKind, VnodeRef};
// use yggdrasil_abi::{error::Error, io::FileMode, path};
//
// use crate::{bvec::BVec, dir::DirectoryNode, file::FileNode, tar::TarIterator};
//
// #[cfg(test)]
// extern crate std;
//
// extern crate alloc;
//
// #[cfg(test)]
// macro_rules! test_allocator_with_counter {
// ($counter:ident, $allocator:ident) => {
// static $counter: core::sync::atomic::AtomicUsize = core::sync::atomic::AtomicUsize::new(0);
//
// struct $allocator;
//
// unsafe impl $crate::block::BlockAllocator for $allocator {
// fn alloc() -> Result<core::ptr::NonNull<u8>, yggdrasil_abi::error::Error> {
// let b = std::boxed::Box::into_raw(std::boxed::Box::new([0; $crate::block::SIZE]));
// $counter.fetch_add(1, core::sync::atomic::Ordering::Release);
// Ok(unsafe { core::ptr::NonNull::new_unchecked(b as _) })
// }
//
// unsafe fn dealloc(block: core::ptr::NonNull<u8>) {
// $counter.fetch_sub(1, core::sync::atomic::Ordering::Release);
// drop(std::boxed::Box::from_raw(
// block.as_ptr() as *mut [u8; $crate::block::SIZE]
// ));
// }
// }
// };
// }
//
// pub mod block;
// pub mod bvec;
//
// mod dir;
// mod file;
// mod tar;
//
// const DEFAULT_FILE_MODE: FileMode = FileMode::new(0o644);
// const DEFAULT_DIR_MODE: FileMode = FileMode::new(0o755);
//
// /// In-memory read/write filesystem
// pub struct MemoryFilesystem<A: BlockAllocator> {
// root: RefCell<Option<VnodeRef>>,
// _pd: PhantomData<A>,
// }
//
// impl<A: BlockAllocator> Filesystem for MemoryFilesystem<A> {
// fn dev(self: Rc<Self>) -> Option<&'static dyn BlockDevice> {
// todo!()
// }
//
// fn data(&self) -> Option<Ref<dyn Any>> {
// todo!()
// }
//
// fn root(self: Rc<Self>) -> Result<VnodeRef, Error> {
// Ok(self.root.borrow().clone().unwrap())
// }
// }
//
// impl<A: BlockAllocator> MemoryFilesystem<A> {
// fn make_path(
// self: &Rc<Self>,
// at: &VnodeRef,
// path: &str,
// kind: VnodeKind,
// create: bool,
// ) -> Result<VnodeRef, Error> {
// if path.is_empty() {
// return Ok(at.clone());
// }
// let (element, rest) = path::split_left(path);
// assert!(!element.is_empty());
//
// let node = at.lookup(element);
// let node = match node {
// Some(node) => node,
// None => {
// if !create {
// return Err(Error::DoesNotExist);
// }
//
// let node = self.create_node_initial(element, kind);
// // TODO require .tar's to have all the directories present to extract their metadata?
// if kind == VnodeKind::Directory {
// node.set_data(Box::new(DirectoryNode::<A>::new(0, 0, DEFAULT_DIR_MODE)));
// }
// at.add_child(node.clone());
//
// node
// }
// };
//
// if rest.is_empty() {
// Ok(node)
// } else {
// assert!(node.is_directory());
// self.make_path(&node, rest, kind, create)
// }
// }
//
// fn create_node_initial(self: &Rc<Self>, name: &str, kind: VnodeKind) -> VnodeRef {
// assert!(!name.is_empty());
// assert!(!name.contains('/'));
//
// let node = Vnode::new(name, kind);
// node.set_fs(self.clone());
//
// // match kind {
// // VnodeKind::Directory => node.set_data(Box::new(DirectoryNode::<A>::new(
// // info.uid, info.gid, info.mode,
// // ))),
// // VnodeKind::Regular => {}
// // _ => todo!(),
// // }
//
// node
// }
//
// fn from_slice_internal(self: &Rc<Self>, tar_data: &'static [u8]) -> Result<VnodeRef, Error> {
// let root = Vnode::new("", VnodeKind::Directory);
// root.set_fs(self.clone());
// root.set_data(Box::new(DirectoryNode::<A>::new(0, 0, DEFAULT_DIR_MODE)));
//
// // 1. Create paths in tar
// for item in TarIterator::new(tar_data) {
// let Ok((hdr, _)) = item else {
// return Err(Error::InvalidArgument);
// };
//
// let path = hdr.name.as_str()?.trim_matches('/');
// let (dirname, filename) = path::split_right(path);
// let parent = self.make_path(&root, dirname, VnodeKind::Directory, true)?;
// let node = self.create_node_initial(filename, hdr.node_kind());
//
// parent.add_child(node);
// }
//
// // 2. Associate files with their data
// for item in TarIterator::new(tar_data) {
// let Ok((hdr, data)) = item else {
// panic!("Unreachable");
// };
//
// let path = hdr.name.as_str()?.trim_matches('/');
// let node = self.make_path(&root, path, VnodeKind::Directory, false)?;
// assert_eq!(node.kind(), hdr.node_kind());
//
// if hdr.node_kind() == VnodeKind::Regular {
// let uid = usize::from(&hdr.uid).try_into().unwrap();
// let gid = usize::from(&hdr.gid).try_into().unwrap();
// let mode = convert_mode(usize::from(&hdr.mode))?;
//
// let data = data.unwrap();
// let bvec = BVec::<A>::try_from(data)?;
// assert_eq!(bvec.size(), data.len());
// node.set_data(Box::new(FileNode {
// uid,
// gid,
// mode,
// data: RefCell::new(bvec),
// }));
// }
// }
//
// Ok(root)
// }
//
// /// Constructs a filesystem tree from a tar image in memory
// pub fn from_slice(tar_data: &'static [u8]) -> Result<Rc<Self>, Error> {
// let fs = Rc::new(Self {
// root: RefCell::new(None),
// _pd: PhantomData,
// });
// let root = fs.from_slice_internal(tar_data)?;
// fs.root.replace(Some(root));
//
// Ok(fs)
// }
//
// /// Constructs an empty memory filesystem
// pub fn empty() -> Rc<Self> {
// let fs = Rc::new(Self {
// root: RefCell::new(None),
// _pd: PhantomData,
// });
// let root = Vnode::new("", VnodeKind::Directory);
// root.set_data(Box::new(DirectoryNode::<A>::new(0, 0, DEFAULT_DIR_MODE)));
// root.set_fs(fs.clone());
// fs.root.replace(Some(root));
// fs
// }
// }
//
// fn convert_mode(mode: usize) -> Result<FileMode, Error> {
// Ok(FileMode::new(mode as u32 & 0o777))
// }
//
// #[cfg(test)]
// mod tests {
// use core::sync::atomic::Ordering;
// use std::rc::Rc;
// use vfs::{Filesystem, IoContext, Read, Seek, VnodeKind, Write};
// use yggdrasil_abi::io::{FileMode, OpenOptions, SeekFrom};
//
// use crate::MemoryFilesystem;
//
// #[repr(C)]
// struct AlignedTo<Align, Bytes: ?Sized> {
// _align: [Align; 0],
// bytes: Bytes,
// }
//
// static TEST_IMAGE: &'static AlignedTo<u64, [u8]> = &AlignedTo {
// _align: [],
// bytes: *include_bytes!("../test/test_image.tar"),
// };
//
// #[test]
// fn test_memfs_construction() {
// fn check_file(ioctx: &IoContext, path: &str, expected_data: &str) {
// let node = ioctx.find(None, path, false, false).unwrap();
//
// assert_eq!(node.kind(), VnodeKind::Regular);
// assert_eq!(node.size().unwrap(), expected_data.len() as u64);
//
// let file = node.open(OpenOptions::READ).unwrap();
// let mut buf = [0; 512];
//
// assert_eq!(
// file.borrow_mut().read(&mut buf).unwrap(),
// expected_data.len()
// );
//
// assert_eq!(&buf[..expected_data.len()], expected_data.as_bytes());
// }
//
// test_allocator_with_counter!(A_COUNTER, A);
//
// let fs = MemoryFilesystem::<A>::from_slice(&TEST_IMAGE.bytes).unwrap();
// let root = fs.root().unwrap();
//
// // Files are small, so no indirect blocks allocated
// assert_eq!(A_COUNTER.load(Ordering::Acquire), 0);
//
// let ioctx = IoContext::new(root.clone());
//
// assert!(Rc::ptr_eq(
// &root,
// &ioctx.find(None, "/", false, false).unwrap()
// ));
//
// let old_data = include_str!("../test/test1.txt");
// check_file(&ioctx, "/test1.txt", old_data);
//
// // Write to the file
// {
// let node = ioctx.find(None, "/test1.txt", false, false).unwrap();
// let file = node.open(OpenOptions::WRITE).unwrap();
//
// assert_eq!(file.borrow_mut().write(b"Hello").unwrap(), 5);
// }
//
// assert_eq!(A_COUNTER.load(Ordering::Acquire), 1);
//
// // Read back
// {
// let node = ioctx.find(None, "/test1.txt", false, false).unwrap();
// let file = node.open(OpenOptions::READ).unwrap();
//
// let mut buf = [0; 512];
// assert_eq!(file.borrow_mut().read(&mut buf).unwrap(), old_data.len());
//
// assert_eq!(&buf[..5], b"Hello");
// assert_eq!(&buf[5..old_data.len()], &old_data.as_bytes()[5..]);
// }
// }
//
// // #[test]
// // fn test_memfs_create_and_write() {
// // test_allocator_with_counter!(A_COUNTER, A);
//
// // let fs = MemoryFilesystem::<A>::empty();
// // let root = fs.root().unwrap();
//
// // let ioctx = IoContext::new(root.clone());
//
// // // Create, write, seek and read file
// // {
// // // TODO CREATE option handling
// // root.create("test1.txt", VnodeKind::Regular).unwrap();
//
// // let file = ioctx
// // .open(
// // None,
// // "/test1.txt",
// // OpenOptions::WRITE | OpenOptions::READ,
// // FileMode::empty(),
// // )
// // .unwrap();
//
// // let write_data = [1, 2, 3, 4];
// // let mut read_data = [0; 512];
//
// // let mut file = file.borrow_mut();
// // assert_eq!(file.write(&write_data).unwrap(), write_data.len());
// // assert_eq!(file.seek(SeekFrom::Start(0)).unwrap(), 0);
// // assert_eq!(file.read(&mut read_data).unwrap(), write_data.len());
// // assert_eq!(&read_data[..write_data.len()], &write_data[..]);
// // }
//
// // // Create a directory
// // {
// // // TODO read directory
// // root.create("dir1", VnodeKind::Directory).unwrap();
//
// // let dir1 = ioctx.find(None, "/dir1", false, false).unwrap();
// // let node = dir1.create("file1.txt", VnodeKind::Regular).unwrap();
// // assert!(Rc::ptr_eq(
// // &ioctx.find(None, "/dir1/file1.txt", false, false).unwrap(),
// // &node
// // ));
// // }
// // }
// }

View File

@ -6,7 +6,3 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" }
kernel-util = { path = "../kernel-util" }
bitflags = "2.3.3"
log = "0.4.20"

View File

@ -1,6 +0,0 @@
use yggdrasil_abi::error::Error;
pub trait BlockDevice {
fn read(&self, pos: usize, buf: &mut [u8]) -> Result<(), Error>;
fn write(&self, pos: usize, buf: &[u8]) -> Result<(), Error>;
}

View File

@ -1,66 +0,0 @@
use core::any::Any;
use alloc::boxed::Box;
use yggdrasil_abi::{
error::Error,
io::{DeviceRequest, FileAttr, FileMode, FileType, OpenOptions},
};
use crate::{node::VnodeImpl, VnodeRef};
pub trait CharDevice {
fn read(&'static self, blocking: bool, data: &mut [u8]) -> Result<usize, Error>;
fn write(&self, blocking: bool, data: &[u8]) -> Result<usize, Error>;
fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error>;
}
pub struct CharDeviceWrapper {
device: &'static dyn CharDevice,
}
impl CharDeviceWrapper {
pub const fn new(device: &'static dyn CharDevice) -> Self {
Self { device }
}
}
impl VnodeImpl for CharDeviceWrapper {
fn open(
&self,
_node: &VnodeRef,
_opts: OpenOptions,
) -> Result<(u64, Option<Box<dyn Any>>), Error> {
Ok((0, None))
}
fn close(&self, _node: &VnodeRef) -> Result<(), Error> {
Ok(())
}
fn read(
&self,
_node: &VnodeRef,
_pos: u64,
_inner: Option<&mut Box<dyn Any>>,
data: &mut [u8],
) -> Result<usize, Error> {
self.device.read(true, data)
}
fn write(&self, _node: &VnodeRef, _pos: u64, data: &[u8]) -> Result<usize, Error> {
self.device.write(true, data)
}
fn metadata(&self, _node: &VnodeRef) -> Result<FileAttr, Error> {
Ok(FileAttr {
size: 0,
ty: FileType::Char,
mode: FileMode::default_file(),
})
}
fn device_request(&self, _node: &VnodeRef, req: &mut DeviceRequest) -> Result<(), Error> {
self.device.device_request(req)
}
}

View File

@ -1,224 +0,0 @@
use core::{any::Any, cell::RefCell, mem::MaybeUninit};
use alloc::{boxed::Box, rc::Rc};
use bitflags::bitflags;
use yggdrasil_abi::{
error::Error,
io::{DirectoryEntry, FileType},
};
use crate::{
node::{VnodeKind, VnodeRef},
Read, ReadDirectory, Seek, SeekFrom, Write, DIR_POSITION_FROM_CACHE,
};
bitflags! {
pub struct FileFlags: u32 {
const READ = 1 << 0;
const WRITE = 1 << 1;
}
}
pub type FileRef = Rc<RefCell<File>>;
enum DirectoryPosition {
// TODO not the best implementation, but at least somewhat safe?
CachePosition(usize),
Dot,
DotDot,
#[allow(dead_code)]
DiskPosition(u64),
#[allow(dead_code)]
End,
}
pub struct NormalFile {
vnode: VnodeRef,
data: Option<Box<dyn Any>>,
pos: u64,
}
pub struct Directory {
vnode: VnodeRef,
pos: DirectoryPosition,
}
pub enum FileInner {
Normal(NormalFile),
Directory(Directory),
}
pub struct File {
inner: FileInner,
flags: FileFlags,
}
impl File {
pub fn normal(
vnode: VnodeRef,
pos: u64,
data: Option<Box<dyn Any>>,
flags: FileFlags,
) -> FileRef {
Rc::new(RefCell::new(Self {
inner: FileInner::Normal(NormalFile { vnode, pos, data }),
flags,
}))
}
pub fn directory(vnode: VnodeRef, pos: u64) -> FileRef {
let pos = if pos == DIR_POSITION_FROM_CACHE {
// Read from cache
DirectoryPosition::Dot
} else {
// Reading from a "physical" directory
todo!()
};
Rc::new(RefCell::new(Self {
inner: FileInner::Directory(Directory { vnode, pos }),
flags: FileFlags::READ,
}))
}
pub fn node(&self) -> Result<VnodeRef, Error> {
match &self.inner {
FileInner::Normal(inner) => Ok(inner.vnode.clone()),
FileInner::Directory(inner) => Ok(inner.vnode.clone()),
}
}
}
impl Write for File {
fn write(&mut self, data: &[u8]) -> Result<usize, Error> {
if !self.flags.contains(FileFlags::WRITE) {
panic!();
}
match &mut self.inner {
FileInner::Normal(inner) => {
let count = inner.vnode.write(inner.pos, data)?;
if inner.vnode.kind() != VnodeKind::Char {
inner.pos += count as u64;
}
Ok(count)
}
FileInner::Directory(_) => unimplemented!(),
}
}
}
impl Read for File {
fn read(&mut self, data: &mut [u8]) -> Result<usize, Error> {
if !self.flags.contains(FileFlags::READ) {
panic!();
}
match &mut self.inner {
FileInner::Normal(inner) => {
let count = inner.vnode.read(inner.pos, inner.data.as_mut(), data)?;
if inner.vnode.kind() != VnodeKind::Char {
inner.pos += count as u64;
}
Ok(count)
}
FileInner::Directory(_) => Err(Error::IsADirectory),
}
}
}
impl Seek for File {
fn seek(&mut self, pos: SeekFrom) -> Result<u64, Error> {
match &mut self.inner {
FileInner::Normal(inner) => {
// TODO check if the file is actually seekable
let size = inner.vnode.size()?;
let pos = match pos {
SeekFrom::Start(offset) => {
if offset > size {
todo!();
}
offset
}
SeekFrom::End(0) => size,
_ => todo!(),
};
inner.pos = pos;
Ok(pos)
}
FileInner::Directory(_) => todo!(),
}
}
}
impl ReadDirectory for File {
fn read_dir_entries(
&mut self,
entries: &mut [MaybeUninit<DirectoryEntry>],
) -> Result<usize, Error> {
let FileInner::Directory(inner) = &mut self.inner else {
return Err(Error::NotADirectory);
};
let mut nread = 0;
let mut rem = entries.len();
while rem != 0 {
let mut entry = DirectoryEntry {
name: [0; 256],
ty: FileType::File,
};
let next_position = match inner.pos {
DirectoryPosition::End => {
break;
}
DirectoryPosition::Dot => {
entry.name[0] = b'.';
entry.ty = FileType::Directory;
DirectoryPosition::DotDot
}
DirectoryPosition::DotDot => {
entry.name[..2].copy_from_slice(b"..");
entry.ty = FileType::Directory;
DirectoryPosition::CachePosition(0)
}
DirectoryPosition::CachePosition(index) => {
let child = inner.vnode.child_at(index);
if let Some(child) = child {
let child_name = child.name();
entry.name[..child_name.len()].copy_from_slice(child_name.as_bytes());
entry.ty = FileType::from(child.kind());
DirectoryPosition::CachePosition(index + 1)
} else {
break;
}
}
DirectoryPosition::DiskPosition(_) => todo!(),
};
inner.pos = next_position;
entries[nread].write(entry);
nread += 1;
rem -= 1;
}
Ok(nread)
}
}
impl Drop for File {
fn drop(&mut self) {
match &mut self.inner {
FileInner::Normal(inner) => {
inner.vnode.close().ok();
}
FileInner::Directory(inner) => {
inner.vnode.close().ok();
}
}
}
}

View File

@ -1,15 +0,0 @@
use core::{any::Any, cell::Ref};
use alloc::rc::Rc;
use yggdrasil_abi::error::Error;
use crate::{block::BlockDevice, node::VnodeRef};
pub trait Filesystem {
fn root(self: Rc<Self>) -> Result<VnodeRef, Error>;
fn dev(self: Rc<Self>) -> Option<&'static dyn BlockDevice>;
fn data(&self) -> Option<Ref<dyn Any>>;
}

View File

@ -1,274 +0,0 @@
use log::trace;
use yggdrasil_abi::{
error::Error,
io::{FileMode, OpenOptions},
path,
};
use crate::{file::FileRef, node::VnodeRef};
pub struct IoContext {
root: VnodeRef,
cwd: VnodeRef,
}
impl IoContext {
pub fn new(root: VnodeRef) -> Self {
Self {
cwd: root.clone(),
root,
}
}
fn _find(
mut at: VnodeRef,
path: &str,
follow: bool,
follow_mount: bool,
) -> Result<VnodeRef, Error> {
let mut element;
let mut rest = path;
loop {
(element, rest) = path::split_left(rest);
if !at.is_directory() {
todo!();
}
match element {
path::PARENT_NAME => {
at = at.parent();
}
path::SELF_NAME => {}
_ => break,
}
}
if follow || follow_mount {
while let Some(target) = at.target() {
assert!(at.is_mountpoint());
if at.is_mountpoint() && !follow_mount {
break;
}
trace!("resolve parent: {:?} -> {:?}", at, target);
at = target;
}
}
if !at.is_directory() {
return Err(Error::NotADirectory);
}
if element.is_empty() && rest.is_empty() {
return Ok(at);
}
let mut node = at.lookup_or_load(element)?;
if follow || follow_mount {
while let Some(target) = node.target() {
assert!(node.is_mountpoint());
if node.is_mountpoint() && !follow_mount {
break;
}
trace!("resolve node: {:?} -> {:?}", node, target);
node = target;
}
}
if rest.is_empty() {
Ok(node)
} else {
Self::_find(node, rest, follow, follow_mount)
}
}
pub fn find(
&self,
at: Option<VnodeRef>,
mut path: &str,
follow: bool,
follow_mount: bool,
) -> Result<VnodeRef, Error> {
trace!("find {:?} in {:?}", path, at);
let at = if path.starts_with('/') {
path = path.trim_start_matches('/');
self.root.clone()
} else if let Some(at) = at {
at
} else {
self.cwd.clone()
};
Self::_find(at, path, follow, follow_mount)
}
pub fn open(
&self,
at: Option<VnodeRef>,
path: &str,
opts: OpenOptions,
_mode: FileMode,
) -> Result<FileRef, Error> {
let node = match self.find(at.clone(), path, true, true) {
Err(Error::DoesNotExist) => {
// TODO check for create option
return Err(Error::DoesNotExist);
}
o => o,
}?;
node.open(opts)
}
pub fn root(&self) -> &VnodeRef {
&self.root
}
}
#[cfg(test)]
mod tests {
use yggdrasil_abi::error::Error;
use crate::{node::VnodeRef, IoContext};
use std::fmt;
macro_rules! node {
($name:literal) => {{
$crate::node::Vnode::new($name, $crate::node::VnodeKind::Regular)
}};
($name:literal [ $($child:expr),* ]) => {{
let _node = $crate::node::Vnode::new($name, $crate::node::VnodeKind::Directory);
$(
_node.add_child($child);
)*
_node
}};
}
struct DumpNode<'a> {
node: &'a VnodeRef,
}
impl fmt::Debug for DumpNode<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.node.dump(f, 0, true)
}
}
#[test]
fn test_vnode_find() {
let t = node! {
"" [
node!("file1.txt"),
node!("file2.txt"),
node! {
"dir1" [
node!("file3.txt")
]
}
]
};
let ctx = IoContext::new(t);
// Absolute lookups
assert_eq!(
ctx.find(None, "/file1.txt", false, false).unwrap().name(),
"file1.txt"
);
assert_eq!(
ctx.find(None, "/file3.txt", false, false).unwrap_err(),
Error::DoesNotExist
);
assert_eq!(
ctx.find(None, "/dir1/file3.txt", false, false)
.unwrap()
.name(),
"file3.txt"
);
// Non-absolute lookups from root
assert_eq!(
ctx.find(None, "file1.txt", false, false).unwrap().name(),
"file1.txt"
);
assert_eq!(
ctx.find(None, "dir1/file3.txt", false, false)
.unwrap()
.name(),
"file3.txt"
);
// Absolute lookups from non-root
let cwd = ctx.find(None, "/dir1", false, false).unwrap();
assert_eq!(
ctx.find(Some(cwd.clone()), "/file1.txt", false, false)
.unwrap()
.name(),
"file1.txt"
);
assert_eq!(
ctx.find(Some(cwd.clone()), "/dir1/file3.txt", false, false)
.unwrap()
.name(),
"file3.txt"
);
assert_eq!(
ctx.find(Some(cwd.clone()), "/file3.txt", false, false)
.unwrap_err(),
Error::DoesNotExist
);
assert_eq!(
ctx.find(Some(cwd.clone()), "/dir2", false, false)
.unwrap_err(),
Error::DoesNotExist
);
// Non-absolute lookups in non-root
assert_eq!(
ctx.find(Some(cwd.clone()), "file3.txt", false, false)
.unwrap()
.name(),
"file3.txt"
);
assert_eq!(
ctx.find(Some(cwd.clone()), "././file3.txt", false, false)
.unwrap()
.name(),
"file3.txt"
);
assert_eq!(
ctx.find(Some(cwd.clone()), "../dir1/file3.txt", false, false)
.unwrap()
.name(),
"file3.txt"
);
assert_eq!(
ctx.find(Some(cwd.clone()), ".", false, false)
.unwrap()
.name(),
"dir1"
);
assert_eq!(
ctx.find(Some(cwd.clone()), "..", false, false)
.unwrap()
.name(),
""
);
assert_eq!(
ctx.find(Some(cwd.clone()), "../..", false, false)
.unwrap()
.name(),
""
);
}
}

View File

@ -1,69 +1 @@
#![no_std]
use core::mem::MaybeUninit;
use yggdrasil_abi::error::Error;
use yggdrasil_abi::io::{DirectoryEntry, SeekFrom};
extern crate alloc;
#[cfg(test)]
extern crate std;
pub(crate) mod block;
pub(crate) mod char;
pub(crate) mod file;
pub(crate) mod fs;
pub(crate) mod ioctx;
pub(crate) mod node;
pub use self::block::BlockDevice;
pub use self::char::{CharDevice, CharDeviceWrapper};
pub use file::{File, FileFlags, FileRef};
pub use fs::Filesystem;
pub use ioctx::IoContext;
pub use node::{CreateInfo, Vnode, VnodeDump, VnodeImpl, VnodeKind, VnodeRef, VnodeWeak};
pub const DIR_POSITION_FROM_CACHE: u64 = u64::MAX;
pub trait Write {
fn write(&mut self, data: &[u8]) -> Result<usize, Error>;
}
pub trait Read {
fn read(&mut self, data: &mut [u8]) -> Result<usize, Error>;
fn read_exact(&mut self, data: &mut [u8]) -> Result<(), Error> {
default_read_exact(self, data)
}
}
pub trait Seek {
fn seek(&mut self, pos: SeekFrom) -> Result<u64, Error>;
}
pub trait ReadDirectory {
fn read_dir_entries(
&mut self,
entries: &mut [MaybeUninit<DirectoryEntry>],
) -> Result<usize, Error>;
}
fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [u8]) -> Result<(), Error> {
while !buf.is_empty() {
match this.read(buf) {
Ok(0) => break,
Ok(n) => {
let tmp = buf;
buf = &mut tmp[n..];
}
Err(e) => todo!("default_read_exact: {:?}", e),
}
}
if !buf.is_empty() {
todo!("default_read_exact unexpected eof")
} else {
Ok(())
}
}

View File

@ -1,519 +0,0 @@
use core::{
any::Any,
cell::{Ref, RefCell, RefMut},
fmt,
};
use alloc::{
boxed::Box,
rc::{Rc, Weak},
string::String,
vec::Vec,
};
use kernel_util::util::OneTimeInit;
use yggdrasil_abi::{
error::Error,
io::{DeviceRequest, FileAttr, FileMode, FileType, OpenOptions},
};
use crate::{
file::{File, FileFlags, FileRef},
fs::Filesystem,
DIR_POSITION_FROM_CACHE,
};
pub type VnodeRef = Rc<Vnode>;
pub type VnodeWeak = Weak<Vnode>;
pub struct VnodeDump {
node: VnodeRef,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum VnodeKind {
Directory,
Regular,
Char,
Block,
}
pub(crate) struct TreeNode {
parent: Option<VnodeWeak>,
children: Vec<VnodeRef>,
}
pub struct Vnode {
name: String,
tree: RefCell<TreeNode>,
kind: VnodeKind,
data: OneTimeInit<Box<dyn VnodeImpl>>,
fs: RefCell<Option<Rc<dyn Filesystem>>>,
target: RefCell<Option<VnodeRef>>,
}
pub struct CreateInfo<'a> {
pub name: &'a str,
pub kind: VnodeKind,
pub mode: FileMode,
pub uid: u32,
pub gid: u32,
}
#[allow(unused_variables)]
pub trait VnodeImpl {
fn create(&self, at: &VnodeRef, info: &CreateInfo) -> Result<VnodeRef, Error> {
Err(Error::NotImplemented)
}
fn remove(&self, at: &VnodeRef, name: &str) -> Result<(), Error> {
Err(Error::NotImplemented)
}
fn open(
&self,
node: &VnodeRef,
opts: OpenOptions,
) -> Result<(u64, Option<Box<dyn Any>>), Error> {
Err(Error::NotImplemented)
}
fn close(&self, node: &VnodeRef) -> Result<(), Error> {
Err(Error::NotImplemented)
}
fn read(
&self,
node: &VnodeRef,
pos: u64,
inner: Option<&mut Box<dyn Any>>,
data: &mut [u8],
) -> Result<usize, Error> {
Err(Error::NotImplemented)
}
fn write(&self, node: &VnodeRef, pos: u64, data: &[u8]) -> Result<usize, Error> {
Err(Error::NotImplemented)
}
fn size(&self, node: &VnodeRef) -> Result<u64, Error> {
Err(Error::NotImplemented)
}
fn metadata(&self, node: &VnodeRef) -> Result<FileAttr, Error> {
Err(Error::NotImplemented)
}
fn device_request(&self, node: &VnodeRef, req: &mut DeviceRequest) -> Result<(), Error> {
Err(Error::NotImplemented)
}
}
impl Vnode {
pub fn new<S: Into<String>>(name: S, kind: VnodeKind) -> VnodeRef {
Rc::new(Self {
name: name.into(),
tree: RefCell::new(TreeNode {
parent: None,
children: Vec::new(),
}),
kind,
data: OneTimeInit::new(),
fs: RefCell::new(None),
target: RefCell::new(None),
})
}
#[inline]
pub fn name(&self) -> &str {
&self.name
}
#[inline]
pub fn kind(&self) -> VnodeKind {
self.kind
}
#[inline]
pub fn target(&self) -> Option<VnodeRef> {
self.target.borrow().clone()
}
#[inline]
pub fn data(&self) -> Option<&dyn VnodeImpl> {
self.data.try_get().map(Box::as_ref)
}
// #[inline]
// pub fn data(&self) -> RefMut<Option<Box<dyn VnodeImpl>>> {
// match self.data.try_borrow_mut() {
// Ok(r) => r,
// Err(e) => {
// panic!("{:?} on {:?}", e, self.name())
// }
// }
// }
#[inline]
pub fn fs(&self) -> Option<Rc<dyn Filesystem>> {
self.fs.borrow().clone()
}
#[inline]
pub fn set_target(&self, target: Option<VnodeRef>) {
self.target.replace(target);
}
pub fn parent(self: &VnodeRef) -> VnodeRef {
match &self.tree.borrow().parent {
Some(parent) => parent.upgrade().unwrap(),
None => self.clone(),
}
}
#[inline]
pub fn is_root(&self) -> bool {
self.tree.borrow().parent.is_none()
}
pub fn set_data(&self, data: Box<dyn VnodeImpl>) {
self.data.init(data);
// self.data.borrow_mut().replace(data);
}
pub fn set_fs(&self, data: Rc<dyn Filesystem>) {
self.fs.replace(Some(data));
}
#[inline]
pub fn is_directory(&self) -> bool {
self.kind == VnodeKind::Directory
}
#[inline]
pub fn is_mountpoint(&self) -> bool {
self.is_directory() && self.target.borrow().is_some()
}
// Cache tree operations
pub fn add_child(self: &VnodeRef, child: VnodeRef) {
let parent_weak = Rc::downgrade(self);
let mut parent_borrow = self.tree.borrow_mut();
assert!(child
.tree
.borrow_mut()
.parent
.replace(parent_weak)
.is_none());
parent_borrow.children.push(child);
}
pub fn remove_child(self: &VnodeRef, name: &str) {
self.children_mut().retain(|node| node.name() != name);
}
pub fn child_at(self: &VnodeRef, index: usize) -> Option<VnodeRef> {
let tree = self.tree.borrow();
tree.children.get(index).cloned()
}
pub fn children(&self) -> Ref<Vec<VnodeRef>> {
let tree = self.tree.borrow();
Ref::map(tree, |t| &t.children)
}
pub fn children_mut(&self) -> RefMut<Vec<VnodeRef>> {
let tree = self.tree.borrow_mut();
RefMut::map(tree, |t| &mut t.children)
}
pub fn dump(&self, f: &mut fmt::Formatter<'_>, depth: usize, indent: bool) -> fmt::Result {
if indent {
for _ in 0..depth {
f.write_str(" ")?;
}
}
write!(f, "{:?}", self.name)?;
if self.is_directory() {
let tree = self.tree.borrow();
let target = self.target();
if let Some(target) = target {
f.write_str(" -> ")?;
return target.dump(f, depth, false);
}
if tree.children.is_empty() {
f.write_str(" []")?;
} else {
f.write_str(" [\n")?;
for child in tree.children.iter() {
child.dump(f, depth + 1, true)?;
f.write_str("\n")?;
}
for _ in 0..depth {
f.write_str(" ")?;
}
f.write_str("]")?;
}
}
Ok(())
}
pub fn lookup(self: &VnodeRef, name: &str) -> Option<VnodeRef> {
assert!(self.is_directory());
self.tree
.borrow()
.children
.iter()
.find(|e| e.name == name)
.cloned()
}
//
pub fn lookup_or_load(self: &VnodeRef, name: &str) -> Result<VnodeRef, Error> {
// Lookup in cache
if let Some(node) = self.lookup(name) {
return Ok(node);
}
// TODO load from FS
Err(Error::DoesNotExist)
}
// Node operations
pub fn open(self: &VnodeRef, flags: OpenOptions) -> Result<FileRef, Error> {
let mut open_flags = FileFlags::empty();
if flags.contains(OpenOptions::READ) {
open_flags |= FileFlags::READ;
}
if flags.contains(OpenOptions::WRITE) {
open_flags |= FileFlags::WRITE;
}
if self.kind == VnodeKind::Directory {
return Err(Error::IsADirectory);
}
if let Some(data) = self.data() {
let (pos, inner) = data.open(self, flags)?;
Ok(File::normal(self.clone(), pos, inner, open_flags))
} else {
todo!()
}
}
pub fn open_directory(self: &VnodeRef) -> Result<FileRef, Error> {
if !self.is_directory() {
return Err(Error::IsADirectory);
}
if let Some(data) = self.data() {
// TODO don't discard directory's Box<dyn Any>
let (pos, _) = data.open(self, OpenOptions::READ)?;
Ok(File::directory(self.clone(), pos))
} else {
// TODO: some options here?
Ok(File::directory(self.clone(), DIR_POSITION_FROM_CACHE))
}
}
pub fn close(self: &VnodeRef) -> Result<(), Error> {
if let Some(data) = self.data() {
data.close(self)
} else {
Ok(())
}
}
pub fn create(self: &VnodeRef, info: &CreateInfo) -> Result<VnodeRef, Error> {
if self.kind != VnodeKind::Directory {
todo!();
}
if info.name.contains('/') {
return Err(Error::InvalidArgument);
}
match self.lookup_or_load(info.name) {
Err(Error::DoesNotExist) => {}
Ok(_) => return Err(Error::AlreadyExists),
e => return e,
};
if let Some(data) = self.data() {
let vnode = data.create(self, info)?;
if let Some(fs) = self.fs() {
vnode.set_fs(fs);
}
self.add_child(vnode.clone());
Ok(vnode)
} else {
Err(Error::NotImplemented)
}
}
pub fn remove(self: &VnodeRef, node: VnodeRef, recurse: bool) -> Result<(), Error> {
let name = node.name();
if self.kind != VnodeKind::Directory {
todo!();
}
if name.contains('/') {
todo!();
}
if node.kind() == VnodeKind::Directory {
if recurse {
todo!();
}
// Check if remove target is not empty
if node.size()? != 0 {
return Err(Error::DirectoryNotEmpty);
}
}
if let Some(data) = self.data() {
data.remove(self, name)?;
}
// Unlink node from cache
self.remove_child(name);
Ok(())
}
pub fn write(self: &VnodeRef, pos: u64, buf: &[u8]) -> Result<usize, Error> {
if self.kind == VnodeKind::Directory {
todo!();
}
if let Some(data) = self.data() {
data.write(self, pos, buf)
} else {
todo!()
}
}
pub fn read(
self: &VnodeRef,
pos: u64,
inner: Option<&mut Box<dyn Any>>,
buf: &mut [u8],
) -> Result<usize, Error> {
if self.kind == VnodeKind::Directory {
todo!();
}
if let Some(data) = self.data() {
data.read(self, pos, inner, buf)
} else {
todo!()
}
}
pub fn size(self: &VnodeRef) -> Result<u64, Error> {
if let Some(data) = self.data() {
data.size(self)
} else {
todo!();
}
}
pub fn mount(self: &VnodeRef, fs_root: VnodeRef) -> Result<(), Error> {
if !self.is_directory() {
return Err(Error::NotADirectory);
}
if !fs_root.is_directory() {
todo!("Filesystem root is not a directory");
}
if self.target.borrow().is_some() {
todo!("Target mountpoint is busy");
}
{
let mut child_borrow = fs_root.tree.borrow_mut();
if child_borrow.parent.is_some() {
todo!("Filesystem is already mounted somewhere else");
}
child_borrow.parent = Some(Rc::downgrade(self));
}
self.target.replace(Some(fs_root));
Ok(())
}
pub fn unmount_target(self: &VnodeRef) -> Result<(), Error> {
if !self.is_directory() {
return Err(Error::NotADirectory);
}
let Some(fs_root) = self.target.take() else {
todo!();
};
{
let mut target_borrow = fs_root.tree.borrow_mut();
let Some(parent) = target_borrow.parent.take() else {
todo!()
};
assert!(Rc::ptr_eq(self, &parent.upgrade().unwrap()));
}
Ok(())
}
pub fn metadata(self: &VnodeRef) -> Result<FileAttr, Error> {
if let Some(data) = self.data() {
data.metadata(self)
} else {
todo!()
}
}
pub fn device_request(self: &VnodeRef, req: &mut DeviceRequest) -> Result<(), Error> {
if let Some(data) = self.data() {
data.device_request(self, req)
} else {
todo!()
}
}
}
impl fmt::Debug for Vnode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let prefix = match self.kind {
VnodeKind::Directory => "DIR ",
VnodeKind::Regular => "REG ",
VnodeKind::Char => "CHR ",
VnodeKind::Block => "BLK ",
};
write!(f, "[{} {}]", prefix, self.name)
}
}
impl VnodeDump {
pub fn new(node: VnodeRef) -> Self {
Self { node }
}
}
impl fmt::Debug for VnodeDump {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.node.dump(f, 0, true)
}
}
impl From<VnodeKind> for FileType {
fn from(value: VnodeKind) -> Self {
match value {
VnodeKind::Regular => Self::File,
VnodeKind::Directory => Self::Directory,
VnodeKind::Block => Self::Block,
VnodeKind::Char => Self::Char,
}
}
}

View File

@ -12,7 +12,6 @@ use super::{
};
use crate::{
arch::{aarch64::mem::table::L3, Architecture},
fs::devfs,
kernel_main, kernel_secondary_main,
mem::{address::IntoRaw, phys, table::EntryLevel, PhysicalAddress, KERNEL_VIRT_OFFSET},
task::runtime,
@ -103,7 +102,8 @@ unsafe extern "C" fn __aarch64_bsp_upper_entry(dtb: PhysicalAddress) -> ! {
// // Setup initrd
// super::setup_initrd();
devfs::init();
// XXX
// devfs::init();
runtime::init_task_queue();

View File

@ -27,7 +27,6 @@ use crate::{
devtree::{self, DevTreeIndexPropExt, DevTreeNodeInfo, DeviceTree, FdtMemoryRegionIter},
power::arm_psci::Psci,
},
fs::{Initrd, INITRD_DATA},
mem::{
address::{FromRaw, IntoRaw},
device::RawDeviceMemoryMapping,
@ -315,11 +314,12 @@ impl AArch64 {
let data = unsafe { PhysicalRef::map_slice(initrd_start, len) };
self.initrd.init(data);
INITRD_DATA.init(Initrd {
phys_page_start: aligned_start,
phys_page_len: aligned_end - aligned_start,
data: self.initrd.get().as_ref(),
});
// XXX
// INITRD_DATA.init(Initrd {
// phys_page_start: aligned_start,
// phys_page_len: aligned_end - aligned_start,
// data: self.initrd.get().as_ref(),
// });
}
Ok(())

View File

@ -8,7 +8,6 @@ use tock_registers::{
register_bitfields, register_structs,
registers::{ReadOnly, ReadWrite, WriteOnly},
};
use vfs::CharDevice;
use crate::{
arch::{aarch64::IrqNumber, Architecture, ARCHITECTURE},
@ -19,7 +18,6 @@ use crate::{
tty::{TtyContext, TtyDevice},
},
device_tree_driver,
fs::devfs::{self, CharDeviceType},
mem::{address::FromRaw, device::DeviceMemoryIo, PhysicalAddress},
sync::IrqSafeSpinlock,
task::process::ProcessId,
@ -109,37 +107,37 @@ impl TtyDevice for Pl011 {
}
}
impl CharDevice for Pl011 {
fn write(&self, blocking: bool, data: &[u8]) -> Result<usize, Error> {
assert!(blocking);
self.line_write(data)
}
fn read(&'static self, blocking: bool, data: &mut [u8]) -> Result<usize, Error> {
assert!(blocking);
match block! {
self.line_read(data).await
} {
Ok(res) => res,
Err(err) => Err(err),
}
}
fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error> {
match req {
&mut DeviceRequest::SetTerminalGroup(id) => {
self.set_signal_group(ProcessId::from(id));
Ok(())
}
DeviceRequest::SetTerminalOptions(config) => self.context.set_config(config),
DeviceRequest::GetTerminalOptions(config) => {
config.write(self.context.config());
Ok(())
}
_ => Err(Error::InvalidArgument),
}
}
}
// impl CharDevice for Pl011 {
// fn write(&self, blocking: bool, data: &[u8]) -> Result<usize, Error> {
// assert!(blocking);
// self.line_write(data)
// }
//
// fn read(&'static self, blocking: bool, data: &mut [u8]) -> Result<usize, Error> {
// assert!(blocking);
// match block! {
// self.line_read(data).await
// } {
// Ok(res) => res,
// Err(err) => Err(err),
// }
// }
//
// fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error> {
// match req {
// &mut DeviceRequest::SetTerminalGroup(id) => {
// self.set_signal_group(ProcessId::from(id));
// Ok(())
// }
// DeviceRequest::SetTerminalOptions(config) => self.context.set_config(config),
// DeviceRequest::GetTerminalOptions(config) => {
// config.write(self.context.config());
// Ok(())
// }
// _ => Err(Error::InvalidArgument),
// }
// }
// }
impl SerialDevice for Pl011 {
fn send(&self, byte: u8) -> Result<(), Error> {
@ -193,7 +191,7 @@ impl Device for Pl011 {
self.inner.init(IrqSafeSpinlock::new(inner));
debug::add_sink(self, LogLevel::Debug);
devfs::add_char_device(self, CharDeviceType::TtySerial)?;
// devfs::add_char_device(self, CharDeviceType::TtySerial)?;
Ok(())
}

View File

@ -21,7 +21,7 @@ pub mod combined {
io::{DeviceRequest, TerminalSize},
};
use device_api::{input::KeyboardConsumer, serial::SerialDevice};
use vfs::CharDevice;
// use vfs::CharDevice;
use crate::device::{
display::{console::DisplayConsole, fb_console::FramebufferConsole},
@ -73,43 +73,43 @@ pub mod combined {
}
}
impl CharDevice for CombinedTerminal {
fn read(&'static self, blocking: bool, data: &mut [u8]) -> Result<usize, Error> {
assert!(blocking);
match block! {
self.line_read(data).await
} {
Ok(res) => res,
Err(err) => Err(err),
}
// self.line_read(data)
}
// impl CharDevice for CombinedTerminal {
// fn read(&'static self, blocking: bool, data: &mut [u8]) -> Result<usize, Error> {
// assert!(blocking);
// match block! {
// self.line_read(data).await
// } {
// Ok(res) => res,
// Err(err) => Err(err),
// }
// // self.line_read(data)
// }
fn write(&self, blocking: bool, data: &[u8]) -> Result<usize, Error> {
assert!(blocking);
self.line_write(data)
}
// fn write(&self, blocking: bool, data: &[u8]) -> Result<usize, Error> {
// assert!(blocking);
// self.line_write(data)
// }
fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error> {
match req {
&mut DeviceRequest::SetTerminalGroup(id) => {
self.set_signal_group(ProcessId::from(id));
Ok(())
}
DeviceRequest::SetTerminalOptions(config) => self.context.set_config(config),
DeviceRequest::GetTerminalOptions(config) => {
config.write(self.context.config());
Ok(())
}
DeviceRequest::GetTerminalSize(out) => {
let (rows, columns) = self.output.text_dimensions();
out.write(TerminalSize { rows, columns });
Ok(())
}
_ => Err(Error::InvalidArgument),
}
}
}
// fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error> {
// match req {
// &mut DeviceRequest::SetTerminalGroup(id) => {
// self.set_signal_group(ProcessId::from(id));
// Ok(())
// }
// DeviceRequest::SetTerminalOptions(config) => self.context.set_config(config),
// DeviceRequest::GetTerminalOptions(config) => {
// config.write(self.context.config());
// Ok(())
// }
// DeviceRequest::GetTerminalSize(out) => {
// let (rows, columns) = self.output.text_dimensions();
// out.write(TerminalSize { rows, columns });
// Ok(())
// }
// _ => Err(Error::InvalidArgument),
// }
// }
// }
}
#[cfg(feature = "fb_console")]

View File

@ -3,19 +3,8 @@ use abi::{
error::Error,
io::{OpenOptions, RawFd},
};
use memfs::MemoryFilesystem;
use vfs::{Filesystem, IoContext, VnodeRef};
use crate::{
fs::{devfs, FileBlockAllocator, INITRD_DATA},
proc,
};
fn setup_root() -> Result<VnodeRef, Error> {
let initrd_data = INITRD_DATA.get();
let fs = MemoryFilesystem::<FileBlockAllocator>::from_slice(initrd_data.data).unwrap();
fs.root()
}
use crate::proc;
/// Kernel's "main" process function.
///
@ -25,46 +14,47 @@ fn setup_root() -> Result<VnodeRef, Error> {
/// initialization has finished.
pub fn kinit() -> Result<(), Error> {
infoln!("In main");
loop {}
#[cfg(feature = "fb_console")]
{
use crate::{device::display::console::update_consoles_task, task::runtime};
// #[cfg(feature = "fb_console")]
// {
// use crate::{device::display::console::update_consoles_task, task::runtime};
runtime::spawn(async move {
update_consoles_task().await;
})?;
}
// runtime::spawn(async move {
// update_consoles_task().await;
// })?;
// }
let root = setup_root()?;
// let root = setup_root()?;
let ioctx = IoContext::new(root);
let node = ioctx.find(None, "/init", true, true)?;
let file = node.open(OpenOptions::READ)?;
// let ioctx = IoContext::new(root);
// let node = ioctx.find(None, "/init", true, true)?;
// let file = node.open(OpenOptions::READ)?;
let devfs = devfs::root();
#[cfg(target_arch = "x86_64")]
let console = ioctx.find(Some(devfs.clone()), "tty0", true, true)?;
#[cfg(target_arch = "aarch64")]
let console = ioctx.find(Some(devfs.clone()), "ttyS0", true, true)?;
let stdin = console.open(OpenOptions::READ)?;
let stdout = console.open(OpenOptions::WRITE)?;
let stderr = stdout.clone();
// let devfs = devfs::root();
// #[cfg(target_arch = "x86_64")]
// let console = ioctx.find(Some(devfs.clone()), "tty0", true, true)?;
// #[cfg(target_arch = "aarch64")]
// let console = ioctx.find(Some(devfs.clone()), "ttyS0", true, true)?;
// let stdin = console.open(OpenOptions::READ)?;
// let stdout = console.open(OpenOptions::WRITE)?;
// let stderr = stdout.clone();
{
// XXX
let (user_init, user_init_main) =
proc::exec::load_elf("init", file, &["/init", "xxx"], &[])?;
let mut io = user_init.io.lock();
io.set_ioctx(ioctx);
io.set_file(RawFd::STDIN, stdin)?;
io.set_file(RawFd::STDOUT, stdout)?;
io.set_file(RawFd::STDERR, stderr)?;
drop(io);
// {
// // XXX
// let (user_init, user_init_main) =
// proc::exec::load_elf("init", file, &["/init", "xxx"], &[])?;
// let mut io = user_init.io.lock();
// io.set_ioctx(ioctx);
// io.set_file(RawFd::STDIN, stdin)?;
// io.set_file(RawFd::STDOUT, stdout)?;
// io.set_file(RawFd::STDERR, stderr)?;
// drop(io);
user_init.set_session_terminal(console);
// user_init.set_session_terminal(console);
user_init_main.enqueue_somewhere();
}
// user_init_main.enqueue_somewhere();
// }
Ok(())
// Ok(())
}

View File

@ -34,7 +34,6 @@ use arch::Architecture;
use crate::{
arch::{ArchitectureImpl, ARCHITECTURE},
fs::sysfs,
mem::heap,
sync::SpinFence,
task::{spawn_kernel_closure, Cpu},
@ -51,7 +50,7 @@ pub mod debug;
pub mod arch;
pub mod device;
pub mod fs;
// pub mod fs;
pub mod init;
pub mod mem;
pub mod panic;
@ -89,7 +88,7 @@ pub fn kernel_main() -> ! {
debugln!("Heap: {:#x?}", heap::heap_range());
// Setup the sysfs
sysfs::init();
// sysfs::init();
unsafe {
ARCHITECTURE.start_application_processors();

View File

@ -7,7 +7,6 @@ use abi::{
process::ProgramArgumentInner,
};
use alloc::{string::String, sync::Arc};
use vfs::FileRef;
use crate::{
mem::{
@ -146,7 +145,8 @@ fn setup_binary<S: Into<String>>(
}
}
let tls_address = proc::elf::clone_tls(&space, &image)?;
// XXX
let tls_address = 0; // proc::elf::clone_tls(&space, &image)?;
let context = TaskContext::user(
image.entry,
@ -165,15 +165,15 @@ fn setup_binary<S: Into<String>>(
// Ok(Process::new_with_context(name, Some(space), context))
}
/// Loads an ELF bianary from `file` and sets up all the necessary data/argument memory
pub fn load_elf<S: Into<String>>(
name: S,
file: FileRef,
args: &[&str],
envs: &[&str],
) -> Result<(Arc<Process>, Arc<Thread>), Error> {
let space = ProcessAddressSpace::new()?;
let image = proc::elf::load_elf_from_file(&space, file)?;
setup_binary(name, space, image, args, envs)
}
// /// Loads an ELF bianary from `file` and sets up all the necessary data/argument memory
// pub fn load_elf<S: Into<String>>(
// name: S,
// file: FileRef,
// args: &[&str],
// envs: &[&str],
// ) -> Result<(Arc<Process>, Arc<Thread>), Error> {
// let space = ProcessAddressSpace::new()?;
// let image = proc::elf::load_elf_from_file(&space, file)?;
//
// setup_binary(name, space, image, args, envs)
// }

View File

@ -1,79 +1,12 @@
//! Process I/O management
use abi::{error::Error, io::RawFd};
use alloc::collections::{btree_map::Entry, BTreeMap};
use vfs::{FileRef, IoContext};
/// I/O context of a process, contains information like root, current directory and file
/// descriptor table
pub struct ProcessIo {
ioctx: Option<IoContext>,
files: BTreeMap<RawFd, FileRef>,
}
pub struct ProcessIo {}
impl ProcessIo {
/// Constructs an uninitialized I/O context
pub fn new() -> Self {
Self {
ioctx: None,
files: BTreeMap::new(),
}
}
/// Returns a file given descriptor refers to
pub fn file(&self, fd: RawFd) -> Result<FileRef, Error> {
self.files.get(&fd).cloned().ok_or(Error::InvalidFile)
}
/// Iterates over the file descriptors in [ProcessIo] and removes them if predicate is `false`
pub fn retain<F: Fn(&RawFd, &mut FileRef) -> bool>(&mut self, f: F) {
self.files.retain(f)
}
/// Sets the inner I/O context
pub fn set_ioctx(&mut self, ioctx: IoContext) {
self.ioctx.replace(ioctx);
}
/// Inserts a file into the descriptor table. Returns error if the file is already present for
/// given descriptor.
pub fn set_file(&mut self, fd: RawFd, file: FileRef) -> Result<(), Error> {
if self.files.contains_key(&fd) {
todo!();
}
self.files.insert(fd, file);
Ok(())
}
/// Allocates a slot for a file and returns it
pub fn place_file(&mut self, file: FileRef) -> Result<RawFd, Error> {
for idx in 0..64 {
let fd = RawFd(idx);
if let Entry::Vacant(e) = self.files.entry(fd) {
e.insert(file);
return Ok(fd);
}
}
todo!();
}
/// Closes the file and removes it from the table
pub fn close_file(&mut self, fd: RawFd) -> Result<(), Error> {
let file = self.files.remove(&fd);
if file.is_none() {
todo!();
}
Ok(())
}
/// Returns the inner I/O context reference
pub fn ioctx(&mut self) -> &mut IoContext {
self.ioctx.as_mut().unwrap()
}
/// Cleans up I/O context after the process exits
pub fn handle_exit(&mut self) {
self.files.clear();
todo!()
}
}

View File

@ -1,5 +1,5 @@
//! Internal management for processes
pub mod elf;
// pub mod elf;
pub mod exec;
pub mod io;

View File

@ -8,7 +8,7 @@ use abi::{
syscall::SyscallFunction,
};
use alloc::rc::Rc;
use vfs::{IoContext, Read, ReadDirectory, Seek, VnodeKind, VnodeRef, Write};
// use vfs::{IoContext, Read, ReadDirectory, Seek, VnodeKind, VnodeRef, Write};
use yggdrasil_abi::{
error::SyscallResult,
io::{MountOptions, UnmountOptions},
@ -17,7 +17,6 @@ use yggdrasil_abi::{
use crate::{
block,
debug::LogLevel,
fs,
mem::{phys, table::MapAttributes},
proc::{self, io::ProcessIo},
sync::IrqSafeSpinlockGuard,
@ -31,26 +30,26 @@ use crate::{
mod arg;
use arg::*;
fn run_with_io<T, F: FnOnce(IrqSafeSpinlockGuard<ProcessIo>) -> T>(proc: &Process, f: F) -> T {
let io = proc.io.lock();
f(io)
}
fn run_with_io_at<
T,
F: FnOnce(Option<VnodeRef>, IrqSafeSpinlockGuard<ProcessIo>) -> Result<T, Error>,
>(
proc: &Process,
at: Option<RawFd>,
f: F,
) -> Result<T, Error> {
let io = proc.io.lock();
let at = at
.map(|fd| io.file(fd).and_then(|f| f.borrow().node()))
.transpose()?;
f(at, io)
}
// fn run_with_io<T, F: FnOnce(IrqSafeSpinlockGuard<ProcessIo>) -> T>(proc: &Process, f: F) -> T {
// let io = proc.io.lock();
// f(io)
// }
//
// fn run_with_io_at<
// T,
// F: FnOnce(Option<VnodeRef>, IrqSafeSpinlockGuard<ProcessIo>) -> Result<T, Error>,
// >(
// proc: &Process,
// at: Option<RawFd>,
// f: F,
// ) -> Result<T, Error> {
// let io = proc.io.lock();
// let at = at
// .map(|fd| io.file(fd).and_then(|f| f.borrow().node()))
// .transpose()?;
//
// f(at, io)
// }
fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error> {
let thread = Thread::current();
@ -119,247 +118,7 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
Ok(0)
}
// I/O
SyscallFunction::Write => {
let fd = RawFd(args[0] as u32);
let data = arg_buffer_ref(args[1] as _, args[2] as _)?;
run_with_io(&process, |io| {
let file = io.file(fd)?;
let mut file_borrow = file.borrow_mut();
file_borrow.write(data)
})
}
SyscallFunction::Read => {
let fd = RawFd(args[0] as u32);
let data = arg_buffer_mut(args[1] as _, args[2] as _)?;
run_with_io(&process, |io| {
let file = io.file(fd)?;
let mut file_borrow = file.borrow_mut();
file_borrow.read(data)
})
}
SyscallFunction::Open => {
let at = arg_option_fd(args[0] as u32);
let path = arg_user_str(args[1] as usize, args[2] as usize)?;
let opts = OpenOptions::from(args[3] as u32);
let mode = FileMode::from(args[4] as u32);
run_with_io_at(&process, at, |at, mut io| {
let file = io.ioctx().open(at, path, opts, mode)?;
// TODO NO_CTTY?
if process.session_terminal().is_none() &&
let Ok(node) = file.borrow().node() && node.kind() == VnodeKind::Char {
debugln!("Session terminal set for #{}: {}", process.id(), path);
process.set_session_terminal(node);
}
let fd = io.place_file(file)?;
Ok(fd.0 as usize)
})
}
SyscallFunction::Close => {
let fd = RawFd(args[0] as u32);
run_with_io(&process, |mut io| {
io.close_file(fd)?;
Ok(0)
})
}
SyscallFunction::OpenDirectory => {
let at = arg_option_fd(args[0] as u32);
let path = arg_user_str(args[1] as usize, args[2] as usize)?;
run_with_io_at(&process, at, |at, mut io| {
let node = io.ioctx().find(at, path, true, true)?;
let file = node.open_directory()?;
let fd = io.place_file(file)?;
Ok(fd.0 as usize)
})
}
SyscallFunction::ReadDirectory => {
let fd = RawFd(args[0] as u32);
let buffer = arg_user_slice_mut::<MaybeUninit<DirectoryEntry>>(
args[1] as usize,
args[2] as usize,
)?;
run_with_io(&process, |io| {
let file = io.file(fd)?;
let mut file_borrow = file.borrow_mut();
file_borrow.read_dir_entries(buffer)
})
}
SyscallFunction::CreateDirectory => {
let at = arg_option_fd(args[0] as u32);
let path = arg_user_str(args[1] as usize, args[2] as usize)?;
let _mode = FileMode::from(args[3] as u32);
run_with_io_at(&process, at, |at, mut io| {
let (parent, name) = abi::path::split_right(path);
let parent_node = io.ioctx().find(at, parent, true, true)?;
todo!();
// parent_node.create(name, VnodeKind::Directory)?;
Ok(0)
})
}
SyscallFunction::Remove => {
let at = arg_option_fd(args[0] as u32);
let path = arg_user_str(args[1] as usize, args[2] as usize)?;
let recurse = args[3] != 0;
run_with_io_at(&process, at, |at, mut io| {
let node = io.ioctx().find(at, path, false, false)?;
if node.is_root() || Rc::ptr_eq(io.ioctx().root(), &node) {
todo!();
}
let parent = node.parent();
parent.remove(node, recurse)?;
Ok(0)
})
}
SyscallFunction::GetMetadata => {
let at = arg_option_fd(args[0] as u32);
let path = arg_user_str(args[1] as usize, args[2] as usize)?;
let buffer = arg_user_mut::<MaybeUninit<FileAttr>>(args[3] as usize)?;
let follow = args[4] != 0;
run_with_io_at(&process, at, |at, mut io| {
let node = if path.is_empty() {
at.ok_or(Error::InvalidArgument)?
} else {
io.ioctx().find(None, path, follow, true)?
};
let metadata = node.metadata()?;
buffer.write(metadata);
Ok(0)
})
}
SyscallFunction::Seek => {
let fd = RawFd(args[0] as u32);
let pos = SeekFrom::from(args[1]);
run_with_io(&process, |io| {
let file = io.file(fd)?;
let mut file_borrow = file.borrow_mut();
file_borrow.seek(pos).map(|v| v as usize)
})
}
SyscallFunction::Mount => {
let options = arg_user_ref::<MountOptions>(args[0] as usize)?;
run_with_io(&process, |mut io| {
let target_node = io.ioctx().find(None, options.target, true, false)?;
if !target_node.is_directory() {
return Err(Error::NotADirectory);
}
let fs_root = fs::create_filesystem(options)?;
target_node.mount(fs_root)?;
debugln!("{:?}", vfs::VnodeDump::new(io.ioctx().root().clone()));
Ok(0)
})
}
SyscallFunction::Unmount => {
let options = arg_user_ref::<UnmountOptions>(args[0] as usize)?;
run_with_io(&process, |mut io| {
let mountpoint = io.ioctx().find(None, options.mountpoint, true, false)?;
mountpoint.unmount_target()?;
debugln!("{:?}", vfs::VnodeDump::new(io.ioctx().root().clone()));
Ok(0)
})
}
SyscallFunction::DeviceRequest => {
let fd = RawFd(args[0] as u32);
let req = arg_user_mut::<DeviceRequest>(args[1] as usize)?;
run_with_io(&process, |io| {
let file = io.file(fd)?;
let node = file.borrow().node()?;
node.device_request(req)?;
Ok(0)
})
}
// Process management
SyscallFunction::SpawnProcess => {
let options = arg_user_ref::<SpawnOptions>(args[0] as usize)?;
run_with_io(&process, |mut io| {
let node = io.ioctx().find(None, options.program, true, true)?;
// Setup a new process from the file
let file = node.open(OpenOptions::READ)?;
let (child_process, child_main) = proc::exec::load_elf(
options.program,
file,
options.arguments,
options.environment,
)?;
let pid: u32 = child_process.id().into();
// Inherit group and session from the creator
child_process.inherit(&process)?;
// Inherit root from the creator
let child_ioctx = IoContext::new(io.ioctx().root().clone());
let mut child_io = child_process.io.lock();
child_io.set_ioctx(child_ioctx);
for opt in options.optional {
match opt {
&SpawnOption::InheritFile { source, child } => {
let src_file = io.file(source)?;
child_io.set_file(child, src_file)?;
}
&SpawnOption::SetProcessGroup(pgroup) => {
child_process.set_group_id(pgroup.into());
}
_ => (),
}
}
if let Some(fd) = options.optional.iter().find_map(|item| {
if let &SpawnOption::GainTerminal(fd) = item {
Some(fd)
} else {
None
}
}) {
debugln!("{} requested terminal {:?}", pid, fd);
let file = child_io.file(fd)?;
let node = file.borrow().node()?;
let mut req = DeviceRequest::SetTerminalGroup(child_process.group_id().into());
node.device_request(&mut req)?;
}
drop(child_io);
child_main.enqueue_somewhere();
Ok(pid as _)
})
}
SyscallFunction::SpawnThread => {
let options = arg_user_ref::<ThreadSpawnOptions>(args[0] as usize)?;
let id = process.spawn_thread(options)?;
@ -421,26 +180,6 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
process.set_group_id(group_id);
Ok(0)
}
SyscallFunction::StartSession => {
let session_terminal = process.clear_session_terminal();
if let Some(ctty) = session_terminal {
// Drop all FDs referring to the old session terminal
run_with_io(&process, |mut io| {
io.retain(|_, f| {
f.borrow()
.node()
.map(|node| !Rc::ptr_eq(&node, &ctty))
.unwrap_or(true)
});
});
}
process.set_session_id(process.id());
process.set_group_id(process.id());
Ok(0)
}
// Waiting and polling
SyscallFunction::WaitProcess => {
let pid = ProcessId::from(args[0] as u32);
@ -458,6 +197,10 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
Ok(0)
}
_ => {
todo!("System call: {:?}", func);
}
}
}

View File

@ -20,7 +20,6 @@ use alloc::{
};
use futures_util::Future;
use kernel_util::util::OneTimeInit;
use vfs::VnodeRef;
use crate::{
mem::{
@ -131,8 +130,7 @@ struct ProcessInner {
session_id: ProcessId,
group_id: ProcessId,
session_terminal: Option<VnodeRef>,
// session_terminal: Option<VnodeRef>,
threads: Vec<Arc<Thread>>,
mutexes: BTreeMap<usize, Arc<UserspaceMutex>>,
}
@ -173,7 +171,7 @@ impl Process {
state: ProcessState::Running,
session_id: id,
group_id: id,
session_terminal: None,
// session_terminal: None,
threads: Vec::new(),
mutexes: BTreeMap::new(),
}),
@ -199,7 +197,8 @@ impl Process {
);
let tls_address = if let Some(image) = self.image.as_ref() {
proc::elf::clone_tls(&self.space, image)?
todo!()
// proc::elf::clone_tls(&self.space, image)?
} else {
0
};
@ -247,28 +246,28 @@ impl Process {
}
// Resources
pub fn session_terminal(&self) -> Option<VnodeRef> {
self.inner.lock().session_terminal.clone()
}
// pub fn session_terminal(&self) -> Option<VnodeRef> {
// self.inner.lock().session_terminal.clone()
// }
pub fn set_session_terminal(&self, node: VnodeRef) {
self.inner.lock().session_terminal.replace(node);
}
// pub fn set_session_terminal(&self, node: VnodeRef) {
// self.inner.lock().session_terminal.replace(node);
// }
pub fn clear_session_terminal(&self) -> Option<VnodeRef> {
self.inner.lock().session_terminal.take()
}
// pub fn clear_session_terminal(&self) -> Option<VnodeRef> {
// self.inner.lock().session_terminal.take()
// }
pub fn inherit(&self, parent: &Process) -> Result<(), Error> {
let mut our_inner = self.inner.lock();
let their_inner = parent.inner.lock();
// pub fn inherit(&self, parent: &Process) -> Result<(), Error> {
// let mut our_inner = self.inner.lock();
// let their_inner = parent.inner.lock();
our_inner.session_id = their_inner.session_id;
our_inner.group_id = their_inner.group_id;
our_inner.session_terminal = their_inner.session_terminal.clone();
// our_inner.session_id = their_inner.session_id;
// our_inner.group_id = their_inner.group_id;
// our_inner.session_terminal = their_inner.session_terminal.clone();
Ok(())
}
// Ok(())
// }
// State
pub fn get_exit_status(&self) -> Option<ExitCode> {
@ -319,7 +318,8 @@ impl Process {
inner.state = ProcessState::Terminated(code);
self.io.lock().handle_exit();
// XXX
// self.io.lock().handle_exit();
drop(inner);