Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions kernel/src/device/virtio/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::mem::dma::{DmaError, DmaRegion, DmaRegionProvider};
use crate::trap::{CurrentTrapFrame, TrapInfo};
use crate::util::lazylock::LazyLock;
use crate::util::spinlock::SpinLock;

use core::sync::atomic::fence;
use core::sync::atomic::{AtomicBool, Ordering};

Expand Down
3 changes: 3 additions & 0 deletions kernel/src/fs/DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
- Each process owns its own `FdTable` and current working directory; `open` resolves a `Node`,
calls `Node::open`, and binds the resulting `File` to an FD in the process table. Container
processes route path resolution through the container VFS instead of the global VFS.
- Directory FDs expose their backing `Node` so `openat`/`newfstatat` can resolve relative paths
against the directory handle itself. Directory nodes track parent/name metadata so the kernel
can reconstruct a mount-aware absolute path when needed (e.g. for mount-point resolution).
- Common filesystem helpers that operate directly on `Node` live in `fs::ops`; any process-aware
path handling stays in `process::fs`.
- The VFS differentiates node kinds via `NodeKind` (regular/dir/symlink/device/etc.); device nodes
Expand Down
13 changes: 13 additions & 0 deletions kernel/src/fs/fd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,19 @@ impl FdTable {
Ok(fd)
}

pub fn open_file_with_flags(
&self,
file: Arc<dyn File>,
close_on_exec: bool,
) -> Result<Fd, VfsError> {
let mut guard = self.inner.lock();
let fd = guard.allocate_fd(self.next_fd.fetch_add(1, Ordering::AcqRel));
let mut entry = FdEntry::new(file);
entry.set_close_on_exec(close_on_exec);
guard.set(fd, entry)?;
Ok(fd)
}

pub fn open_fixed(&self, fd: Fd, file: Arc<dyn File>) -> Result<(), VfsError> {
let mut guard = self.inner.lock();
if guard.exists(fd) {
Expand Down
13 changes: 10 additions & 3 deletions kernel/src/fs/file.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use alloc::vec::Vec;
use alloc::{sync::Arc, vec::Vec};
use core::any::Any;

use super::{DirEntry, VfsError};
use super::{DirEntry, Node, VfsError};
use crate::util::stream::{ControlError, ControlRequest};

/// Per-open handle that performs I/O and control operations.
pub trait File: Send + Sync {
pub trait File: Send + Sync + Any {
fn read(&self, buf: &mut [u8]) -> Result<usize, VfsError>;

fn write(&self, _data: &[u8]) -> Result<usize, VfsError> {
Expand All @@ -22,4 +23,10 @@ pub trait File: Send + Sync {
fn ioctl(&self, _request: &ControlRequest<'_>) -> Result<u64, ControlError> {
Err(ControlError::Unsupported)
}

fn dir_node(&self) -> Option<Arc<dyn Node>> {
None
}

fn as_any(&self) -> &dyn Any;
}
8 changes: 8 additions & 0 deletions kernel/src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub enum VfsError {
AlreadyMounted,
AlreadyExists,
InvalidPath,
BadFd,
NotFound,
NotDirectory,
NotFile,
Expand Down Expand Up @@ -116,6 +117,13 @@ impl Vfs {
self.resolve_absolute(path, 0)
}

pub fn mount_path_for_node(&self, node: &Arc<dyn Node>) -> Option<Path> {
self.mounts
.iter()
.find(|mount| Arc::ptr_eq(&mount.root, node))
.map(|mount| mount.path.clone())
}

fn inject_mount_points(&self, path: &Path, entries: &mut Vec<DirEntry>) {
let base_components = path.components();
for mount in &self.mounts {
Expand Down
4 changes: 4 additions & 0 deletions kernel/src/fs/node/char_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,8 @@ where
fn ioctl(&self, request: &ControlRequest<'_>) -> Result<u64, ControlError> {
self.device.control(request)
}

fn as_any(&self) -> &dyn core::any::Any {
self
}
}
8 changes: 8 additions & 0 deletions kernel/src/fs/node/directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ pub trait DirNode: Send + Sync {
fn lookup(&self, name: &PathComponent) -> Result<Arc<dyn Node>, VfsError>;
fn read_dir(&self) -> Result<Vec<DirEntry>, VfsError>;

fn parent(&self) -> Option<Arc<dyn Node>> {
None
}

fn name(&self) -> Option<&str> {
None
}

fn create_file(&self, _name: &str) -> Result<Arc<dyn Node>, VfsError> {
Err(VfsError::ReadOnly)
}
Expand Down
50 changes: 43 additions & 7 deletions kernel/src/fs/vfs/fat32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use alloc::{
boxed::Box,
format,
string::{String, ToString},
sync::Arc,
sync::{Arc, Weak},
vec,
vec::Vec,
};
Expand Down Expand Up @@ -79,9 +79,12 @@ impl<D: BlockDevice + Send> FatFileSystem<D> {
}
let volume = Arc::new(FatVolume::new(device, bpb)?);
let chain = volume.cluster_chain(volume.bpb.root_cluster)?;
let root = Arc::new(FatDirectory {
let root = Arc::new_cyclic(|self_ref| FatDirectory {
volume: volume.clone(),
chain,
parent: None,
name: None,
self_ref: self_ref.clone(),
});
Ok(Self { root })
}
Expand Down Expand Up @@ -376,6 +379,9 @@ impl BiosParameterBlock {
pub struct FatDirectory<D: BlockDevice + Send> {
volume: Arc<FatVolume<D>>,
chain: Vec<u32>,
parent: Option<Weak<FatDirectory<D>>>,
name: Option<String>,
self_ref: Weak<FatDirectory<D>>,
}

struct FatDirFile<D: BlockDevice + Send> {
Expand All @@ -396,6 +402,14 @@ impl<D: BlockDevice + Send + 'static> File for FatDirFile<D> {
fn readdir(&self) -> Result<Vec<DirEntry>, VfsError> {
self.node.read_dir()
}

fn dir_node(&self) -> Option<Arc<dyn Node>> {
Some(self.node.clone())
}

fn as_any(&self) -> &dyn core::any::Any {
self
}
}

impl<D: BlockDevice + Send + 'static> Node for FatDirectory<D> {
Expand Down Expand Up @@ -461,13 +475,20 @@ impl<D: BlockDevice + Send + 'static> DirNode for FatDirectory<D> {
}
if entry.cmp_name == target {
return match entry.kind {
NodeKind::Directory => Ok(Arc::new(FatDirectory {
volume: self.volume.clone(),
chain: self
NodeKind::Directory => {
let chain = self
.volume
.cluster_chain(entry.first_cluster)
.map_err(|_| VfsError::Corrupted)?,
})),
.map_err(|_| VfsError::Corrupted)?;
let parent = self.self_ref.upgrade().ok_or(VfsError::Corrupted)?;
Ok(Arc::new_cyclic(|self_ref| FatDirectory {
volume: self.volume.clone(),
chain,
parent: Some(Arc::downgrade(&parent)),
name: Some(entry.name.clone()),
self_ref: self_ref.clone(),
}))
}
NodeKind::Regular => Ok(Arc::new(FatFileNode {
volume: self.volume.clone(),
clusters: self
Expand All @@ -483,6 +504,17 @@ impl<D: BlockDevice + Send + 'static> DirNode for FatDirectory<D> {
}
Err(VfsError::NotFound)
}

fn parent(&self) -> Option<Arc<dyn Node>> {
self.parent
.as_ref()
.and_then(|parent| parent.upgrade())
.map(|parent| parent as Arc<dyn Node>)
}

fn name(&self) -> Option<&str> {
self.name.as_deref()
}
}

pub struct FatFileNode<D: BlockDevice + Send> {
Expand Down Expand Up @@ -529,6 +561,10 @@ impl<D: BlockDevice + Send + 'static> File for FatFileHandle<D> {
*guard = next;
Ok(next as u64)
}

fn as_any(&self) -> &dyn core::any::Any {
self
}
}

impl<D: BlockDevice + Send + 'static> Node for FatFileNode<D> {
Expand Down
41 changes: 38 additions & 3 deletions kernel/src/fs/vfs/memfs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use alloc::{
collections::BTreeMap,
string::{String, ToString},
sync::Arc,
sync::{Arc, Weak},
vec::Vec,
};

Expand All @@ -15,6 +15,9 @@ use crate::fs::{
/// Simple in-memory writable filesystem backed by a tree of nodes.
pub struct MemDirectory {
inner: SpinLock<DirInner>,
parent: Option<Weak<MemDirectory>>,
name: Option<String>,
self_ref: Weak<MemDirectory>,
}

struct DirInner {
Expand All @@ -23,10 +26,17 @@ struct DirInner {

impl MemDirectory {
pub fn new() -> Arc<Self> {
Arc::new(Self {
Self::new_with_parent(None, None)
}

fn new_with_parent(parent: Option<Weak<MemDirectory>>, name: Option<String>) -> Arc<Self> {
Arc::new_cyclic(|self_ref| Self {
inner: SpinLock::new(DirInner {
entries: BTreeMap::new(),
}),
parent,
name,
self_ref: self_ref.clone(),
})
}
}
Expand Down Expand Up @@ -130,6 +140,10 @@ impl File for MemFileHandle {
*guard = next;
Ok(next as u64)
}

fn as_any(&self) -> &dyn core::any::Any {
self
}
}

struct MemDirFile {
Expand All @@ -154,6 +168,14 @@ impl File for MemDirFile {
fn readdir(&self) -> Result<Vec<DirEntry>, VfsError> {
self.node.read_dir()
}

fn dir_node(&self) -> Option<Arc<dyn Node>> {
Some(self.node.clone())
}

fn as_any(&self) -> &dyn core::any::Any {
self
}
}

impl Node for MemFileNode {
Expand Down Expand Up @@ -216,6 +238,17 @@ impl DirNode for MemDirectory {
.ok_or(VfsError::NotFound)
}

fn parent(&self) -> Option<Arc<dyn Node>> {
self.parent
.as_ref()
.and_then(|parent| parent.upgrade())
.map(|parent| parent as Arc<dyn Node>)
}

fn name(&self) -> Option<&str> {
self.name.as_deref()
}

fn create_file(&self, name: &str) -> Result<Arc<dyn Node>, VfsError> {
let mut inner = self.inner.lock();
if inner.entries.contains_key(name) {
Expand All @@ -231,7 +264,9 @@ impl DirNode for MemDirectory {
if inner.entries.contains_key(name) {
return Err(VfsError::AlreadyExists);
}
let dir = MemDirectory::new();
let parent = self.self_ref.upgrade().ok_or(VfsError::Corrupted)?;
let dir =
MemDirectory::new_with_parent(Some(Arc::downgrade(&parent)), Some(name.to_string()));
inner.entries.insert(name.to_string(), dir.clone());
Ok(dir)
}
Expand Down
2 changes: 2 additions & 0 deletions kernel/src/kernel_proc/DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
(`cc`/`gcc`/`clang`) into `target/xtask-assets/linux-syscall.elf`.
- Additional syscall coverage comes from `linux-syscall-adv.elf` plus its exec target
`linux-syscall-child.elf`, built via `xtask-assets` from `xtask-assets/fixtures`.
- TCP socket syscall coverage uses `linux-syscall-net.elf`, built via `xtask-assets` from
`xtask-assets/fixtures`, with a kernel-side smoltcp client driving the accept path.
- `xtask` also runs the linux-syscall binary on the host to confirm Linux and Cyrius produce the
same stdout for the stdin/file I/O scenario.

Expand Down
Loading