Re-organize some systree-related code

This commit is contained in:
Chen Chengjun 2025-06-05 03:06:51 +00:00 committed by Tate, Hongliang Tian
parent a67bd8cdc9
commit c56aee92f4
9 changed files with 125 additions and 273 deletions

1
Cargo.lock generated
View File

@ -268,6 +268,7 @@ version = "0.1.0"
dependencies = [
"bitflags 2.9.0",
"component",
"inherit-methods-macro",
"ostd",
"spin",
]

View File

@ -9,6 +9,7 @@ edition = "2021"
bitflags = "2.5"
ostd = { path = "../../../ostd" }
component = { path = "../../libs/comp-sys/component" }
inherit-methods-macro = { git = "https://github.com/asterinas/inherit-methods-macro", rev = "98f7e3e"}
spin = "0.9"
[lints]

View File

@ -37,9 +37,6 @@ pub struct SysAttr {
name: SysStr,
/// Flags defining the behavior and permissions of the attribute.
flags: SysAttrFlags,
// Potentially add read/write handler functions or trait objects later
// read_handler: fn(...) -> Result<usize>,
// write_handler: fn(...) -> Result<usize>,
}
impl SysAttr {

View File

@ -7,7 +7,7 @@ use core::{
sync::atomic::{AtomicU64, Ordering},
};
use ostd::mm::{VmReader, VmWriter};
use ostd::mm::{FallibleVmWrite, VmReader, VmWriter};
use super::{Error, Result, SysAttrSet, SysStr};
@ -16,9 +16,9 @@ pub const MAX_ATTR_SIZE: usize = 4096;
/// The three types of nodes in a `SysTree`.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum SysNodeType {
/// A branching node is one that may contain child nodes.
/// A branching node is one that can have child nodes.
Branch,
/// A leaf node is one that may not contain child nodes.
/// A leaf node is one that cannot have child nodes.
Leaf,
/// A symlink node,
/// which ia a special kind of leaf node that points to another node,
@ -27,6 +27,7 @@ pub enum SysNodeType {
}
/// A trait that represents a branching node in a `SysTree`.
#[expect(clippy::type_complexity)]
pub trait SysBranchNode: SysNode {
/// Visits a child node with the given name using a closure.
///
@ -49,7 +50,7 @@ pub trait SysBranchNode: SysNode {
/// So the caller should do as little as possible inside the closure.
/// In particular, the caller should _not_ invoke other methods
/// on this object as this might cause deadlock.
fn visit_child_with(&self, name: &str, f: &mut dyn FnMut(Option<&dyn SysNode>));
fn visit_child_with(&self, name: &str, f: &mut dyn FnMut(Option<&Arc<dyn SysObj>>));
/// Visits child nodes with a minimum ID using a closure.
///
@ -75,7 +76,7 @@ pub trait SysBranchNode: SysNode {
fn visit_children_with(
&self,
min_id: u64,
f: &mut dyn for<'a> FnMut(&'a Arc<(dyn SysObj + 'static)>) -> Option<()>,
f: &mut dyn for<'a> FnMut(&'a Arc<(dyn SysObj)>) -> Option<()>,
);
/// Returns a child with a specified name.
@ -182,18 +183,18 @@ pub trait SysObj: Any + Send + Sync + Debug + 'static {
/// Returns a reference to this object as `Any` for downcasting.
fn as_any(&self) -> &dyn Any;
/// Attempts to get an Arc to this object as a `SysSymlink`.
fn arc_as_symlink(&self) -> Option<Arc<dyn SysSymlink>> {
/// Casts this object to a trait object of `SysTree` symlink.
fn cast_to_symlink(&self) -> Option<Arc<dyn SysSymlink>> {
None
}
/// Attempts to get an Arc to this object as a `SysNode`.
fn arc_as_node(&self) -> Option<Arc<dyn SysNode>> {
/// Casts this object to a trait object of a `SysTree` node.
fn cast_to_node(&self) -> Option<Arc<dyn SysNode>> {
None
}
/// Attempts to get an Arc to this object as a `SysBranchNode`.
fn arc_as_branch(&self) -> Option<Arc<dyn SysBranchNode>> {
/// Casts this object to a trait object of a `SysTree` branch node.
fn cast_to_branch(&self) -> Option<Arc<dyn SysBranchNode>> {
None
}
@ -210,7 +211,7 @@ pub trait SysObj: Any + Send + Sync + Debug + 'static {
///
/// The root node of a `SysTree` has an empty name.
/// All other inodes must have an non-empty name.
fn name(&self) -> SysStr;
fn name(&self) -> &SysStr;
/// Returns whether a node is the root of a `SysTree`.
fn is_root(&self) -> bool {

View File

@ -6,22 +6,24 @@ use alloc::{
sync::{Arc, Weak},
vec::Vec,
};
use core::{any::Any, fmt::Debug};
use core::fmt::Debug;
use inherit_methods_macro::inherit_methods;
use ostd::{
mm::{FallibleVmRead, FallibleVmWrite, VmReader, VmWriter},
prelude::ktest,
};
use super::{
Error, Result, SysAttrFlags, SysAttrSet, SysAttrSetBuilder, SysBranchNode, SysBranchNodeFields,
SysNode, SysNodeId, SysNodeType, SysObj, SysStr, SysSymlink, SysTree,
impl_cast_methods_for_branch, impl_cast_methods_for_symlink, Error, Result, SysAttrFlags,
SysAttrSet, SysAttrSetBuilder, SysBranchNode, SysBranchNodeFields, SysNode, SysNodeId,
SysNodeType, SysObj, SysStr, SysSymlink, SysTree,
};
#[derive(Debug)]
struct DeviceNode {
fields: SysBranchNodeFields<dyn SysObj>,
self_ref: Weak<Self>,
weak_self: Weak<Self>,
}
impl DeviceNode {
@ -41,38 +43,20 @@ impl DeviceNode {
Arc::new_cyclic(|weak_self| DeviceNode {
fields,
self_ref: weak_self.clone(),
weak_self: weak_self.clone(),
})
}
}
impl SysObj for DeviceNode {
fn as_any(&self) -> &dyn Any {
self
}
fn arc_as_node(&self) -> Option<Arc<dyn SysNode>> {
self.self_ref
.upgrade()
.map(|arc_self| arc_self as Arc<dyn SysNode>)
}
fn arc_as_branch(&self) -> Option<Arc<dyn SysBranchNode>> {
self.self_ref
.upgrade()
.map(|arc_self| arc_self as Arc<dyn SysBranchNode>)
}
impl_cast_methods_for_branch!();
fn id(&self) -> &SysNodeId {
self.fields.id()
}
fn type_(&self) -> SysNodeType {
SysNodeType::Branch
}
fn name(&self) -> SysStr {
self.fields.name().to_string().into()
fn name(&self) -> &SysStr {
self.fields.name()
}
}
@ -129,45 +113,13 @@ impl SysNode for DeviceNode {
}
}
#[inherit_methods(from = "self.fields")]
impl SysBranchNode for DeviceNode {
fn visit_child_with(&self, name: &str, f: &mut dyn FnMut(Option<&dyn SysNode>)) {
let children = self.fields.children.read();
children
.get(name)
.map(|child| {
child
.arc_as_node()
.map(|node| f(Some(node.as_ref())))
.unwrap_or_else(|| f(None))
})
.unwrap_or_else(|| f(None));
}
fn visit_child_with(&self, name: &str, f: &mut dyn FnMut(Option<&Arc<dyn SysObj>>));
fn visit_children_with(&self, min_id: u64, f: &mut dyn FnMut(&Arc<dyn SysObj>) -> Option<()>) {
let children = self.fields.children.read();
for child in children
.values()
.filter(|child| child.id().as_u64() >= min_id)
{
if f(child).is_none() {
break;
}
}
}
fn visit_children_with(&self, min_id: u64, f: &mut dyn FnMut(&Arc<dyn SysObj>) -> Option<()>);
fn child(&self, name: &str) -> Option<Arc<dyn SysObj>> {
let children = self.fields.children.read();
children.get(name).cloned()
}
fn children(&self) -> Vec<Arc<dyn SysObj>> {
let children = self.fields.children.read();
children.values().cloned().collect()
}
fn count_children(&self) -> usize {
self.fields.children.read().len()
}
fn child(&self, name: &str) -> Option<Arc<dyn SysObj>>;
}
#[derive(Debug)]
@ -175,7 +127,7 @@ struct SymlinkNode {
id: SysNodeId,
name: SysStr,
target: String,
self_ref: Weak<Self>,
weak_self: Weak<Self>,
}
impl SymlinkNode {
@ -184,32 +136,20 @@ impl SymlinkNode {
id: SysNodeId::new(),
name: name.to_string().into(),
target: target.to_string(),
self_ref: weak_self.clone(),
weak_self: weak_self.clone(),
})
}
}
impl SysObj for SymlinkNode {
fn as_any(&self) -> &dyn Any {
self
}
fn arc_as_symlink(&self) -> Option<Arc<dyn SysSymlink>> {
self.self_ref
.upgrade()
.map(|arc_self| arc_self as Arc<dyn SysSymlink>)
}
impl_cast_methods_for_symlink!();
fn id(&self) -> &SysNodeId {
&self.id
}
fn type_(&self) -> SysNodeType {
SysNodeType::Symlink
}
fn name(&self) -> SysStr {
self.name.clone()
fn name(&self) -> &SysStr {
&self.name
}
}
@ -230,7 +170,7 @@ fn systree_singleton() {
// Check if root node exists
assert!(root.is_root());
assert_eq!(root.name(), "");
assert_eq!(root.type_(), SysNodeType::Leaf);
assert_eq!(root.type_(), SysNodeType::Branch);
}
#[ktest]
@ -309,7 +249,7 @@ fn symlinks() {
// Verify symlink was added correctly
let symlink_obj = device.child("device_link").unwrap();
let symlink_node = symlink_obj.arc_as_symlink().unwrap();
let symlink_node = symlink_obj.cast_to_symlink().unwrap();
assert_eq!(symlink_node.target_path(), "/sys/devices/device");
}

View File

@ -4,22 +4,18 @@
use alloc::{
borrow::Cow,
collections::BTreeMap,
sync::{Arc, Weak},
vec::Vec,
};
use core::any::Any;
use ostd::{
mm::{VmReader, VmWriter},
sync::RwLock,
};
use inherit_methods_macro::inherit_methods;
use ostd::mm::{VmReader, VmWriter};
use super::{
attr::SysAttrSet,
node::{SysBranchNode, SysNode, SysNodeId, SysNodeType, SysObj, SysSymlink},
node::{SysBranchNode, SysNode, SysNodeId, SysNodeType, SysObj},
Error, Result, SysStr,
};
use crate::{impl_cast_methods_for_branch, SysBranchNodeFields};
#[derive(Debug)]
pub struct SysTree {
@ -32,12 +28,13 @@ impl SysTree {
/// and standard subdirectories like "devices", "block", "kernel".
/// This is intended to be called once for the singleton.
pub(crate) fn new() -> Self {
let name = ""; // Only the root has an empty name
let attr_set = SysAttrSet::new_empty(); // The root has no attributes
let fields = SysBranchNodeFields::new(SysStr::from(name), attr_set);
let root_node = Arc::new_cyclic(|weak_self| RootNode {
id: SysNodeId::new(),
name: "".into(),
attrs: SysAttrSet::new_empty(),
children: RwLock::new(BTreeMap::new()),
self_ref: weak_self.clone(),
fields,
weak_self: weak_self.clone(),
});
Self { root: root_node }
@ -49,22 +46,22 @@ impl SysTree {
}
}
/// The root node in the `SysTree`.
///
/// A `RootNode` can work like a branching node, allowing to add additional nodes
/// as its children.
#[derive(Debug)]
pub struct RootNode {
id: SysNodeId,
name: SysStr,
attrs: SysAttrSet,
children: RwLock<BTreeMap<SysStr, Arc<dyn SysObj>>>,
self_ref: Weak<Self>,
fields: SysBranchNodeFields<dyn SysObj>,
weak_self: Weak<Self>,
}
impl RootNode {
/// Adds a child node. This was part of the concrete RootNode impl in lib.rs.
/// It's not part of the SysBranchNode trait definition.
/// Adds a child node to this `RootNode`.
pub fn add_child(&self, new_child: Arc<dyn SysObj>) -> Result<()> {
let name = new_child.name();
let mut children_guard = self.children.write();
if children_guard.contains_key(&name) {
let mut children_guard = self.fields.children.write();
if children_guard.contains_key(name) {
return Err(Error::PermissionDenied);
}
children_guard.insert(name.clone(), new_child);
@ -72,41 +69,13 @@ impl RootNode {
}
}
#[inherit_methods(from = "self.fields")]
impl SysObj for RootNode {
fn as_any(&self) -> &dyn Any {
self
}
impl_cast_methods_for_branch!();
fn arc_as_symlink(&self) -> Option<Arc<dyn SysSymlink>> {
None
}
fn id(&self) -> &SysNodeId;
fn arc_as_node(&self) -> Option<Arc<dyn SysNode>> {
self.self_ref
.upgrade()
.map(|arc_self| arc_self as Arc<dyn SysNode>)
}
fn arc_as_branch(&self) -> Option<Arc<dyn SysBranchNode>> {
self.self_ref
.upgrade()
.map(|arc_self| arc_self as Arc<dyn SysBranchNode>)
}
fn id(&self) -> &SysNodeId {
&self.id
}
fn type_(&self) -> SysNodeType {
if self.children.read().is_empty() {
return SysNodeType::Leaf;
}
SysNodeType::Branch
}
fn name(&self) -> SysStr {
self.name.clone()
}
fn name(&self) -> &SysStr;
fn is_root(&self) -> bool {
true
@ -119,7 +88,7 @@ impl SysObj for RootNode {
impl SysNode for RootNode {
fn node_attrs(&self) -> &SysAttrSet {
&self.attrs
self.fields.attr_set()
}
fn read_attr(&self, _name: &str, _writer: &mut VmWriter) -> Result<usize> {
@ -131,35 +100,11 @@ impl SysNode for RootNode {
}
}
#[inherit_methods(from = "self.fields")]
impl SysBranchNode for RootNode {
fn visit_child_with(&self, name: &str, f: &mut dyn FnMut(Option<&dyn SysNode>)) {
let children_guard = self.children.read();
children_guard
.get(name)
.map(|child| {
if let Some(node_ref) = child.arc_as_node().as_deref() {
f(Some(node_ref));
} else {
f(None);
}
})
.unwrap_or_else(|| f(None));
}
fn visit_child_with(&self, name: &str, f: &mut dyn FnMut(Option<&Arc<dyn SysObj>>));
fn visit_children_with(&self, _min_id: u64, f: &mut dyn FnMut(&Arc<dyn SysObj>) -> Option<()>) {
let children_guard = self.children.read();
for child_arc in children_guard.values() {
if f(child_arc).is_none() {
break;
}
}
}
fn visit_children_with(&self, _min_id: u64, f: &mut dyn FnMut(&Arc<dyn SysObj>) -> Option<()>);
fn child(&self, name: &str) -> Option<Arc<dyn SysObj>> {
self.children.read().get(name).cloned()
}
fn children(&self) -> Vec<Arc<dyn SysObj>> {
self.children.read().values().cloned().collect()
}
fn child(&self, name: &str) -> Option<Arc<dyn SysObj>>;
}

View File

@ -3,7 +3,6 @@
//! Utility definitions and helper structs for implementing `SysTree` nodes.
use alloc::{collections::BTreeMap, string::String, sync::Arc};
use core::ops::Deref;
use ostd::sync::RwLock;
@ -31,8 +30,8 @@ impl SysObjFields {
&self.id
}
pub fn name(&self) -> &str {
self.name.deref()
pub fn name(&self) -> &SysStr {
&self.name
}
}
@ -54,7 +53,7 @@ impl SysNormalNodeFields {
self.base.id()
}
pub fn name(&self) -> &str {
pub fn name(&self) -> &SysStr {
self.base.name()
}
@ -81,7 +80,7 @@ impl<C: SysObj + ?Sized> SysBranchNodeFields<C> {
self.base.id()
}
pub fn name(&self) -> &str {
pub fn name(&self) -> &SysStr {
self.base.name()
}
@ -97,7 +96,7 @@ impl<C: SysObj + ?Sized> SysBranchNodeFields<C> {
pub fn add_child(&self, new_child: Arc<C>) -> Result<()> {
let mut children = self.children.write();
let name = new_child.name();
if children.contains_key(name.deref()) {
if children.contains_key(name) {
return Err(Error::PermissionDenied);
}
children.insert(name.clone(), new_child);
@ -108,6 +107,29 @@ impl<C: SysObj + ?Sized> SysBranchNodeFields<C> {
let mut children = self.children.write();
children.remove(child_name)
}
pub fn visit_child_with(&self, name: &str, f: &mut dyn FnMut(Option<&Arc<C>>)) {
let children_guard = self.children.read();
f(children_guard.get(name))
}
pub fn visit_children_with(&self, min_id: u64, f: &mut dyn FnMut(&Arc<C>) -> Option<()>) {
let children_guard = self.children.read();
for child_arc in children_guard.values() {
if child_arc.id().as_u64() < min_id {
continue;
}
if f(child_arc).is_none() {
break;
}
}
}
pub fn child(&self, name: &str) -> Option<Arc<C>> {
let children = self.children.read();
children.get(name).cloned()
}
}
#[derive(Debug)]
@ -128,7 +150,7 @@ impl SymlinkNodeFields {
self.base.id()
}
pub fn name(&self) -> &str {
pub fn name(&self) -> &SysStr {
self.base.name()
}

View File

@ -191,7 +191,7 @@ impl SysFsInode {
match child_type {
SysNodeType::Branch => {
let child_branch = child_sysnode
.arc_as_branch()
.cast_to_branch()
.ok_or(Error::new(Errno::EIO))?;
let inode = Self::new_branch_dir(
self.systree,
@ -202,7 +202,7 @@ impl SysFsInode {
}
SysNodeType::Leaf => {
let child_leaf_node =
child_sysnode.arc_as_node().ok_or(Error::new(Errno::EIO))?;
child_sysnode.cast_to_node().ok_or(Error::new(Errno::EIO))?;
let inode = Self::new_leaf_dir(
self.systree,
InnerNode::Leaf(child_leaf_node),
@ -212,7 +212,7 @@ impl SysFsInode {
}
SysNodeType::Symlink => {
let child_symlink = child_sysnode
.arc_as_symlink()
.cast_to_symlink()
.ok_or(Error::new(Errno::EIO))?;
let inode = Self::new_symlink(
self.systree,
@ -646,7 +646,7 @@ impl Iterator for NodeDentryIter {
};
return Some(Dentry {
ino: obj_ino,
name: obj.name(),
name: obj.name().clone(),
type_,
});
}

View File

@ -9,13 +9,15 @@ use alloc::{
vec,
vec::Vec,
};
use core::{any::Any, fmt::Debug};
use core::fmt::Debug;
use aster_systree::{
impl_cast_methods_for_branch, impl_cast_methods_for_node, impl_cast_methods_for_symlink,
init_for_ktest, singleton as systree_singleton, Error as SysTreeError, Result as SysTreeResult,
SysAttrFlags, SysAttrSet, SysAttrSetBuilder, SysBranchNode, SysBranchNodeFields, SysNode,
SysNodeId, SysNodeType, SysNormalNodeFields, SysObj, SysStr, SysSymlink, SysTree,
};
use inherit_methods_macro::inherit_methods;
use ostd::{
mm::{FallibleVmRead, FallibleVmWrite, VmReader, VmWriter},
prelude::ktest,
@ -40,7 +42,7 @@ use crate::{
struct MockLeafNode {
fields: SysNormalNodeFields,
data: RwLock<BTreeMap<String, String>>, // Store attribute data
self_ref: Weak<Self>,
weak_self: Weak<Self>,
}
impl MockLeafNode {
@ -67,28 +69,20 @@ impl MockLeafNode {
Arc::new_cyclic(|weak_self| MockLeafNode {
fields,
data: RwLock::new(data),
self_ref: weak_self.clone(),
weak_self: weak_self.clone(),
})
}
}
impl SysObj for MockLeafNode {
fn as_any(&self) -> &dyn Any {
self
}
fn arc_as_node(&self) -> Option<Arc<dyn SysNode>> {
self.self_ref
.upgrade()
.map(|arc_self| arc_self as Arc<dyn SysNode>)
}
impl_cast_methods_for_node!();
fn id(&self) -> &SysNodeId {
self.fields.id()
}
fn type_(&self) -> SysNodeType {
SysNodeType::Leaf
}
fn name(&self) -> SysStr {
Cow::Owned(self.fields.name().to_string()) // Convert to Cow::Owned
fn name(&self) -> &SysStr {
self.fields.name()
}
}
@ -143,7 +137,7 @@ impl SysNode for MockLeafNode {
#[derive(Debug)]
struct MockBranchNode {
fields: SysBranchNodeFields<dyn SysObj>,
self_ref: Weak<Self>,
weak_self: Weak<Self>,
}
impl MockBranchNode {
@ -160,7 +154,7 @@ impl MockBranchNode {
Arc::new_cyclic(|weak_self| MockBranchNode {
fields,
self_ref: weak_self.clone(),
weak_self: weak_self.clone(),
})
}
@ -170,27 +164,14 @@ impl MockBranchNode {
}
impl SysObj for MockBranchNode {
fn as_any(&self) -> &dyn Any {
self
}
fn arc_as_node(&self) -> Option<Arc<dyn SysNode>> {
self.self_ref
.upgrade()
.map(|arc_self| arc_self as Arc<dyn SysNode>)
}
fn arc_as_branch(&self) -> Option<Arc<dyn SysBranchNode>> {
self.self_ref
.upgrade()
.map(|arc_self| arc_self as Arc<dyn SysBranchNode>)
}
impl_cast_methods_for_branch!();
fn id(&self) -> &SysNodeId {
self.fields.id()
}
fn type_(&self) -> SysNodeType {
SysNodeType::Branch
}
fn name(&self) -> SysStr {
Cow::Owned(self.fields.name().to_string()) // Convert to Cow::Owned
fn name(&self) -> &SysStr {
self.fields.name()
}
}
@ -232,41 +213,13 @@ impl SysNode for MockBranchNode {
}
}
#[inherit_methods(from = "self.fields")]
impl SysBranchNode for MockBranchNode {
fn visit_child_with(&self, name: &str, f: &mut dyn FnMut(Option<&dyn SysNode>)) {
self.fields
.children
.read()
.get(name)
.map(|child| {
child
.arc_as_node()
.map(|node| f(Some(node.as_ref())))
.unwrap_or_else(|| f(None));
})
.unwrap_or_else(|| f(None));
}
fn visit_child_with(&self, name: &str, f: &mut dyn FnMut(Option<&Arc<dyn SysObj>>));
fn visit_children_with(&self, min_id: u64, f: &mut dyn FnMut(&Arc<dyn SysObj>) -> Option<()>) {
let children = self.fields.children.read();
for child in children
.values()
.filter(|child| child.id().as_u64() >= min_id)
{
if f(child).is_none() {
break;
}
}
}
fn visit_children_with(&self, min_id: u64, f: &mut dyn FnMut(&Arc<dyn SysObj>) -> Option<()>);
fn child(&self, name: &str) -> Option<Arc<dyn SysObj>> {
let children = self.fields.children.read();
children.get(name).cloned()
}
fn children(&self) -> Vec<Arc<dyn SysObj>> {
self.fields.children.read().values().cloned().collect()
}
fn child(&self, name: &str) -> Option<Arc<dyn SysObj>>;
}
// Mock Symlink
@ -275,7 +228,7 @@ struct MockSymlinkNode {
id: SysNodeId,
name: SysStr,
target: String,
self_ref: Weak<Self>,
weak_self: Weak<Self>,
}
impl MockSymlinkNode {
@ -284,28 +237,20 @@ impl MockSymlinkNode {
id: SysNodeId::new(),
name: name.to_string().into(),
target: target.to_string(),
self_ref: weak_self.clone(),
weak_self: weak_self.clone(),
})
}
}
impl SysObj for MockSymlinkNode {
fn as_any(&self) -> &dyn Any {
self
}
fn arc_as_symlink(&self) -> Option<Arc<dyn SysSymlink>> {
self.self_ref
.upgrade()
.map(|arc_self| arc_self as Arc<dyn SysSymlink>)
}
impl_cast_methods_for_symlink!();
fn id(&self) -> &SysNodeId {
&self.id
}
fn type_(&self) -> SysNodeType {
SysNodeType::Symlink
}
fn name(&self) -> SysStr {
self.name.clone()
fn name(&self) -> &SysStr {
&self.name
}
}