Support the basic configfs

This commit is contained in:
Chen Chengjun 2025-09-08 07:34:48 +00:00 committed by Tate, Hongliang Tian
parent 537f08d7cf
commit fc69af3e95
9 changed files with 389 additions and 3 deletions

View File

@ -617,10 +617,10 @@ macro_rules! inherit_sys_branch_node {
}
}
fn child(&self, name: &str) -> Option<Arc<dyn SysObj>> {
fn child(&self, name: &str) -> Option<Arc<dyn $crate::SysObj>> {
self.$field
.child(name)
.map(|child| child as Arc<dyn SysObj>)
.map(|child| child as Arc<dyn $crate::SysObj>)
}
fn create_child(&self, name: &str) -> $crate::Result<alloc::sync::Arc<dyn $crate::SysObj>> {

View File

@ -0,0 +1,96 @@
// SPDX-License-Identifier: MPL-2.0
use alloc::sync::Arc;
use aster_block::BlockDevice;
use aster_systree::SysNode;
use spin::Once;
use super::inode::ConfigInode;
use crate::{
fs::{
configfs::systree_node::ConfigRootNode,
registry::{FsProperties, FsType},
utils::{systree_inode::SysTreeInodeTy, FileSystem, FsFlags, Inode, SuperBlock},
Result,
},
prelude::*,
};
/// A file system that provides a user-space interface for configuring kernel objects.
///
/// `ConfigFs` is a RAM-based file system that allows user-space applications to create,
/// configure, and manage kernel objects through a virtual file system interface.
/// Unlike sysfs which is primarily read-only and represents existing kernel state,
/// `ConfigFs` is designed for dynamic creation and configuration of kernel objects.
pub struct ConfigFs {
sb: SuperBlock,
root: Arc<dyn Inode>,
}
// Magic number for `ConfigFs` (taken from Linux).
const MAGIC_NUMBER: u64 = 0x62656570;
const BLOCK_SIZE: usize = 4096;
const NAME_MAX: usize = 255;
impl ConfigFs {
/// Returns the `CgroupFs` singleton.
pub(super) fn singleton() -> &'static Arc<ConfigFs> {
static SINGLETON: Once<Arc<ConfigFs>> = Once::new();
SINGLETON.call_once(|| Self::new(ConfigRootNode::singleton().clone()))
}
fn new(root_node: Arc<ConfigRootNode>) -> Arc<Self> {
let sb = SuperBlock::new(MAGIC_NUMBER, BLOCK_SIZE, NAME_MAX);
let root_inode = ConfigInode::new_root(root_node);
Arc::new(Self {
sb,
root: root_inode,
})
}
}
impl FileSystem for ConfigFs {
fn sync(&self) -> Result<()> {
// `ConfigFs` is volatile, sync is a no-op
Ok(())
}
fn root_inode(&self) -> Arc<dyn Inode> {
self.root.clone()
}
fn sb(&self) -> SuperBlock {
self.sb.clone()
}
fn flags(&self) -> FsFlags {
FsFlags::empty()
}
}
pub(super) struct ConfigFsType;
impl FsType for ConfigFsType {
fn name(&self) -> &'static str {
"configfs"
}
fn properties(&self) -> FsProperties {
FsProperties::empty()
}
fn create(
&self,
_args: Option<CString>,
_disk: Option<Arc<dyn BlockDevice>>,
) -> Result<Arc<dyn FileSystem>> {
Ok(ConfigFs::singleton().clone() as _)
}
fn sysnode(&self) -> Option<Arc<dyn SysNode>> {
None
}
}

View File

@ -0,0 +1,81 @@
// SPDX-License-Identifier: MPL-2.0
use alloc::sync::{Arc, Weak};
use ostd::sync::RwLock;
use crate::{
fs::{
configfs::fs::ConfigFs,
utils::{
systree_inode::{SysTreeInodeTy, SysTreeNodeKind},
FileSystem, Inode, InodeMode, Metadata,
},
},
Result,
};
/// An inode abstraction used in the `ConfigFs`.
pub struct ConfigInode {
/// The corresponding node in the SysTree.
node_kind: SysTreeNodeKind,
/// The metadata of this inode.
metadata: Metadata,
/// The file mode (permissions) of this inode, protected by a lock.
mode: RwLock<InodeMode>,
/// Weak reference to the parent inode.
parent: Weak<ConfigInode>,
/// Weak self-reference for cyclic data structures.
this: Weak<ConfigInode>,
}
impl SysTreeInodeTy for ConfigInode {
fn new_arc(
node_kind: SysTreeNodeKind,
metadata: Metadata,
mode: InodeMode,
parent: Weak<Self>,
) -> Arc<Self>
where
Self: Sized,
{
Arc::new_cyclic(|this| Self {
node_kind,
metadata,
mode: RwLock::new(mode),
parent,
this: this.clone(),
})
}
fn node_kind(&self) -> &SysTreeNodeKind {
&self.node_kind
}
fn metadata(&self) -> &Metadata {
&self.metadata
}
fn mode(&self) -> Result<InodeMode> {
Ok(*self.mode.read())
}
fn set_mode(&self, mode: InodeMode) -> Result<()> {
*self.mode.write() = mode;
Ok(())
}
fn parent(&self) -> &Weak<Self> {
&self.parent
}
fn this(&self) -> Arc<Self> {
self.this.upgrade().expect("Weak ref invalid")
}
}
impl Inode for ConfigInode {
fn fs(&self) -> Arc<dyn FileSystem> {
ConfigFs::singleton().clone()
}
}

View File

@ -0,0 +1,51 @@
// SPDX-License-Identifier: MPL-2.0
use alloc::sync::Arc;
use aster_systree::{EmptyNode, SysBranchNode};
use systree_node::ConfigRootNode;
use crate::{fs::configfs::fs::ConfigFsType, prelude::*};
mod fs;
mod inode;
mod systree_node;
#[cfg(ktest)]
mod test;
// This method should be called during kernel file system initialization,
// _after_ `aster_systree::init`.
pub(super) fn init() {
let config_kernel_sysnode = EmptyNode::new("config".into());
super::sysfs::register_kernel_sysnode(config_kernel_sysnode).unwrap();
super::registry::register(&ConfigFsType).unwrap();
}
/// Registers a subsystem `SysTree` node under the root node of [`ConfigFs`].
///
/// If a subsystem with the same name has already been registered,
/// this function returns an error.
pub fn register_subsystem(subsystem: Arc<dyn SysBranchNode>) -> Result<()> {
ConfigRootNode::singleton().add_child(subsystem)?;
Ok(())
}
/// Unregisters a subsystem from the root node of [`ConfigFs`] by its name.
///
/// If no subsystem with the given name exists, this function returns an error.
#[expect(dead_code)]
pub fn unregister_subsystem(name: &str) -> Result<()> {
ConfigRootNode::singleton().remove_child(name)?;
Ok(())
}
#[cfg(ktest)]
pub fn init_for_ktest() {
aster_systree::init_for_ktest();
super::registry::init();
super::sysfs::init();
init();
}

View File

@ -0,0 +1,54 @@
// SPDX-License-Identifier: MPL-2.0
use alloc::sync::{Arc, Weak};
use core::fmt::Debug;
use aster_systree::{
inherit_sys_branch_node, BranchNodeFields, Result, SysAttrSet, SysBranchNode, SysObj, SysPerms,
SysStr,
};
use inherit_methods_macro::inherit_methods;
use spin::Once;
/// The `SysTree` node that represents the root node of the `ConfigFs`.
#[derive(Debug)]
pub struct ConfigRootNode {
fields: BranchNodeFields<dyn SysObj, Self>,
}
#[inherit_methods(from = "self.fields")]
impl ConfigRootNode {
/// Returns the `ConfigRootNode` singleton.
pub(super) fn singleton() -> &'static Arc<ConfigRootNode> {
static SINGLETON: Once<Arc<ConfigRootNode>> = Once::new();
SINGLETON.call_once(Self::new)
}
fn new() -> Arc<Self> {
let name = SysStr::from("config");
let attrs = SysAttrSet::new_empty();
Arc::new_cyclic(|weak_self| {
let fields = BranchNodeFields::new(name, attrs, weak_self.clone());
ConfigRootNode { fields }
})
}
/// Adds a child node.
pub fn add_child(&self, new_child: Arc<dyn SysObj>) -> Result<()>;
}
inherit_sys_branch_node!(ConfigRootNode, fields, {
fn is_root(&self) -> bool {
true
}
fn init_parent(&self, _parent: Weak<dyn SysBranchNode>) {
// This method should be a no-op for `RootNode`.
}
fn perms(&self) -> SysPerms {
SysPerms::DEFAULT_RW_PERMS
}
});

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: MPL-2.0
pub mod cgroupfs;
pub mod configfs;
pub mod device;
pub mod devpts;
pub mod epoll;
@ -60,6 +61,7 @@ pub fn init() {
sysfs::init();
procfs::init();
cgroupfs::init();
configfs::init();
ramfs::init();
tmpfs::init();
devpts::init();

View File

@ -0,0 +1,84 @@
// SPDX-License-Identifier: MPL-2.0
use alloc::sync::Arc;
use aster_systree::{
inherit_sys_branch_node, BranchNodeFields, Error, Result, SysAttrSetBuilder, SysBranchNode,
SysNode, SysPerms, SysStr,
};
use inherit_methods_macro::inherit_methods;
use ostd::mm::{VmReader, VmWriter};
use spin::Once;
/// Registers a new kernel `SysNode`.
pub(super) fn register(config_obj: Arc<dyn SysNode>) -> crate::Result<()> {
KERNEL_SYS_NODE_ROOT.get().unwrap().add_child(config_obj)?;
Ok(())
}
/// Unregisters a kernel `SysNode`.
pub(super) fn unregister(name: &str) -> crate::Result<()> {
let _ = KERNEL_SYS_NODE_ROOT.get().unwrap().remove_child(name)?;
Ok(())
}
pub(super) fn init() {
KERNEL_SYS_NODE_ROOT.call_once(|| {
let singleton = KernelSysNodeRoot::new();
super::systree_singleton()
.root()
.add_child(singleton.clone())
.unwrap();
singleton
});
}
static KERNEL_SYS_NODE_ROOT: Once<Arc<KernelSysNodeRoot>> = Once::new();
/// A systree node representing the `/sys/kernel` directory.
///
/// This node serves as the root for all kernel-related sysfs entries,
/// including kernel parameters, debugging interfaces, and various
/// kernel subsystem information. It corresponds to the `/kernel`
/// directory in the sysfs filesystem.
#[derive(Debug)]
pub struct KernelSysNodeRoot {
fields: BranchNodeFields<dyn SysNode, Self>,
}
#[inherit_methods(from = "self.fields")]
impl KernelSysNodeRoot {
/// Creates a new `KernelSysNodeRoot` instance.
fn new() -> Arc<Self> {
let name = SysStr::from("kernel");
let builder = SysAttrSetBuilder::new();
// TODO: Add more kernel-specific attributes.
let attrs = builder
.build()
.expect("Failed to build kernel attribute set");
Arc::new_cyclic(|weak_self| {
let fields = BranchNodeFields::new(name, attrs, weak_self.clone());
KernelSysNodeRoot { fields }
})
}
/// Adds a kernel `SysNode` to this node.
fn add_child(&self, new_child: Arc<dyn SysNode>) -> Result<()>;
}
inherit_sys_branch_node!(KernelSysNodeRoot, fields, {
fn read_attr(&self, _name: &str, _writer: &mut VmWriter) -> Result<usize> {
// TODO: Add support for reading attributes.
Err(Error::AttributeError)
}
fn write_attr(&self, _name: &str, _reader: &mut VmReader) -> Result<usize> {
// TODO: Add support for writing attributes.
Err(Error::AttributeError)
}
fn perms(&self) -> SysPerms {
SysPerms::DEFAULT_RW_PERMS
}
});

View File

@ -2,14 +2,31 @@
mod fs;
mod inode;
mod kernel;
#[cfg(ktest)]
mod test;
pub use aster_systree::primary_tree as systree_singleton;
use aster_systree::SysNode;
use fs::SysFsType;
use crate::prelude::*;
// This method should be called during kernel file system initialization,
// _after_ `aster_systree::init`.
pub fn init() {
super::registry::register(&SysFsType).unwrap();
kernel::init();
}
/// Registers a new kernel `SysNode`.
pub fn register_kernel_sysnode(config_obj: Arc<dyn SysNode>) -> Result<()> {
kernel::register(config_obj)
}
/// Unregisters a kernel `SysNode`.
#[expect(dead_code)]
pub fn unregister_kernel_sysnode(name: &str) -> Result<()> {
kernel::unregister(name)
}

View File

@ -6,4 +6,5 @@
# a generic init process. It should later be replaced by the actual init process.
mount -t sysfs none /sys
mount -t proc none /proc
mount -t cgroup2 none /sys/fs/cgroup
mount -t cgroup2 none /sys/fs/cgroup
mount -t configfs none /sys/kernel/config