Fix the mountpoint state maintaining for Dentry

This commit is contained in:
Chen Chengjun 2025-08-12 06:52:27 +00:00 committed by Tate, Hongliang Tian
parent ae32062e77
commit aea4013a43
3 changed files with 51 additions and 26 deletions

View File

@ -28,6 +28,7 @@ pub(super) struct Dentry {
name_and_parent: RwLock<Option<(String, Arc<Dentry>)>>,
children: RwMutex<DentryChildren>,
flags: AtomicU32,
mount_count: AtomicU32,
this: Weak<Dentry>,
}
@ -50,6 +51,7 @@ impl Dentry {
},
children: RwMutex::new(DentryChildren::new()),
flags: AtomicU32::new(DentryFlags::empty().bits()),
mount_count: AtomicU32::new(0),
this: weak_self.clone(),
})
}
@ -120,14 +122,22 @@ impl Dentry {
self.flags().contains(DentryFlags::MOUNTED)
}
pub fn set_mounted_bit(&self) {
self.flags
.fetch_or(DentryFlags::MOUNTED.bits(), Ordering::Release);
pub(super) fn inc_mount_count(&self) {
// FIXME: Theoretically, an overflow could occur. In the future,
// we could prevent this by implementing a global maximum mount limit.
let old_count = self.mount_count.fetch_add(1, Ordering::Relaxed);
if old_count == 0 {
self.flags
.fetch_or(DentryFlags::MOUNTED.bits(), Ordering::Relaxed);
}
}
pub fn clear_mounted_bit(&self) {
self.flags
.fetch_and(!(DentryFlags::MOUNTED.bits()), Ordering::Release);
pub(super) fn dec_mount_count(&self) {
let old_count = self.mount_count.fetch_sub(1, Ordering::Relaxed);
if old_count == 1 {
self.flags
.fetch_and(!(DentryFlags::MOUNTED.bits()), Ordering::Relaxed);
}
}
/// Currently, the root `Dentry` of a fs is the root of a mount.

View File

@ -169,12 +169,7 @@ impl Path {
}
}
/// Makes current `Dentry` to be a mountpoint,
/// sets it as the mountpoint of the child mount.
pub(super) fn set_mountpoint(&self, child_mount: Arc<MountNode>) {
child_mount.set_mountpoint(&self.dentry);
self.dentry.set_mounted_bit();
}
}
/// Mounts the fs on current `Dentry` as a mountpoint.
///
@ -192,7 +187,7 @@ impl Path {
}
let child_mount = self.mount_node.mount(fs, &self.dentry)?;
self.set_mountpoint(child_mount.clone());
Ok(child_mount)
}
@ -212,8 +207,6 @@ impl Path {
let child_mount = parent_mount_node.unmount(&mountpoint)?;
let child_mount = mountpoint_mount_node.unmount(&parent_mount_path)?;
mountpoint.clear_mounted_bit();
Ok(child_mount)
}

View File

@ -84,6 +84,8 @@ impl MountNode {
let key = mountpoint.key();
let child_mount = Self::new(fs, Some(Arc::downgrade(self)));
self.children.write().insert(key, child_mount.clone());
child_mount.set_mountpoint(mountpoint);
Ok(child_mount)
}
@ -96,6 +98,9 @@ impl MountNode {
.write()
.remove(&mountpoint.key())
.ok_or_else(|| Error::with_message(Errno::ENOENT, "can not find child mount"))?;
child_mount.clear_mountpoint();
Ok(child_mount)
}
@ -160,18 +165,22 @@ impl MountNode {
}
/// Detaches the mount node from the parent mount node.
fn detach_mount_node(&self) {
fn detach_from_parent(&self) {
if let Some(parent) = self.parent() {
let parent = parent.upgrade().unwrap();
parent
let child = parent
.children
.write()
.remove(&self.mountpoint().unwrap().key());
if let Some(child) = child {
child.clear_mountpoint();
}
}
}
/// Attaches the mount node to the mountpoint.
fn attach_mount_node(&self, target_path: &Path) {
fn attach_to_path(&self, target_path: &Path) {
let key = target_path.key();
target_path
.mount_node()
@ -179,7 +188,7 @@ impl MountNode {
.write()
.insert(key, self.this());
self.set_parent(target_path.mount_node());
target_path.set_mountpoint(self.this());
self.set_mountpoint(&target_path.dentry);
}
/// Grafts the mount node tree to the mountpoint.
@ -187,8 +196,9 @@ impl MountNode {
if target_path.type_() != InodeType::Dir {
return_errno!(Errno::ENOTDIR);
}
self.detach_mount_node();
self.attach_mount_node(target_path);
self.detach_from_parent();
self.attach_to_path(target_path);
Ok(())
}
@ -208,12 +218,24 @@ impl MountNode {
}
/// Sets the mountpoint.
///
/// In some cases we may need to reset the mountpoint of
/// the created `MountNode`, such as move mount.
pub(super) fn set_mountpoint(&self, inner: &Arc<Dentry>) {
pub(super) fn set_mountpoint(&self, dentry: &Arc<Dentry>) {
let mut mountpoint = self.mountpoint.write();
*mountpoint = Some(inner.clone());
if let Some(mountpoint) = mountpoint.as_deref() {
mountpoint.dec_mount_count();
}
dentry.inc_mount_count();
*mountpoint = Some(dentry.clone());
}
/// Clears the mountpoint.
pub(super) fn clear_mountpoint(&self) {
let mut mountpoint = self.mountpoint.write();
if let Some(mountpoint) = mountpoint.as_deref() {
mountpoint.dec_mount_count();
}
*mountpoint = None;
}
/// Flushes all pending filesystem metadata and cached file data to the device.