Fix the mountpoint state maintaining for Dentry
This commit is contained in:
parent
ae32062e77
commit
aea4013a43
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in New Issue