Optimize the cache and lock parts in MountNode

This commit is contained in:
Shaowei Song 2024-09-25 02:51:08 +00:00 committed by Tate, Hongliang Tian
parent 791c566b71
commit ae4ac38471

View File

@ -1,5 +1,7 @@
// SPDX-License-Identifier: MPL-2.0
use hashbrown::HashMap;
use crate::{
fs::{
path::dentry::{Dentry, DentryKey, Dentry_},
@ -8,28 +10,28 @@ use crate::{
prelude::*,
};
/// The MountNode can form a mount tree to maintain the mount information.
/// The `MountNode` is used to form a mount tree to maintain the mount information.
pub struct MountNode {
/// Root Dentry_.
/// Root dentry.
root_dentry: Arc<Dentry_>,
/// Mountpoint Dentry_. A mount node can be mounted on one dentry of another mount node,
/// Mountpoint dentry. A mount node can be mounted on one dentry of another mount node,
/// which makes the mount being the child of the mount node.
mountpoint_dentry: RwLock<Option<Arc<Dentry_>>>,
mountpoint_dentry: RwMutex<Option<Arc<Dentry_>>>,
/// The associated FS.
fs: Arc<dyn FileSystem>,
/// The parent mount node.
parent: RwLock<Option<Weak<MountNode>>>,
parent: RwMutex<Option<Weak<MountNode>>>,
/// Child mount nodes which are mounted on one dentry of self.
children: Mutex<BTreeMap<DentryKey, Arc<Self>>>,
children: RwMutex<HashMap<DentryKey, Arc<Self>>>,
/// Reference to self.
this: Weak<Self>,
}
impl MountNode {
/// Create a root mount node with an associated FS.
/// Creates a root mount node with an associated FS.
///
/// The root mount node is not mounted on other mount nodes(which means it has no
/// parent). The root inode of the fs will form the root dentryinner of it.
/// The root mount node is not mounted on other mount nodes (which means it has no
/// parent). The root inode of the fs will form the inner root dentry.
///
/// It is allowed to create a mount node even if the fs has been provided to another
/// mount node. It is the fs's responsibility to ensure the data consistency.
@ -48,15 +50,15 @@ impl MountNode {
fn new(fs: Arc<dyn FileSystem>, parent_mount: Option<Weak<MountNode>>) -> Arc<Self> {
Arc::new_cyclic(|weak_self| Self {
root_dentry: Dentry_::new_root(fs.root_inode()),
mountpoint_dentry: RwLock::new(None),
parent: RwLock::new(parent_mount),
children: Mutex::new(BTreeMap::new()),
mountpoint_dentry: RwMutex::new(None),
parent: RwMutex::new(parent_mount),
children: RwMutex::new(HashMap::new()),
fs,
this: weak_self.clone(),
})
}
/// Mount an fs on the mountpoint, it will create a new child mount node.
/// Mounts a fs on the mountpoint, it will create a new child mount node.
///
/// If the given mountpoint has already been mounted, then its mounted child mount
/// node will be updated.
@ -77,11 +79,11 @@ impl MountNode {
let key = mountpoint.key();
let child_mount = Self::new(fs, Some(Arc::downgrade(mountpoint.mount_node())));
self.children.lock().insert(key, child_mount.clone());
self.children.write().insert(key, child_mount.clone());
Ok(child_mount)
}
/// Unmount a child mount node from the mountpoint and return it.
/// Unmounts a child mount node from the mountpoint and returns it.
///
/// The mountpoint should belong to this mount node, or an error is returned.
pub fn unmount(&self, mountpoint: &Dentry) -> Result<Arc<Self>> {
@ -91,28 +93,28 @@ impl MountNode {
let child_mount = self
.children
.lock()
.write()
.remove(&mountpoint.key())
.ok_or_else(|| Error::with_message(Errno::ENOENT, "can not find child mount"))?;
Ok(child_mount)
}
/// Clone a mount node with the an root `Dentry_`.
/// Clones a mount node with the an root `Dentry_`.
///
/// The new mount node will have the same fs as the original one and
/// have no parent and children. We should set the parent and children manually.
fn clone_mount_node(&self, root_dentry: &Arc<Dentry_>) -> Arc<Self> {
Arc::new_cyclic(|weak_self| Self {
root_dentry: root_dentry.clone(),
mountpoint_dentry: RwLock::new(None),
parent: RwLock::new(None),
children: Mutex::new(BTreeMap::new()),
mountpoint_dentry: RwMutex::new(None),
parent: RwMutex::new(None),
children: RwMutex::new(HashMap::new()),
fs: self.fs.clone(),
this: weak_self.clone(),
})
}
/// Clone a mount tree starting from the specified root `Dentry_`.
/// Clones a mount tree starting from the specified root `Dentry_`.
///
/// The new mount tree will replicate the structure of the original tree.
/// The new tree is a separate entity rooted at the given `Dentry_`,
@ -134,7 +136,7 @@ impl MountNode {
while let Some(old_mount) = stack.pop() {
let new_parent_mount = new_stack.pop().unwrap().clone();
let old_children = old_mount.children.lock();
let old_children = old_mount.children.read();
for old_child_mount in old_children.values() {
let mountpoint_dentry = old_child_mount.mountpoint_dentry().unwrap();
if !mountpoint_dentry.is_descendant_of(old_mount.root_dentry()) {
@ -145,7 +147,7 @@ impl MountNode {
let key = mountpoint_dentry.key();
new_parent_mount
.children
.lock()
.write()
.insert(key, new_child_mount.clone());
new_child_mount.set_parent(&new_parent_mount);
new_child_mount
@ -157,30 +159,30 @@ impl MountNode {
new_root_mount.clone()
}
/// Detach the mount node from the parent mount node.
/// Detaches the mount node from the parent mount node.
fn detach_mount_node(&self) {
if let Some(parent) = self.parent() {
let parent = parent.upgrade().unwrap();
parent
.children
.lock()
.write()
.remove(&self.mountpoint_dentry().unwrap().key());
}
}
/// Attach the mount node to the mountpoint.
/// Attaches the mount node to the mountpoint.
fn attach_mount_node(&self, mountpoint: &Arc<Dentry>) {
let key = mountpoint.key();
mountpoint
.mount_node()
.children
.lock()
.write()
.insert(key, self.this());
self.set_parent(mountpoint.mount_node());
mountpoint.set_mountpoint(self.this());
}
/// Graft the mount node tree to the mountpoint.
/// Grafts the mount node tree to the mountpoint.
pub fn graft_mount_node_tree(&self, mountpoint: &Arc<Dentry>) -> Result<()> {
if mountpoint.type_() != InodeType::Dir {
return_errno!(Errno::ENOTDIR);
@ -190,28 +192,28 @@ impl MountNode {
Ok(())
}
/// Try to get a child mount node from the mountpoint.
/// Gets a child mount node from the mountpoint if any.
pub fn get(&self, mountpoint: &Dentry) -> Option<Arc<Self>> {
if !Arc::ptr_eq(mountpoint.mount_node(), &self.this()) {
return None;
}
self.children.lock().get(&mountpoint.key()).cloned()
self.children.read().get(&mountpoint.key()).cloned()
}
/// Get the root `Dentry_` of this mount node.
/// Gets the root `Dentry_` of this mount node.
pub fn root_dentry(&self) -> &Arc<Dentry_> {
&self.root_dentry
}
/// Try to get the mountpoint `Dentry_` of this mount node.
/// Gets the mountpoint `Dentry_` of this mount node if any.
pub fn mountpoint_dentry(&self) -> Option<Arc<Dentry_>> {
self.mountpoint_dentry.read().clone()
}
/// Set the mountpoint.
/// Sets the mountpoint.
///
/// In some cases we may need to reset the mountpoint of
/// the created MountNode, such as move mount.
/// the created `MountNode`, such as move mount.
pub fn set_mountpoint_dentry(&self, inner: &Arc<Dentry_>) {
let mut mountpoint_dentry = self.mountpoint_dentry.write();
*mountpoint_dentry = Some(inner.clone());
@ -219,7 +221,7 @@ impl MountNode {
/// Flushes all pending filesystem metadata and cached file data to the device.
pub fn sync(&self) -> Result<()> {
let children = self.children.lock();
let children = self.children.read();
for child in children.values() {
child.sync()?;
}
@ -229,12 +231,12 @@ impl MountNode {
Ok(())
}
/// Try to get the parent mount node.
/// Gets the parent mount node if any.
pub fn parent(&self) -> Option<Weak<Self>> {
self.parent.read().as_ref().cloned()
}
/// Set the parent.
/// Sets the parent mount node.
///
/// In some cases we may need to reset the parent of
/// the created MountNode, such as move mount.
@ -243,12 +245,11 @@ impl MountNode {
*parent = Some(Arc::downgrade(mount_node));
}
/// Get strong reference to self.
fn this(&self) -> Arc<Self> {
self.this.upgrade().unwrap()
}
/// Get the associated fs.
/// Gets the associated fs.
pub fn fs(&self) -> &Arc<dyn FileSystem> {
&self.fs
}