Skip to content

Commit

Permalink
Implements tmpfs root, mkdir and lookup (#733)
Browse files Browse the repository at this point in the history
Co-authored-by: tompro <tomas.prochazka@apertia.cz>
  • Loading branch information
SuchAFuriousDeath and SuchAFuriousDeath authored Mar 18, 2024
1 parent 921969c commit 5675e20
Show file tree
Hide file tree
Showing 16 changed files with 410 additions and 129 deletions.
2 changes: 1 addition & 1 deletion src/elf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub struct Elf<I: Read + Seek> {
}

impl<I: Read + Seek> Elf<I> {
pub fn open<N: Into<String>>(name: N, mut image: I) -> Result<Self, OpenError> {
pub fn open(name: impl Into<String>, mut image: I) -> Result<Self, OpenError> {
// Seek to file header.
if let Err(e) = image.rewind() {
return Err(OpenError::SeekFailed(0, e));
Expand Down
97 changes: 49 additions & 48 deletions src/kernel/src/fs/dev/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ pub use self::cdev::*;
use self::dirent::Dirent;
use self::vnode::VnodeBackend;
use super::{
path_contains, DirentType, Filesystem, FsConfig, Mode, Mount, MountFlags, MountOpts,
path_contains, DirentType, Filesystem, Fs, FsConfig, Mode, Mount, MountFlags, MountOpts,
MountSource, VPathBuf, Vnode, VnodeItem, VnodeType,
};
use crate::errno::{Errno, EEXIST, ENOENT, EOPNOTSUPP};
Expand Down Expand Up @@ -79,52 +79,6 @@ pub fn dev_exists(name: impl AsRef<str>) -> bool {
false
}

/// See `devfs_allocv` on the PS4 for a reference.
fn alloc_vnode(
fs: Arc<DevFs>,
mnt: &Arc<Mount>,
ent: Arc<Dirent>,
) -> Result<Arc<Vnode>, AllocVnodeError> {
// Check for active vnode.
let mut current = ent.vnode_mut();

if let Some(v) = current.as_ref().and_then(|v| v.upgrade()) {
return Ok(v);
}

// Create vnode. Beware of deadlock because we are currently holding on dirent lock.
let tag = "devfs";
let backend = VnodeBackend::new(fs, ent.clone());
let vn = match ent.ty() {
DirentType::Character => {
let dev = ent
.cdev()
.unwrap()
.upgrade()
.ok_or(AllocVnodeError::DeviceGone)?;
let vn = Vnode::new(mnt, VnodeType::CharacterDevice, tag, backend);

*vn.item_mut() = Some(VnodeItem::Device(dev));
vn
}
DirentType::Directory => Vnode::new(
mnt,
VnodeType::Directory(ent.inode() == DevFs::DEVFS_ROOTINO),
tag,
backend,
),
DirentType::Link => todo!("devfs_allocv with DT_LNK"),
};

// Set current vnode.

*current = Some(Arc::downgrade(&vn));
drop(current);

// TODO: Implement insmntque1.
Ok(vn)
}

/// An implementation of `devfs_mount` structure.
#[derive(Debug)]
pub struct DevFs {
Expand Down Expand Up @@ -285,6 +239,52 @@ impl DevFs {
dir.children_mut().push(Arc::new(dd));
dir
}

/// See `devfs_allocv` on the PS4 for a reference.
fn alloc_vnode(
self: &Arc<DevFs>,
mnt: &Arc<Mount>,
ent: Arc<Dirent>,
) -> Result<Arc<Vnode>, AllocVnodeError> {
// Check for active vnode.
let mut current = ent.vnode_mut();

if let Some(v) = current.as_ref().and_then(|v| v.upgrade()) {
return Ok(v);
}

// Create vnode. Beware of deadlock because we are currently holding on dirent lock.
let tag = "devfs";
let backend = VnodeBackend::new(self.clone(), ent.clone());
let vn = match ent.ty() {
DirentType::Character => {
let dev = ent
.cdev()
.unwrap()
.upgrade()
.ok_or(AllocVnodeError::DeviceGone)?;
let vn = Vnode::new(mnt, VnodeType::CharacterDevice, tag, backend);

*vn.item_mut() = Some(VnodeItem::Device(dev));
vn
}
DirentType::Directory => Vnode::new(
mnt,
VnodeType::Directory(ent.inode() == DevFs::DEVFS_ROOTINO),
tag,
backend,
),
DirentType::Link => todo!("devfs_allocv with DT_LNK"),
};

// Set current vnode.

*current = Some(Arc::downgrade(&vn));
drop(current);

// TODO: Implement insmntque1.
Ok(vn)
}
}

bitflags! {
Expand Down Expand Up @@ -317,6 +317,7 @@ pub enum MakeDevError {
}

pub fn mount(
_: Option<&Arc<Fs>>,
conf: &'static FsConfig,
cred: &Arc<Ucred>,
path: VPathBuf,
Expand Down Expand Up @@ -353,7 +354,7 @@ impl Filesystem for DevFs {
fn root(self: Arc<Self>, mnt: &Arc<Mount>) -> Result<Arc<Vnode>, Box<dyn Errno>> {
let ent = self.root.clone();

let vnode = alloc_vnode(self, mnt, ent)?;
let vnode = self.alloc_vnode(mnt, ent)?;

Ok(vnode)
}
Expand Down
6 changes: 3 additions & 3 deletions src/kernel/src/fs/dev/vnode.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::dirent::Dirent;
use super::{alloc_vnode, AllocVnodeError, DevFs};
use super::{AllocVnodeError, DevFs};
use crate::errno::{Errno, EIO, ENOENT, ENOTDIR, ENXIO};
use crate::fs::{
check_access, Access, IoCmd, OpenFlags, RevokeFlags, VFile, Vnode, VnodeAttrs, VnodeItem,
Expand Down Expand Up @@ -140,7 +140,7 @@ impl crate::fs::VnodeBackend for VnodeBackend {
None => return Err(Box::new(LookupError::NoParent)),
};

match alloc_vnode(self.fs.clone(), vn.fs(), parent) {
match self.fs.alloc_vnode(vn.mount(), parent) {
Ok(v) => Ok(v),
Err(e) => Err(Box::new(LookupError::AllocVnodeFailed(e))),
}
Expand All @@ -155,7 +155,7 @@ impl crate::fs::VnodeBackend for VnodeBackend {
None => todo!("devfs lookup with non-existent file"),
};

match alloc_vnode(self.fs.clone(), vn.fs(), item) {
match self.fs.alloc_vnode(vn.mount(), item) {
Ok(v) => Ok(v),
Err(e) => Err(Box::new(LookupError::AllocVnodeFailed(e))),
}
Expand Down
3 changes: 2 additions & 1 deletion src/kernel/src/fs/host/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use self::file::{HostFile, HostId};
use self::vnode::VnodeBackend;
use super::{
Filesystem, FsConfig, Mount, MountFlags, MountOpt, MountOpts, MountSource, VPathBuf, Vnode,
Filesystem, Fs, FsConfig, Mount, MountFlags, MountOpt, MountOpts, MountSource, VPathBuf, Vnode,
VnodeType,
};
use crate::errno::{Errno, EIO};
Expand All @@ -28,6 +28,7 @@ pub struct HostFs {
}

pub fn mount(
_: Option<&Arc<Fs>>,
conf: &'static FsConfig,
cred: &Arc<Ucred>,
path: VPathBuf,
Expand Down
4 changes: 2 additions & 2 deletions src/kernel/src/fs/host/vnode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ impl crate::fs::VnodeBackend for VnodeBackend {
// Get vnode.
let vn = self
.fs
.get_vnode(vn.fs(), &file)
.get_vnode(vn.mount(), &file)
.map_err(LookupError::GetVnodeFailed)?;

Ok(vn)
Expand All @@ -110,7 +110,7 @@ impl crate::fs::VnodeBackend for VnodeBackend {
.map_err(|e| MkDirError::from(e))?;
let vn = self
.fs
.get_vnode(parent.fs(), &dir)
.get_vnode(parent.mount(), &dir)
.map_err(MkDirError::GetVnodeFailed)?;

Ok(vn)
Expand Down
25 changes: 16 additions & 9 deletions src/kernel/src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ impl Fs {
let mut mounts = Mounts::new();
let conf = Self::find_config("devfs").unwrap();
let init = (conf.mount)(
None,
conf,
kern_cred,
vpath!("/dev").to_owned(),
Expand Down Expand Up @@ -214,15 +215,15 @@ impl Fs {

// Prevent ".." on root so this cannot escape from chroot.
if com == ".." && Arc::ptr_eq(&resolved, &root) {
return Err(LookupError::NotFound);
return Err(LookupError::EscapeChroot);
}

// Lookup next component.
vn = match resolved.lookup(td, com) {
Ok(v) => v,
Err(e) => {
if e.errno() == ENOENT {
return Err(LookupError::NotFound);
return Err(LookupError::NotFound(e));
} else {
return Err(LookupError::LookupFailed(
i,
Expand Down Expand Up @@ -330,6 +331,7 @@ impl Fs {

// TODO: Implement budgetid.
let mount = (conf.mount)(
Some(self),
conf,
td.map_or(&self.kern_cred, |t| t.cred()),
path,
Expand Down Expand Up @@ -939,6 +941,7 @@ pub struct FsConfig {
ty: u32, // vfc_typenum
next: Option<&'static FsConfig>, // vfc_list.next
mount: fn(
fs: Option<&Arc<Fs>>,
conf: &'static Self,
cred: &Arc<Ucred>,
path: VPathBuf,
Expand Down Expand Up @@ -1137,7 +1140,11 @@ pub enum LookupError {

#[error("no such file or directory")]
#[errno(ENOENT)]
NotFound,
EscapeChroot,

#[error("no such file or directory")]
#[errno(ENOENT)]
NotFound(#[source] Box<dyn Errno>),

#[error("cannot lookup '{1}' from component #{0}")]
LookupFailed(usize, Box<str>, #[source] Box<dyn Errno>),
Expand Down Expand Up @@ -1228,14 +1235,14 @@ static MLFS: FsConfig = FsConfig {
name: "mlfs",
ty: 0xF1,
next: Some(&UDF2),
mount: |_, _, _, _, _, _| todo!("mount for mlfs"),
mount: |_, _, _, _, _, _, _| todo!("mount for mlfs"),
};

static UDF2: FsConfig = FsConfig {
name: "udf2",
ty: 0,
next: Some(&DEVFS),
mount: |_, _, _, _, _, _| todo!("mount for udf2"),
mount: |_, _, _, _, _, _, _| todo!("mount for udf2"),
};

static DEVFS: FsConfig = FsConfig {
Expand All @@ -1256,28 +1263,28 @@ static UNIONFS: FsConfig = FsConfig {
name: "unionfs",
ty: 0x41,
next: Some(&PROCFS),
mount: |_, _, _, _, _, _| todo!("mount for unionfs"),
mount: |_, _, _, _, _, _, _| todo!("mount for unionfs"),
};

static PROCFS: FsConfig = FsConfig {
name: "procfs",
ty: 0x2,
next: Some(&CD9660),
mount: |_, _, _, _, _, _| todo!("mount for procfs"),
mount: |_, _, _, _, _, _, _| todo!("mount for procfs"),
};

static CD9660: FsConfig = FsConfig {
name: "cd9660",
ty: 0xBD,
next: Some(&UFS),
mount: |_, _, _, _, _, _| todo!("mount for cd9660"),
mount: |_, _, _, _, _, _, _| todo!("mount for cd9660"),
};

static UFS: FsConfig = FsConfig {
name: "ufs",
ty: 0x35,
next: Some(&NULLFS),
mount: |_, _, _, _, _, _| todo!("mount for ufs"),
mount: |_, _, _, _, _, _, _| todo!("mount for ufs"),
};

static NULLFS: FsConfig = FsConfig {
Expand Down
13 changes: 13 additions & 0 deletions src/kernel/src/fs/mount.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::{FsConfig, Mode, VPathBuf, Vnode};
use crate::arnd;
use crate::errno::Errno;
use crate::ucred::{Gid, Ucred, Uid};
use bitflags::bitflags;
Expand All @@ -9,6 +10,7 @@ use std::collections::HashMap;
use std::convert::Infallible;
use std::fmt::Formatter;
use std::fmt::{Debug, Display, Error};
use std::hash::{Hash, Hasher};
use std::hint::unreachable_unchecked;
use std::path::PathBuf;
use std::sync::{Arc, Mutex, RwLock, RwLockWriteGuard};
Expand Down Expand Up @@ -78,6 +80,7 @@ pub struct Mount {
cred: Arc<Ucred>, // mnt_cred
parent: RwLock<Option<Arc<Vnode>>>, // mnt_vnodecovered
flags: MountFlags, // mnt_flag
hashseed: u32, // mnt_hashseed
stats: FsStats, // mnt_stat
}

Expand All @@ -101,6 +104,12 @@ impl Mount {
cred: cred.clone(),
parent: RwLock::new(parent),
flags,
hashseed: {
let mut buf = [0u8; 4];
arnd::rand_bytes(&mut buf);

u32::from_ne_bytes(buf)
},
stats: FsStats {
ty: config.ty,
id: [0; 2],
Expand All @@ -119,6 +128,10 @@ impl Mount {
self.flags
}

pub fn hashseed(&self) -> u32 {
self.hashseed
}

pub fn parent_mut(&self) -> RwLockWriteGuard<Option<Arc<Vnode>>> {
self.parent.write().unwrap()
}
Expand Down
36 changes: 36 additions & 0 deletions src/kernel/src/fs/null/hash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use crate::fs::{Mount, Vnode};
use std::{
collections::HashMap,
sync::{Arc, Mutex},
};

pub(super) static NULL_HASHTABLE: Mutex<NullHashTable> = Mutex::new(NullHashTable(None));

// Maps a hash to a pair of (lower vnode, null vnode).
pub(super) struct NullHashTable(Option<HashMap<u32, (Arc<Vnode>, Arc<Vnode>)>>);

impl NullHashTable {
/// See `null_hashget` on the PS4 for a reference.
pub(super) fn get(&mut self, mnt: &Arc<Mount>, lower: &Arc<Vnode>) -> Option<Arc<Vnode>> {
let table = self.0.get_or_insert(HashMap::new());

let hash = lower.hash_index();

let (stored_lower, nullnode) = table.get(&hash)?;

if Arc::ptr_eq(lower, stored_lower) && Arc::ptr_eq(nullnode.mount(), mnt) {
return Some(nullnode.clone());
}

None
}

/// See `null_hashins` on the PS4 for a reference.
pub(super) fn insert(&mut self, mnt: &Arc<Mount>, lower: &Arc<Vnode>, nullnode: &Arc<Vnode>) {
let table = self.0.get_or_insert(HashMap::new());

let hash_index = lower.hash_index();

table.insert(hash_index, (lower.clone(), nullnode.clone()));
}
}
Loading

0 comments on commit 5675e20

Please sign in to comment.