diff --git a/regression/Makefile b/regression/Makefile index 3418f0407..a84c4ca18 100644 --- a/regression/Makefile +++ b/regression/Makefile @@ -17,7 +17,7 @@ all: build $(INITRAMFS): @rm -rf $@ && mkdir -p $@ @# Mkdir necessary folders - @mkdir -p $@/bin $@/etc $@/sbin $@/usr/bin $@/root $@/tmp $@/opt $@/lib64 $@/lib/x86_64-linux-gnu + @mkdir -p $@/bin $@/etc $@/sbin $@/usr/bin $@/root $@/tmp $@/opt $@/proc $@/dev $@/lib64 $@/lib/x86_64-linux-gnu @# Install busybox @/bin/busybox --install -s $@/bin @cp /usr/bin/busybox $@/usr/bin diff --git a/services/libs/jinux-std/src/fs/fs_resolver.rs b/services/libs/jinux-std/src/fs/fs_resolver.rs index b96b4a008..bbf7905b6 100644 --- a/services/libs/jinux-std/src/fs/fs_resolver.rs +++ b/services/libs/jinux-std/src/fs/fs_resolver.rs @@ -3,29 +3,14 @@ use alloc::str; use super::file_table::FileDescripter; use super::inode_handle::InodeHandle; -use super::procfs::ProcFS; use super::ramfs::RamFS; use super::utils::{ - AccessMode, CreationFlags, Dentry, FileSystem, InodeMode, InodeType, StatusFlags, Vnode, - PATH_MAX, SYMLINKS_MAX, + AccessMode, CreationFlags, Dentry, InodeMode, InodeType, MountNode, StatusFlags, PATH_MAX, + SYMLINKS_MAX, }; lazy_static! { - static ref ROOT_FS: Arc = RamFS::new(true); - static ref ROOT_DENTRY: Arc = { - let vnode = Vnode::new(ROOT_FS.root_inode()).unwrap(); - Dentry::new_root(vnode) - }; - static ref PROC_FS: Arc = ProcFS::new(); - static ref PROC_DENTRY: Arc = { - let vnode = Vnode::new(PROC_FS.root_inode()).unwrap(); - Dentry::new_root(vnode) - }; - static ref DEV_FS: Arc = RamFS::new(false); - static ref DEV_DENTRY: Arc = { - let vnode = Vnode::new(DEV_FS.root_inode()).unwrap(); - Dentry::new_root(vnode) - }; + static ref ROOT_MOUNT: Arc = MountNode::new_root(RamFS::new(true)).unwrap(); } pub struct FsResolver { @@ -45,8 +30,8 @@ impl Clone for FsResolver { impl FsResolver { pub fn new() -> Self { Self { - root: ROOT_DENTRY.clone(), - cwd: ROOT_DENTRY.clone(), + root: ROOT_MOUNT.root_dentry().clone(), + cwd: ROOT_MOUNT.root_dentry().clone(), } } @@ -134,28 +119,7 @@ impl FsResolver { fn lookup_inner(&self, path: &FsPath, follow_tail_link: bool) -> Result> { let dentry = match path.inner { FsPathInner::Absolute(path) => { - // TODO: Mount procfs at "/proc" if mount feature is ready - if path.starts_with("/proc") { - let path = path.strip_prefix("/proc").unwrap(); - self.lookup_from_parent( - &PROC_DENTRY, - path.trim_start_matches('/'), - follow_tail_link, - )? - } else if path.starts_with("/dev") { - let path = path.strip_prefix("/dev").unwrap(); - self.lookup_from_parent( - &DEV_DENTRY, - path.trim_start_matches('/'), - follow_tail_link, - )? - } else { - self.lookup_from_parent( - &self.root, - path.trim_start_matches('/'), - follow_tail_link, - )? - } + self.lookup_from_parent(&self.root, path.trim_start_matches('/'), follow_tail_link)? } FsPathInner::CwdRelative(path) => { self.lookup_from_parent(&self.cwd, path, follow_tail_link)? diff --git a/services/libs/jinux-std/src/fs/initramfs.rs b/services/libs/jinux-std/src/fs/initramfs.rs index df896427b..c52c97220 100644 --- a/services/libs/jinux-std/src/fs/initramfs.rs +++ b/services/libs/jinux-std/src/fs/initramfs.rs @@ -1,7 +1,10 @@ -use super::fs_resolver::{FsPath, FsResolver}; -use super::utils::{InodeMode, InodeType}; use crate::prelude::*; +use super::fs_resolver::{FsPath, FsResolver}; +use super::procfs::ProcFS; +use super::ramfs::RamFS; +use super::utils::{InodeMode, InodeType}; + use cpio_decoder::{CpioDecoder, FileType}; use lending_iterator::LendingIterator; use libflate::gzip::Decoder as GZipDecoder; @@ -65,6 +68,12 @@ pub fn init(gzip_ramdisk_buf: &[u8]) -> Result<()> { } } } + // Mount ProcFS + let proc_dentry = fs.lookup(&FsPath::try_from("/proc")?)?; + proc_dentry.mount(ProcFS::new())?; + // Mount DevFS + let dev_dentry = fs.lookup(&FsPath::try_from("/dev")?)?; + dev_dentry.mount(RamFS::new(false))?; println!("[kernel] initramfs is ready"); Ok(()) diff --git a/services/libs/jinux-std/src/fs/utils/dentry_cache.rs b/services/libs/jinux-std/src/fs/utils/dentry.rs similarity index 52% rename from services/libs/jinux-std/src/fs/utils/dentry_cache.rs rename to services/libs/jinux-std/src/fs/utils/dentry.rs index 4620f2fb9..4702c0a5e 100644 --- a/services/libs/jinux-std/src/fs/utils/dentry_cache.rs +++ b/services/libs/jinux-std/src/fs/utils/dentry.rs @@ -2,9 +2,10 @@ use crate::fs::device::Device; use crate::prelude::*; use alloc::string::String; +use core::sync::atomic::{AtomicU32, Ordering}; use core::time::Duration; -use super::{FileSystem, InodeMode, InodeType, Metadata, Vnode, NAME_MAX}; +use super::{FileSystem, InodeMode, InodeType, Metadata, MountNode, Vnode, NAME_MAX}; lazy_static! { static ref DCACHE: Mutex>> = Mutex::new(BTreeMap::new()); @@ -13,60 +14,156 @@ lazy_static! { /// The dentry cache to accelerate path lookup pub struct Dentry { vnode: Vnode, - name_and_parent: RwLock<(String, Option>)>, + name_and_parent: RwLock)>>, this: Weak, children: Mutex, + mount_node: Weak, + flags: AtomicU32, } impl Dentry { - /// Create a new dentry cache with root inode - pub fn new_root(root_vnode: Vnode) -> Arc { - let root = Self::new("/", None, root_vnode); + /// Create a new root dentry with the giving vnode and mount node. + /// + /// It is been created during the construction of MountNode struct. The MountNode + /// struct holds an arc reference to this root dentry, while this dentry holds a + /// weak reference to the MountNode struct. + pub(super) fn new_root(vnode: Vnode, mount: Weak) -> Arc { + let root = Self::new(vnode, DentryOptions::Root(mount)); DCACHE.lock().insert(root.key(), root.clone()); root } - /// Internal constructor - fn new(name: &str, parent: Option>, vnode: Vnode) -> Arc { + /// Internal constructor. + fn new(vnode: Vnode, options: DentryOptions) -> Arc { Arc::new_cyclic(|weak_self| Self { vnode, - name_and_parent: RwLock::new((String::from(name), parent)), + mount_node: match &options { + DentryOptions::Root(mount) => mount.clone(), + DentryOptions::Leaf(name_and_parent) => name_and_parent.1.mount_node.clone(), + }, + flags: AtomicU32::new(DentryFlags::empty().bits()), + name_and_parent: match options { + DentryOptions::Leaf(name_and_parent) => RwLock::new(Some(name_and_parent)), + _ => RwLock::new(None), + }, this: weak_self.clone(), children: Mutex::new(Children::new()), }) } - /// Get the name of Dentry. - pub fn name(&self) -> String { - self.name_and_parent.read().0.clone() + /// Get the overlaid dentry of self. + /// + /// It will jump into the child mount if it is a mountpoint. + fn overlaid_dentry(&self) -> Arc { + if !self.is_mountpoint() { + return self.this(); + } + match self.mount_node().get(&self) { + Some(child_mount) => child_mount.root_dentry().overlaid_dentry(), + None => self.this(), + } } - /// Get the parent dentry. + /// Get the name of dentry. + /// + /// Returns "/" if it is a root dentry. + fn name(&self) -> String { + match self.name_and_parent.read().as_ref() { + Some(name_and_parent) => name_and_parent.0.clone(), + None => String::from("/"), + } + } + + /// Get the effective name of dentry. + /// + /// If it is the root of mount, it will go up to the mountpoint to get the name + /// of the mountpoint recursively. + fn effective_name(&self) -> String { + if !self.is_root_of_mount() { + return self.name(); + } + + match self.mount_node().mountpoint_dentry() { + Some(self_mountpoint) => self_mountpoint.effective_name(), + None => self.name(), + } + } + + /// Get the parent. /// /// Returns None if it is root dentry. - pub fn parent(&self) -> Option> { - self.name_and_parent.read().1.clone() + fn parent(&self) -> Option> { + 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: Option>) { + /// Get the effective parent of dentry. + /// + /// If it is the root of mount, it will go up to the mountpoint to get the parent + /// of the mountpoint recursively. + fn effective_parent(&self) -> Option> { + if !self.is_root_of_mount() { + return self.parent(); + } + + match self.mount_node().mountpoint_dentry() { + Some(self_mountpoint) => self_mountpoint.effective_parent(), + None => self.parent(), + } + } + + fn set_name_and_parent(&self, name: &str, parent: Arc) { let mut name_and_parent = self.name_and_parent.write(); - name_and_parent.0 = String::from(name); - name_and_parent.1 = parent; + *name_and_parent = Some((String::from(name), parent)); } - fn this(&self) -> Arc { + /// Get the arc reference to self. + fn this(&self) -> Arc { self.this.upgrade().unwrap() } - fn key(&self) -> DentryKey { - let parent = self.parent().unwrap_or(self.this()); - DentryKey::new(&self.name_and_parent.read().0, &parent) + /// Get the DentryKey. + pub fn key(&self) -> DentryKey { + DentryKey::new(&self) } + /// Get the vnode. pub fn vnode(&self) -> &Vnode { &self.vnode } + /// Get the DentryFlags. + fn flags(&self) -> DentryFlags { + let flags = self.flags.load(Ordering::Relaxed); + DentryFlags::from_bits(flags).unwrap() + } + + fn is_mountpoint(&self) -> bool { + self.flags().contains(DentryFlags::MOUNTED) + } + + fn set_mountpoint(&self) { + self.flags + .fetch_or(DentryFlags::MOUNTED.bits(), Ordering::Release); + } + + fn clear_mountpoint(&self) { + self.flags + .fetch_and(!(DentryFlags::MOUNTED.bits()), Ordering::Release); + } + + /// Currently, the root dentry of a fs is the root of a mount. + fn is_root_of_mount(&self) -> bool { + self.name_and_parent.read().as_ref().is_none() + } + + /// Get the mount node which the dentry belongs to. + pub fn mount_node(&self) -> Arc { + self.mount_node.upgrade().unwrap() + } + /// Create a dentry by making inode. pub fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result> { if self.vnode.inode_type() != InodeType::Dir { @@ -79,7 +176,10 @@ impl Dentry { let child = { let vnode = self.vnode.create(name, type_, mode)?; - let dentry = Dentry::new(name, Some(self.this()), vnode); + let dentry = Self::new( + vnode, + DentryOptions::Leaf((String::from(name), self.this())), + ); children.insert_dentry(&dentry); dentry }; @@ -98,7 +198,10 @@ impl Dentry { let child = { let vnode = self.vnode.mknod(name, mode, device)?; - let dentry = Dentry::new(name, Some(self.this()), vnode); + let dentry = Self::new( + vnode, + DentryOptions::Leaf((String::from(name), self.this())), + ); children.insert_dentry(&dentry); dentry }; @@ -119,14 +222,17 @@ impl Dentry { let dentry = match name { "." => self.this(), - ".." => self.parent().unwrap_or(self.this()), + ".." => self.effective_parent().unwrap_or(self.this()), name => { let mut children = self.children.lock(); match children.find_dentry(name) { - Some(dentry) => dentry.clone(), + Some(dentry) => dentry.overlaid_dentry(), None => { let vnode = self.vnode.lookup(name)?; - let dentry = Dentry::new(name, Some(self.this()), vnode); + let dentry = Self::new( + vnode, + DentryOptions::Leaf((String::from(name), self.this())), + ); children.insert_dentry(&dentry); dentry } @@ -145,9 +251,15 @@ impl Dentry { if children.find_dentry(name).is_some() { return_errno!(Errno::EEXIST); } + if !Arc::ptr_eq(&old.mount_node(), &self.mount_node()) { + return_errno_with_message!(Errno::EXDEV, "cannot cross mount"); + } let old_vnode = old.vnode(); self.vnode.link(old_vnode, name)?; - let dentry = Dentry::new(name, Some(self.this()), old_vnode.clone()); + let dentry = Self::new( + old_vnode.clone(), + DentryOptions::Leaf((String::from(name), self.this())), + ); children.insert_dentry(&dentry); Ok(()) } @@ -158,6 +270,7 @@ impl Dentry { return_errno!(Errno::ENOTDIR); } let mut children = self.children.lock(); + let _ = children.find_dentry_with_checking_mountpoint(name)?; self.vnode.unlink(name)?; children.delete_dentry(name); Ok(()) @@ -169,6 +282,7 @@ impl Dentry { return_errno!(Errno::ENOTDIR); } let mut children = self.children.lock(); + let _ = children.find_dentry_with_checking_mountpoint(name)?; self.vnode.rmdir(name)?; children.delete_dentry(name); Ok(()) @@ -206,11 +320,13 @@ impl Dentry { return Ok(()); } let mut children = self.children.lock(); + let old_dentry = children.find_dentry_with_checking_mountpoint(old_name)?; + let _ = children.find_dentry_with_checking_mountpoint(new_name)?; self.vnode.rename(old_name, &self.vnode, new_name)?; - match children.find_dentry(old_name) { + match old_dentry.as_ref() { Some(dentry) => { children.delete_dentry(old_name); - dentry.set_name_and_parent(new_name, Some(self.this())); + dentry.set_name_and_parent(new_name, self.this()); children.insert_dentry(&dentry); } None => { @@ -219,13 +335,18 @@ impl Dentry { } } else { // Self and new_dir are different Dentry + if !Arc::ptr_eq(&self.mount_node(), &new_dir.mount_node()) { + return_errno_with_message!(Errno::EXDEV, "cannot cross mount"); + } let (mut self_children, mut new_dir_children) = write_lock_children_on_two_dentries(&self, &new_dir); + let old_dentry = self_children.find_dentry_with_checking_mountpoint(old_name)?; + let _ = new_dir_children.find_dentry_with_checking_mountpoint(new_name)?; self.vnode.rename(old_name, &new_dir.vnode, new_name)?; - match self_children.find_dentry(old_name) { + match old_dentry.as_ref() { Some(dentry) => { self_children.delete_dentry(old_name); - dentry.set_name_and_parent(new_name, Some(new_dir.this())); + dentry.set_name_and_parent(new_name, new_dir.this()); new_dir_children.insert_dentry(&dentry); } None => { @@ -236,6 +357,44 @@ impl Dentry { Ok(()) } + /// Mount the fs on this dentry. It will make this dentry to be a mountpoint. + /// + /// If the given mountpoint has already been mounted, then its mounted child mount + /// will be updated. + /// The root dentry cannot be mounted. + /// + /// Return the mounted child mount. + pub fn mount(&self, fs: Arc) -> Result> { + if self.vnode.inode_type() != InodeType::Dir { + return_errno!(Errno::ENOTDIR); + } + if self.effective_parent().is_none() { + return_errno_with_message!(Errno::EINVAL, "can not mount on root"); + } + + let child_mount = self.mount_node().mount(fs, &self.this())?; + self.set_mountpoint(); + Ok(child_mount) + } + + /// Unmount and return the mounted child mount. + /// + /// Note that the root mount cannot be unmounted. + pub fn umount(&self) -> Result> { + if !self.is_root_of_mount() { + return_errno_with_message!(Errno::EINVAL, "not mounted"); + } + + let mount_node = self.mount_node(); + let Some(mountpoint) = mount_node.mountpoint_dentry() else { + return_errno_with_message!(Errno::EINVAL, "cannot umount root mount"); + }; + + let child_mount = mountpoint.mount_node().umount(mountpoint)?; + mountpoint.clear_mountpoint(); + Ok(child_mount) + } + /// Get the filesystem the inode belongs to pub fn fs(&self) -> Arc { self.vnode.fs() @@ -287,16 +446,18 @@ impl Dentry { } /// Get the absolute path. + /// + /// It will resolve the mountpoint automatically. pub fn abs_path(&self) -> String { - let mut path = self.name(); + let mut path = self.effective_name(); let mut dentry = self.this(); loop { - match dentry.parent() { + match dentry.effective_parent() { None => break, Some(parent_dentry) => { path = { - let parent_name = parent_dentry.name(); + let parent_name = parent_dentry.effective_name(); if parent_name != "/" { parent_name + "/" + &path } else { @@ -313,6 +474,41 @@ impl Dentry { } } +/// DentryKey is the unique identifier for Dentry in DCACHE. +/// +/// 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. +#[derive(Clone, Hash, PartialOrd, Ord, Eq, PartialEq)] +pub struct DentryKey { + name: String, + parent_ptr: usize, +} + +impl DentryKey { + /// Form the DentryKey for the dentry. + pub 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()), + }; + Self { + name, + parent_ptr: Arc::as_ptr(&parent) as usize, + } + } +} + +bitflags! { + struct DentryFlags: u32 { + const MOUNTED = 1 << 0; + } +} + +enum DentryOptions { + Root(Weak), + Leaf((String, Arc)), +} + struct Children { inner: BTreeMap>, } @@ -348,20 +544,18 @@ impl Children { None } } -} -#[derive(Clone, Hash, PartialOrd, Ord, Eq, PartialEq)] -struct DentryKey { - name: String, - parent_ptr: usize, -} - -impl DentryKey { - pub fn new(name: &str, parent: &Arc) -> Self { - Self { - name: String::from(name), - parent_ptr: Arc::as_ptr(parent) as usize, + pub fn find_dentry_with_checking_mountpoint( + &mut self, + name: &str, + ) -> Result>> { + let dentry = self.find_dentry(name); + if let Some(dentry) = dentry.as_ref() { + if dentry.is_mountpoint() { + return_errno_with_message!(Errno::EBUSY, "dentry is mountpint"); + } } + Ok(dentry) } } diff --git a/services/libs/jinux-std/src/fs/utils/mod.rs b/services/libs/jinux-std/src/fs/utils/mod.rs index 14b61df1c..ff9d7a202 100644 --- a/services/libs/jinux-std/src/fs/utils/mod.rs +++ b/services/libs/jinux-std/src/fs/utils/mod.rs @@ -3,7 +3,7 @@ pub use access_mode::AccessMode; pub use channel::{Channel, Consumer, Producer}; pub use creation_flags::CreationFlags; -pub use dentry_cache::Dentry; +pub use dentry::{Dentry, DentryKey}; pub use dirent_visitor::DirentVisitor; pub use direntry_vec::DirEntryVecExt; pub use file_creation_mask::FileCreationMask; @@ -11,6 +11,7 @@ pub use fs::{FileSystem, FsFlags, SuperBlock}; pub use inode::{Inode, InodeMode, InodeType, Metadata}; pub use io_events::IoEvents; pub use ioctl::IoctlCmd; +pub use mount::MountNode; pub use page_cache::PageCache; pub use poll::{Pollee, Poller}; pub use status_flags::StatusFlags; @@ -19,7 +20,7 @@ pub use vnode::{Vnode, VnodeWriter}; mod access_mode; mod channel; mod creation_flags; -mod dentry_cache; +mod dentry; mod dirent_visitor; mod direntry_vec; mod file_creation_mask; @@ -27,6 +28,7 @@ mod fs; mod inode; mod io_events; mod ioctl; +mod mount; mod page_cache; mod poll; mod status_flags; diff --git a/services/libs/jinux-std/src/fs/utils/mount.rs b/services/libs/jinux-std/src/fs/utils/mount.rs new file mode 100644 index 000000000..be0e28c2e --- /dev/null +++ b/services/libs/jinux-std/src/fs/utils/mount.rs @@ -0,0 +1,121 @@ +use crate::prelude::*; + +use super::{Dentry, DentryKey, FileSystem, InodeType, Vnode}; + +/// The MountNode can form a mount tree to maintain the mount information. +pub struct MountNode { + /// Root dentry. + root_dentry: Arc, + /// 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: Option>, + /// The associated FS. + fs: Arc, + /// Child mount nodes which are mounted on one dentry of self. + children: Mutex>>, + /// Reference to self. + this: Weak, +} + +impl MountNode { + /// Create 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 dentry of it. + /// + /// 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. + pub fn new_root(fs: Arc) -> Result> { + Self::new(fs, None) + } + + /// The internal constructor. + /// + /// Root mount node has no mountpoint which other mount nodes must have mountpoint. + fn new(fs: Arc, mountpoint: Option>) -> Result> { + let vnode = Vnode::new(fs.root_inode())?; + Ok(Arc::new_cyclic(|weak_self| Self { + root_dentry: Dentry::new_root(vnode, weak_self.clone()), + mountpoint_dentry: mountpoint, + children: Mutex::new(BTreeMap::new()), + fs, + this: weak_self.clone(), + })) + } + + /// Mount an 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. + /// + /// The mountpoint should belong to this mount node, or an error is returned. + /// + /// It is allowed to mount a fs even if the fs has been provided to another + /// mountpoint. It is the fs's responsibility to ensure the data consistency. + /// + /// Return the mounted child mount. + pub fn mount(&self, fs: Arc, mountpoint: &Arc) -> Result> { + if !Arc::ptr_eq(&mountpoint.mount_node(), &self.this()) { + return_errno_with_message!(Errno::EINVAL, "mountpoint not belongs to this"); + } + if mountpoint.inode_type() != InodeType::Dir { + return_errno!(Errno::ENOTDIR); + } + + let key = mountpoint.key(); + let child_mount = Self::new(fs, Some(mountpoint.clone()))?; + self.children.lock().insert(key, child_mount.clone()); + Ok(child_mount) + } + + /// Unmount a child mount node from the mountpoint and return it. + /// + /// The mountpoint should belong to this mount node, or an error is returned. + pub fn umount(&self, mountpoint: &Dentry) -> Result> { + if !Arc::ptr_eq(&mountpoint.mount_node(), &self.this()) { + return_errno_with_message!(Errno::EINVAL, "mountpoint not belongs to this"); + } + + let child_mount = self + .children + .lock() + .remove(&mountpoint.key()) + .ok_or_else(|| Error::with_message(Errno::ENOENT, "can not find child mount"))?; + Ok(child_mount) + } + + /// Try to get a child mount node from the mountpoint. + pub fn get(&self, mountpoint: &Dentry) -> Option> { + if !Arc::ptr_eq(&mountpoint.mount_node(), &self.this()) { + return None; + } + self.children.lock().get(&mountpoint.key()).cloned() + } + + /// Get the root dentry of this mount node. + pub fn root_dentry(&self) -> &Arc { + &self.root_dentry + } + + /// Try to get the mountpoint dentry of this mount node. + pub fn mountpoint_dentry(&self) -> Option<&Arc> { + self.mountpoint_dentry.as_ref() + } + + /// Try to get the parent mount node. + pub fn parent(&self) -> Option> { + self.mountpoint_dentry + .as_ref() + .map(|dentry| dentry.mount_node()) + } + + /// Get strong reference to self. + fn this(&self) -> Arc { + self.this.upgrade().unwrap() + } + + /// Get the associated fs. + pub fn fs(&self) -> &Arc { + &self.fs + } +} diff --git a/services/libs/jinux-std/src/syscall/rename.rs b/services/libs/jinux-std/src/syscall/rename.rs index a348f25b3..5b2cca0e7 100644 --- a/services/libs/jinux-std/src/syscall/rename.rs +++ b/services/libs/jinux-std/src/syscall/rename.rs @@ -28,14 +28,15 @@ pub fn sys_renameat( let current = current!(); let fs = current.fs().read(); - let old_dentry = { + let (old_dir_dentry, old_name) = { let old_pathname = old_pathname.to_string_lossy(); if old_pathname.is_empty() { return_errno_with_message!(Errno::ENOENT, "oldpath is empty"); } let old_fs_path = FsPath::new(old_dirfd, old_pathname.as_ref())?; - fs.lookup_no_follow(&old_fs_path)? + fs.lookup_dir_and_base_name(&old_fs_path)? }; + let old_dentry = old_dir_dentry.lookup(&old_name)?; let (new_dir_dentry, new_name) = { let new_pathname = new_pathname.to_string_lossy(); @@ -63,8 +64,7 @@ pub fn sys_renameat( } } - let old_dir_dentry = old_dentry.parent().unwrap(); - old_dir_dentry.rename(&old_dentry.name(), &new_dir_dentry, &new_name)?; + old_dir_dentry.rename(&old_name, &new_dir_dentry, &new_name)?; Ok(SyscallReturn::Return(0)) }