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
2 changes: 2 additions & 0 deletions libkernel/src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ bitflags::bitflags! {
// Reserved psuedo filesystem instances created internally in the kernel.
pub const DEVFS_ID: u64 = 1;
pub const PROCFS_ID: u64 = 2;
pub const SYSFS_ID: u64 = 3;
pub const CGROUPFS_ID: u64 = 4;
pub const FS_ID_START: u64 = 10;

/// Trait for a mounted filesystem instance. Its main role is to act as a
Expand Down
2 changes: 1 addition & 1 deletion scripts/qemu-runner.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ bin="${elf%.elf}.bin"

# Convert to binary format
aarch64-none-elf-objcopy -O binary "$elf" "$bin"
qemu-system-aarch64 -M virt,gic-version=3 -initrd moss.img -cpu cortex-a72 -m 2G -smp 4 -nographic -s -kernel "$bin" -append "$append_args --rootfs=ext4fs --automount=/dev,devfs --automount=/tmp,tmpfs --automount=/proc,procfs"
qemu-system-aarch64 -M virt,gic-version=3 -initrd moss.img -cpu cortex-a72 -m 2G -smp 4 -nographic -s -kernel "$bin" -append "$append_args --rootfs=ext4fs --automount=/dev,devfs --automount=/tmp,tmpfs --automount=/proc,procfs --automount=/sys,sysfs"
1 change: 1 addition & 0 deletions scripts/symlinks.cmds
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mkdir /bin
mkdir /dev
mkdir /proc
mkdir /sys
mkdir /tmp
symlink /bin/[ /bin/busybox
symlink /bin/[[ /bin/busybox
Expand Down
177 changes: 177 additions & 0 deletions src/drivers/fs/cgroup/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
use crate::drivers::Driver;
use crate::fs::FilesystemDriver;
use crate::sync::OnceLock;
use alloc::boxed::Box;
use alloc::sync::Arc;
use alloc::vec::Vec;
use async_trait::async_trait;
use core::hash::Hasher;
use libkernel::error::FsError;
use libkernel::fs::attr::FileAttr;
use libkernel::fs::{
BlockDevice, CGROUPFS_ID, DirStream, Dirent, FileType, Inode, InodeId, SimpleDirStream,
};
use libkernel::{
error::{KernelError, Result},
fs::Filesystem,
};
use log::warn;

/// Deterministically generates an inode ID for the given path segments within the sysfs filesystem.
fn get_inode_id(path_segments: &[&str]) -> u64 {
let mut hasher = rustc_hash::FxHasher::default();
// Ensure non-collision if other filesystems also use this method
hasher.write(b"cgroupfs");
for segment in path_segments {
hasher.write(segment.as_bytes());
}
let hash = hasher.finish();
assert_ne!(hash, 0, "Generated inode ID cannot be zero");
hash
}

macro_rules! static_dir {
($name:ident, $path:expr, $( $entry_name:expr => $entry_type:expr, $entry_ident:ident ),* $(,)? ) => {
struct $name {
id: InodeId,
attr: FileAttr,
}

impl $name {
fn new(id: InodeId) -> Self {
Self {
id,
attr: FileAttr {
file_type: FileType::Directory,
..FileAttr::default()
},
}
}

const fn num_entries() -> usize {
0 $(+ { let _ = $entry_name; 1 })*
}
}

#[async_trait]
impl Inode for $name {
fn id(&self) -> InodeId {
self.id
}

async fn getattr(&self) -> Result<FileAttr> {
Ok(self.attr.clone())
}

async fn lookup(&self, name: &str) -> Result<Arc<dyn Inode>> {
match name {
$(
$entry_name => {
let inode_id = InodeId::from_fsid_and_inodeid(
SYSFS_ID,
get_inode_id(&[$path, $entry_name]),
);
Ok(Arc::new($entry_ident::new(inode_id)))
},
)*
_ => Err(KernelError::Fs(FsError::NotFound)),
}
}

async fn readdir(&self, start_offset: u64) -> Result<Box<dyn DirStream>> {
#[allow(unused_mut)]
let mut entries: Vec<Dirent> = Vec::with_capacity(Self::num_entries());
$(
entries.push(Dirent {
id: InodeId::from_fsid_and_inodeid(
SYSFS_ID,
get_inode_id(&[$path, $entry_name]),
),
name: $entry_name.to_string(),
offset: (entries.len() + 1) as u64,
file_type: $entry_type,
});
)*
Ok(Box::new(SimpleDirStream::new(entries, start_offset)))
}
}
};
}

static_dir! {
RootInode,
"",
}

pub struct CgroupFs {
root: Arc<RootInode>,
}

impl CgroupFs {
fn new() -> Arc<Self> {
Arc::new(Self {
root: Arc::new(RootInode::new(InodeId::from_fsid_and_inodeid(
CGROUPFS_ID,
get_inode_id(&[]),
))),
})
}
}

#[async_trait]
impl Filesystem for CgroupFs {
async fn root_inode(&self) -> Result<Arc<dyn Inode>> {
Ok(self.root.clone())
}

fn id(&self) -> u64 {
CGROUPFS_ID
}
}

static SYSFS_INSTANCE: OnceLock<Arc<CgroupFs>> = OnceLock::new();

/// Initializes and/or returns the global singleton [`CgroupFs`] instance.
/// This is the main entry point for the rest of the kernel to interact with cgroupfs.
pub fn cgroupfs() -> Arc<CgroupFs> {
SYSFS_INSTANCE
.get_or_init(|| {
log::info!("cgroupfs initialized");
CgroupFs::new()
})
.clone()
}

pub struct CgroupFsDriver;

impl CgroupFsDriver {
#[must_use]
pub fn new() -> Self {
Self
}
}

impl Driver for CgroupFsDriver {
fn name(&self) -> &'static str {
"cgroupfs"
}

fn as_filesystem_driver(self: Arc<Self>) -> Option<Arc<dyn FilesystemDriver>> {
Some(self)
}
}

#[async_trait]
impl FilesystemDriver for CgroupFsDriver {
async fn construct(
&self,
_fs_id: u64,
device: Option<Box<dyn BlockDevice>>,
) -> Result<Arc<dyn Filesystem>> {
if device.is_some() {
warn!("cgroupfs should not be constructed with a block device");
return Err(KernelError::InvalidValue);
}
Ok(cgroupfs())
}
}
6 changes: 6 additions & 0 deletions src/drivers/fs/mod.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
use alloc::sync::Arc;
use cgroup::CgroupFsDriver;
use dev::DevFsDriver;
use ext4::Ext4FsDriver;
use fat32::Fat32FsDriver;
use proc::ProcFsDriver;
use sys::SysFsDriver;
use tmpfs::TmpFsDriver;

use super::DM;

pub mod cgroup;
pub mod dev;
pub mod ext4;
pub mod fat32;
pub mod proc;
pub mod sys;
pub mod tmpfs;

pub fn register_fs_drivers() {
Expand All @@ -20,5 +24,7 @@ pub fn register_fs_drivers() {
dm.insert_driver(Arc::new(Fat32FsDriver::new()));
dm.insert_driver(Arc::new(DevFsDriver::new()));
dm.insert_driver(Arc::new(ProcFsDriver::new()));
dm.insert_driver(Arc::new(SysFsDriver::new()));
dm.insert_driver(Arc::new(TmpFsDriver::new()));
dm.insert_driver(Arc::new(CgroupFsDriver::new()));
}
Loading