Add pseudo `Dentry`
This commit is contained in:
parent
fe633972f3
commit
cb5449cf2a
|
|
@ -18,13 +18,63 @@ use crate::{
|
|||
pub(super) struct Dentry {
|
||||
inode: Arc<dyn Inode>,
|
||||
type_: InodeType,
|
||||
name_and_parent: RwLock<Option<(String, Arc<Dentry>)>>,
|
||||
name_and_parent: NameAndParent,
|
||||
// FIXME: Only maintain children for directory dentries.
|
||||
children: RwMutex<DentryChildren>,
|
||||
flags: AtomicU32,
|
||||
mount_count: AtomicU32,
|
||||
this: Weak<Dentry>,
|
||||
}
|
||||
|
||||
/// The name and parent of a `Dentry`.
|
||||
enum NameAndParent {
|
||||
Real(Option<RwLock<(String, Arc<Dentry>)>>),
|
||||
Pseudo(fn(&dyn Inode) -> String),
|
||||
}
|
||||
|
||||
/// An error returned by [`NameAndParent::set`].
|
||||
#[derive(Debug)]
|
||||
struct SetNameAndParentError;
|
||||
|
||||
impl NameAndParent {
|
||||
fn name(&self, inode: &dyn Inode) -> String {
|
||||
match self {
|
||||
NameAndParent::Real(name_and_parent) => match name_and_parent {
|
||||
Some(name_and_parent) => name_and_parent.read().0.clone(),
|
||||
None => String::from("/"),
|
||||
},
|
||||
NameAndParent::Pseudo(name_fn) => (name_fn)(inode),
|
||||
}
|
||||
}
|
||||
|
||||
fn parent(&self) -> Option<Arc<Dentry>> {
|
||||
if let NameAndParent::Real(Some(name_and_parent)) = self {
|
||||
Some(name_and_parent.read().1.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the name and parent of the `Dentry`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `SetNameAndParentError` if the `Dentry` is a root or pseudo `Dentry`.
|
||||
fn set(
|
||||
&self,
|
||||
name: &str,
|
||||
parent: Arc<Dentry>,
|
||||
) -> core::result::Result<(), SetNameAndParentError> {
|
||||
if let NameAndParent::Real(Some(name_and_parent)) = self {
|
||||
let mut name_and_parent = name_and_parent.write();
|
||||
*name_and_parent = (String::from(name), parent);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(SetNameAndParentError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Dentry {
|
||||
/// Creates a new root `Dentry` with the given inode.
|
||||
///
|
||||
|
|
@ -34,14 +84,27 @@ impl Dentry {
|
|||
Self::new(inode, DentryOptions::Root)
|
||||
}
|
||||
|
||||
/// Creates a new pseudo `Dentry` with the given inode and name function.
|
||||
pub(super) fn new_pseudo(
|
||||
inode: Arc<dyn Inode>,
|
||||
name_fn: fn(&dyn Inode) -> String,
|
||||
) -> Arc<Self> {
|
||||
Self::new(inode, DentryOptions::Pseudo(name_fn))
|
||||
}
|
||||
|
||||
fn new(inode: Arc<dyn Inode>, options: DentryOptions) -> Arc<Self> {
|
||||
let name_and_parent = match options {
|
||||
DentryOptions::Root => NameAndParent::Real(None),
|
||||
DentryOptions::Leaf(name_and_parent) => {
|
||||
NameAndParent::Real(Some(RwLock::new(name_and_parent)))
|
||||
}
|
||||
DentryOptions::Pseudo(name_fn) => NameAndParent::Pseudo(name_fn),
|
||||
};
|
||||
|
||||
Arc::new_cyclic(|weak_self| Self {
|
||||
type_: inode.type_(),
|
||||
inode,
|
||||
name_and_parent: match options {
|
||||
DentryOptions::Leaf(name_and_parent) => RwLock::new(Some(name_and_parent)),
|
||||
_ => RwLock::new(None),
|
||||
},
|
||||
name_and_parent,
|
||||
children: RwMutex::new(DentryChildren::new()),
|
||||
flags: AtomicU32::new(DentryFlags::empty().bits()),
|
||||
mount_count: AtomicU32::new(0),
|
||||
|
|
@ -49,6 +112,10 @@ impl Dentry {
|
|||
})
|
||||
}
|
||||
|
||||
pub(super) fn is_pseudo(&self) -> bool {
|
||||
matches!(self.name_and_parent, NameAndParent::Pseudo(_))
|
||||
}
|
||||
|
||||
/// Gets the type of the `Dentry`.
|
||||
pub(super) fn type_(&self) -> InodeType {
|
||||
self.type_
|
||||
|
|
@ -58,25 +125,14 @@ impl Dentry {
|
|||
///
|
||||
/// Returns "/" if it is a root `Dentry`.
|
||||
pub(super) fn name(&self) -> String {
|
||||
match self.name_and_parent.read().as_ref() {
|
||||
Some(name_and_parent) => name_and_parent.0.clone(),
|
||||
None => String::from("/"),
|
||||
}
|
||||
self.name_and_parent.name(self.inode.as_ref())
|
||||
}
|
||||
|
||||
/// Gets the parent `Dentry`.
|
||||
///
|
||||
/// Returns `None` if it is a root `Dentry`.
|
||||
/// Returns `None` if it is a root or pseudo `Dentry`.
|
||||
pub(super) fn parent(&self) -> Option<Arc<Self>> {
|
||||
self.name_and_parent
|
||||
.read()
|
||||
.as_ref()
|
||||
.map(|name_and_parent| name_and_parent.1.clone())
|
||||
}
|
||||
|
||||
fn set_name_and_parent(&self, name: &str, parent: Arc<Self>) {
|
||||
let mut name_and_parent = self.name_and_parent.write();
|
||||
*name_and_parent = Some((String::from(name), parent));
|
||||
self.name_and_parent.parent()
|
||||
}
|
||||
|
||||
fn this(&self) -> Arc<Self> {
|
||||
|
|
@ -365,7 +421,7 @@ impl Dentry {
|
|||
match old_dentry.as_ref() {
|
||||
Some(dentry) => {
|
||||
children.delete(old_name);
|
||||
dentry.set_name_and_parent(new_name, self.this());
|
||||
dentry.name_and_parent.set(new_name, self.this()).unwrap();
|
||||
if dentry.is_dentry_cacheable() {
|
||||
children.insert(String::from(new_name), dentry.clone());
|
||||
}
|
||||
|
|
@ -385,7 +441,10 @@ impl Dentry {
|
|||
match old_dentry.as_ref() {
|
||||
Some(dentry) => {
|
||||
self_children.delete(old_name);
|
||||
dentry.set_name_and_parent(new_name, new_dir.this());
|
||||
dentry
|
||||
.name_and_parent
|
||||
.set(new_name, new_dir.this())
|
||||
.unwrap();
|
||||
if dentry.is_dentry_cacheable() {
|
||||
new_dir_children.insert(String::from(new_name), dentry.clone());
|
||||
}
|
||||
|
|
@ -415,7 +474,7 @@ impl Dentry {
|
|||
current_dir = parent_dir;
|
||||
}
|
||||
|
||||
debug_assert!(path_name.starts_with('/'));
|
||||
debug_assert!(path_name.starts_with('/') || self.is_pseudo());
|
||||
path_name
|
||||
}
|
||||
}
|
||||
|
|
@ -433,8 +492,9 @@ impl Debug for Dentry {
|
|||
|
||||
/// `DentryKey` is the unique identifier for the corresponding `Dentry`.
|
||||
///
|
||||
/// For none-root dentries, it uses self's name and parent's pointer to form the key,
|
||||
/// meanwhile, the root `Dentry` uses "/" and self's pointer to form the key.
|
||||
/// - For non-root dentries, it uses self's name and parent's pointer to form the key,
|
||||
/// - For the root dentry, it uses "/" and self's pointer to form the key.
|
||||
/// - For pseudo dentries, it uses self's name and self's pointer to form the key.
|
||||
#[derive(Debug, Clone, Hash, PartialOrd, Ord, Eq, PartialEq)]
|
||||
pub(super) struct DentryKey {
|
||||
name: String,
|
||||
|
|
@ -443,11 +503,10 @@ pub(super) struct DentryKey {
|
|||
|
||||
impl DentryKey {
|
||||
/// Forms a `DentryKey` from the corresponding `Dentry`.
|
||||
pub(super) fn new(dentry: &Dentry) -> Self {
|
||||
let (name, parent) = match dentry.name_and_parent.read().as_ref() {
|
||||
Some(name_and_parent) => name_and_parent.clone(),
|
||||
None => (String::from("/"), dentry.this()),
|
||||
};
|
||||
fn new(dentry: &Dentry) -> Self {
|
||||
let name = dentry.name();
|
||||
let parent = dentry.parent().unwrap_or_else(|| dentry.this());
|
||||
|
||||
Self {
|
||||
name,
|
||||
parent_ptr: Arc::as_ptr(&parent) as usize,
|
||||
|
|
@ -464,6 +523,7 @@ bitflags! {
|
|||
enum DentryOptions {
|
||||
Root,
|
||||
Leaf((String, Arc<Dentry>)),
|
||||
Pseudo(fn(&dyn Inode) -> String),
|
||||
}
|
||||
|
||||
/// Manages child dentries, including both valid and negative entries.
|
||||
|
|
|
|||
Loading…
Reference in New Issue