mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-21 08:16:32 +00:00
Re-organize some systree-related code
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
a67bd8cdc9
commit
c56aee92f4
@ -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]
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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>>;
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user