mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 08:53:29 +00:00
Refactor Dentry
to optimize the vfs layer
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
271e893889
commit
ea489252f4
@ -16,7 +16,7 @@ mod pty;
|
|||||||
pub use pty::{PtyMaster, PtySlave};
|
pub use pty::{PtyMaster, PtySlave};
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
|
|
||||||
static DEV_PTS: Once<Arc<Dentry>> = Once::new();
|
static DEV_PTS: Once<Dentry> = Once::new();
|
||||||
|
|
||||||
pub fn init() -> Result<()> {
|
pub fn init() -> Result<()> {
|
||||||
let fs = FsResolver::new();
|
let fs = FsResolver::new();
|
||||||
|
@ -91,7 +91,7 @@ impl From<u64> for DeviceId {
|
|||||||
///
|
///
|
||||||
/// If the parent path is not existing, `mkdir -p` the parent path.
|
/// If the parent path is not existing, `mkdir -p` the parent path.
|
||||||
/// This function is used in registering device.
|
/// This function is used in registering device.
|
||||||
pub fn add_node(device: Arc<dyn Device>, path: &str) -> Result<Arc<Dentry>> {
|
pub fn add_node(device: Arc<dyn Device>, path: &str) -> Result<Dentry> {
|
||||||
let mut dentry = {
|
let mut dentry = {
|
||||||
let fs_resolver = FsResolver::new();
|
let fs_resolver = FsResolver::new();
|
||||||
fs_resolver.lookup(&FsPath::try_from("/dev").unwrap())?
|
fs_resolver.lookup(&FsPath::try_from("/dev").unwrap())?
|
||||||
|
@ -17,8 +17,8 @@ pub const AT_FDCWD: FileDesc = -100;
|
|||||||
/// File system resolver.
|
/// File system resolver.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FsResolver {
|
pub struct FsResolver {
|
||||||
root: Arc<Dentry>,
|
root: Dentry,
|
||||||
cwd: Arc<Dentry>,
|
cwd: Dentry,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FsResolver {
|
impl FsResolver {
|
||||||
@ -31,22 +31,22 @@ impl FsResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the root directory.
|
/// Gets the root directory.
|
||||||
pub fn root(&self) -> &Arc<Dentry> {
|
pub fn root(&self) -> &Dentry {
|
||||||
&self.root
|
&self.root
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the current working directory.
|
/// Gets the current working directory.
|
||||||
pub fn cwd(&self) -> &Arc<Dentry> {
|
pub fn cwd(&self) -> &Dentry {
|
||||||
&self.cwd
|
&self.cwd
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the current working directory to the given `dentry`.
|
/// Sets the current working directory to the given `dentry`.
|
||||||
pub fn set_cwd(&mut self, dentry: Arc<Dentry>) {
|
pub fn set_cwd(&mut self, dentry: Dentry) {
|
||||||
self.cwd = dentry;
|
self.cwd = dentry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the root directory to the given `dentry`.
|
/// Sets the root directory to the given `dentry`.
|
||||||
pub fn set_root(&mut self, dentry: Arc<Dentry>) {
|
pub fn set_root(&mut self, dentry: Dentry) {
|
||||||
self.root = dentry;
|
self.root = dentry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ impl FsResolver {
|
|||||||
|
|
||||||
fn open_existing_file(
|
fn open_existing_file(
|
||||||
&self,
|
&self,
|
||||||
target_dentry: Arc<Dentry>,
|
target_dentry: Dentry,
|
||||||
open_args: &OpenArgs,
|
open_args: &OpenArgs,
|
||||||
) -> Result<InodeHandle> {
|
) -> Result<InodeHandle> {
|
||||||
let inode = target_dentry.inode();
|
let inode = target_dentry.inode();
|
||||||
@ -147,19 +147,19 @@ impl FsResolver {
|
|||||||
|
|
||||||
/// Lookups the target dentry according to the `path`.
|
/// Lookups the target dentry according to the `path`.
|
||||||
/// Symlinks are always followed.
|
/// Symlinks are always followed.
|
||||||
pub fn lookup(&self, path: &FsPath) -> Result<Arc<Dentry>> {
|
pub fn lookup(&self, path: &FsPath) -> Result<Dentry> {
|
||||||
let (follow_tail_link, stop_on_parent) = (true, false);
|
let (follow_tail_link, stop_on_parent) = (true, false);
|
||||||
self.lookup_inner(path, &mut LookupCtx::new(follow_tail_link, stop_on_parent))
|
self.lookup_inner(path, &mut LookupCtx::new(follow_tail_link, stop_on_parent))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lookups the target dentry according to the `path`.
|
/// Lookups the target dentry according to the `path`.
|
||||||
/// If the last component is a symlink, it will not be followed.
|
/// If the last component is a symlink, it will not be followed.
|
||||||
pub fn lookup_no_follow(&self, path: &FsPath) -> Result<Arc<Dentry>> {
|
pub fn lookup_no_follow(&self, path: &FsPath) -> Result<Dentry> {
|
||||||
let (follow_tail_link, stop_on_parent) = (false, false);
|
let (follow_tail_link, stop_on_parent) = (false, false);
|
||||||
self.lookup_inner(path, &mut LookupCtx::new(follow_tail_link, stop_on_parent))
|
self.lookup_inner(path, &mut LookupCtx::new(follow_tail_link, stop_on_parent))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_inner(&self, path: &FsPath, lookup_ctx: &mut LookupCtx) -> Result<Arc<Dentry>> {
|
fn lookup_inner(&self, path: &FsPath, lookup_ctx: &mut LookupCtx) -> Result<Dentry> {
|
||||||
let dentry = match path.inner {
|
let dentry = match path.inner {
|
||||||
FsPathInner::Absolute(path) => {
|
FsPathInner::Absolute(path) => {
|
||||||
self.lookup_from_parent(&self.root, path.trim_start_matches('/'), lookup_ctx)?
|
self.lookup_from_parent(&self.root, path.trim_start_matches('/'), lookup_ctx)?
|
||||||
@ -192,10 +192,10 @@ impl FsResolver {
|
|||||||
#[allow(clippy::redundant_closure)]
|
#[allow(clippy::redundant_closure)]
|
||||||
fn lookup_from_parent(
|
fn lookup_from_parent(
|
||||||
&self,
|
&self,
|
||||||
parent: &Arc<Dentry>,
|
parent: &Dentry,
|
||||||
relative_path: &str,
|
relative_path: &str,
|
||||||
lookup_ctx: &mut LookupCtx,
|
lookup_ctx: &mut LookupCtx,
|
||||||
) -> Result<Arc<Dentry>> {
|
) -> Result<Dentry> {
|
||||||
debug_assert!(!relative_path.starts_with('/'));
|
debug_assert!(!relative_path.starts_with('/'));
|
||||||
|
|
||||||
if relative_path.len() > PATH_MAX {
|
if relative_path.len() > PATH_MAX {
|
||||||
@ -285,7 +285,7 @@ impl FsResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Lookups the target dentry according to the given `fd`.
|
/// Lookups the target dentry according to the given `fd`.
|
||||||
pub fn lookup_from_fd(&self, fd: FileDesc) -> Result<Arc<Dentry>> {
|
pub fn lookup_from_fd(&self, fd: FileDesc) -> Result<Dentry> {
|
||||||
let current = current!();
|
let current = current!();
|
||||||
let file_table = current.file_table().lock();
|
let file_table = current.file_table().lock();
|
||||||
let inode_handle = file_table
|
let inode_handle = file_table
|
||||||
@ -299,7 +299,7 @@ impl FsResolver {
|
|||||||
/// the base file name according to the given `path`.
|
/// the base file name according to the given `path`.
|
||||||
///
|
///
|
||||||
/// If the last component is a symlink, do not deference it.
|
/// If the last component is a symlink, do not deference it.
|
||||||
pub fn lookup_dir_and_base_name(&self, path: &FsPath) -> Result<(Arc<Dentry>, String)> {
|
pub fn lookup_dir_and_base_name(&self, path: &FsPath) -> Result<(Dentry, String)> {
|
||||||
if matches!(path.inner, FsPathInner::Fd(_)) {
|
if matches!(path.inner, FsPathInner::Fd(_)) {
|
||||||
return_errno!(Errno::ENOENT);
|
return_errno!(Errno::ENOENT);
|
||||||
}
|
}
|
||||||
@ -327,7 +327,7 @@ impl FsResolver {
|
|||||||
&self,
|
&self,
|
||||||
path: &FsPath,
|
path: &FsPath,
|
||||||
is_dir: bool,
|
is_dir: bool,
|
||||||
) -> Result<(Arc<Dentry>, String)> {
|
) -> Result<(Dentry, String)> {
|
||||||
if matches!(path.inner, FsPathInner::Fd(_)) {
|
if matches!(path.inner, FsPathInner::Fd(_)) {
|
||||||
return_errno!(Errno::ENOENT);
|
return_errno!(Errno::ENOENT);
|
||||||
}
|
}
|
||||||
@ -364,7 +364,7 @@ struct LookupCtx {
|
|||||||
stop_on_parent: bool,
|
stop_on_parent: bool,
|
||||||
// (file_name, file_is_dir)
|
// (file_name, file_is_dir)
|
||||||
tail_file: Option<(String, bool)>,
|
tail_file: Option<(String, bool)>,
|
||||||
parent: Option<Arc<Dentry>>,
|
parent: Option<Dentry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LookupCtx {
|
impl LookupCtx {
|
||||||
@ -394,7 +394,7 @@ impl LookupCtx {
|
|||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parent(&self) -> Option<&Arc<Dentry>> {
|
pub fn parent(&self) -> Option<&Dentry> {
|
||||||
self.parent.as_ref()
|
self.parent.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,7 +402,7 @@ impl LookupCtx {
|
|||||||
let _ = self.tail_file.insert((file_name.to_string(), file_is_dir));
|
let _ = self.tail_file.insert((file_name.to_string(), file_is_dir));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_parent(&mut self, parent: &Arc<Dentry>) {
|
pub fn set_parent(&mut self, parent: &Dentry) {
|
||||||
let _ = self.parent.insert(parent.clone());
|
let _ = self.parent.insert(parent.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,7 @@ use super::*;
|
|||||||
use crate::{prelude::*, process::signal::Pollable};
|
use crate::{prelude::*, process::signal::Pollable};
|
||||||
|
|
||||||
impl InodeHandle<Rights> {
|
impl InodeHandle<Rights> {
|
||||||
pub fn new(
|
pub fn new(dentry: Dentry, access_mode: AccessMode, status_flags: StatusFlags) -> Result<Self> {
|
||||||
dentry: Arc<Dentry>,
|
|
||||||
access_mode: AccessMode,
|
|
||||||
status_flags: StatusFlags,
|
|
||||||
) -> Result<Self> {
|
|
||||||
let inode_mode = dentry.inode().mode()?;
|
let inode_mode = dentry.inode().mode()?;
|
||||||
if access_mode.is_readable() && !inode_mode.is_readable() {
|
if access_mode.is_readable() && !inode_mode.is_readable() {
|
||||||
return_errno_with_message!(Errno::EACCES, "file is not readable");
|
return_errno_with_message!(Errno::EACCES, "file is not readable");
|
||||||
@ -24,7 +20,7 @@ impl InodeHandle<Rights> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_unchecked_access(
|
pub fn new_unchecked_access(
|
||||||
dentry: Arc<Dentry>,
|
dentry: Dentry,
|
||||||
access_mode: AccessMode,
|
access_mode: AccessMode,
|
||||||
status_flags: StatusFlags,
|
status_flags: StatusFlags,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
|
@ -32,7 +32,7 @@ use crate::{
|
|||||||
pub struct InodeHandle<R = Rights>(Arc<InodeHandle_>, R);
|
pub struct InodeHandle<R = Rights>(Arc<InodeHandle_>, R);
|
||||||
|
|
||||||
struct InodeHandle_ {
|
struct InodeHandle_ {
|
||||||
dentry: Arc<Dentry>,
|
dentry: Dentry,
|
||||||
/// `file_io` is Similar to `file_private` field in `file` structure in linux. If
|
/// `file_io` is Similar to `file_private` field in `file` structure in linux. If
|
||||||
/// `file_io` is Some, typical file operations including `read`, `write`, `poll`,
|
/// `file_io` is Some, typical file operations including `read`, `write`, `poll`,
|
||||||
/// `ioctl` will be provided by `file_io`, instead of `dentry`.
|
/// `ioctl` will be provided by `file_io`, instead of `dentry`.
|
||||||
@ -354,7 +354,7 @@ impl Debug for InodeHandle_ {
|
|||||||
|
|
||||||
/// Methods for both dyn and static
|
/// Methods for both dyn and static
|
||||||
impl<R> InodeHandle<R> {
|
impl<R> InodeHandle<R> {
|
||||||
pub fn dentry(&self) -> &Arc<Dentry> {
|
pub fn dentry(&self) -> &Dentry {
|
||||||
&self.0.dentry
|
&self.0.dentry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,21 +22,20 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// A `Dentry` is used to represent a location in the mount tree.
|
/// A `Dentry` is used to represent a location in the mount tree.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Dentry {
|
pub struct Dentry {
|
||||||
mount_node: Arc<MountNode>,
|
mount_node: Arc<MountNode>,
|
||||||
inner: Arc<Dentry_>,
|
inner: Arc<Dentry_>,
|
||||||
this: Weak<Dentry>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The inner structure of `Dentry` for caching helpful nodes
|
/// The inner structure of `Dentry` for caching helpful nodes
|
||||||
/// to accelerate the path lookup.
|
/// to accelerate the path lookup.
|
||||||
pub struct Dentry_ {
|
pub struct Dentry_ {
|
||||||
inode: Arc<dyn Inode>,
|
inode: Arc<dyn Inode>,
|
||||||
name_and_parent: RwMutex<Option<(String, Arc<Dentry_>)>>,
|
name_and_parent: RwLock<Option<(String, Arc<Dentry_>)>>,
|
||||||
this: Weak<Dentry_>,
|
|
||||||
children: RwMutex<Children>,
|
children: RwMutex<Children>,
|
||||||
flags: AtomicU32,
|
flags: AtomicU32,
|
||||||
|
this: Weak<Dentry_>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dentry_ {
|
impl Dentry_ {
|
||||||
@ -53,8 +52,8 @@ impl Dentry_ {
|
|||||||
inode,
|
inode,
|
||||||
flags: AtomicU32::new(DentryFlags::empty().bits()),
|
flags: AtomicU32::new(DentryFlags::empty().bits()),
|
||||||
name_and_parent: match options {
|
name_and_parent: match options {
|
||||||
DentryOptions::Leaf(name_and_parent) => RwMutex::new(Some(name_and_parent)),
|
DentryOptions::Leaf(name_and_parent) => RwLock::new(Some(name_and_parent)),
|
||||||
_ => RwMutex::new(None),
|
_ => RwLock::new(None),
|
||||||
},
|
},
|
||||||
this: weak_self.clone(),
|
this: weak_self.clone(),
|
||||||
children: RwMutex::new(Children::new()),
|
children: RwMutex::new(Children::new()),
|
||||||
@ -139,129 +138,116 @@ impl Dentry_ {
|
|||||||
|
|
||||||
/// Creates a `Dentry_` by creating a new inode of the `type_` with the `mode`.
|
/// Creates a `Dentry_` by creating a new inode of the `type_` with the `mode`.
|
||||||
pub fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<Self>> {
|
pub fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<Self>> {
|
||||||
if self.inode.type_() != InodeType::Dir {
|
if self.type_() != InodeType::Dir {
|
||||||
return_errno!(Errno::ENOTDIR);
|
return_errno!(Errno::ENOTDIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
let children = self.children.upread();
|
let children = self.children.upread();
|
||||||
if children.find_dentry(name).is_some() {
|
if children.contains(name) {
|
||||||
return_errno!(Errno::EEXIST);
|
return_errno!(Errno::EEXIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
let child = {
|
let new_inode = self.inode.create(name, type_, mode)?;
|
||||||
let inode = self.inode.create(name, type_, mode)?;
|
let name = String::from(name);
|
||||||
let dentry = Self::new(
|
let new_child = Dentry_::new(new_inode, DentryOptions::Leaf((name.clone(), self.this())));
|
||||||
inode,
|
|
||||||
DentryOptions::Leaf((String::from(name), self.this())),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut children = children.upgrade();
|
let mut children = children.upgrade();
|
||||||
children.insert_dentry(&dentry);
|
children.insert(name, new_child.clone());
|
||||||
dentry
|
Ok(new_child)
|
||||||
};
|
|
||||||
Ok(child)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lookups a target `Dentry_` from the cache in children.
|
/// Lookups a target `Dentry_` from the cache in children.
|
||||||
pub fn lookup_via_cache(&self, name: &str) -> Option<Arc<Dentry_>> {
|
pub fn lookup_via_cache(&self, name: &str) -> Option<Arc<Dentry_>> {
|
||||||
let children = self.children.read();
|
let children = self.children.read();
|
||||||
children.find_dentry(name)
|
children.find(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lookups a target `Dentry_` from the file system.
|
/// Lookups a target `Dentry_` from the file system.
|
||||||
pub fn lookup_via_fs(&self, name: &str) -> Result<Arc<Dentry_>> {
|
pub fn lookup_via_fs(&self, name: &str) -> Result<Arc<Dentry_>> {
|
||||||
let children = self.children.upread();
|
let children = self.children.upread();
|
||||||
|
|
||||||
let inode = self.inode.lookup(name)?;
|
let inode = self.inode.lookup(name)?;
|
||||||
let inner = Self::new(
|
let name = String::from(name);
|
||||||
inode,
|
let target = Self::new(inode, DentryOptions::Leaf((name.clone(), self.this())));
|
||||||
DentryOptions::Leaf((String::from(name), self.this())),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut children = children.upgrade();
|
let mut children = children.upgrade();
|
||||||
children.insert_dentry(&inner);
|
children.insert(name, target.clone());
|
||||||
Ok(inner)
|
Ok(target)
|
||||||
}
|
|
||||||
|
|
||||||
fn insert_dentry(&self, child_dentry: &Arc<Dentry_>) {
|
|
||||||
let mut children = self.children.write();
|
|
||||||
children.insert_dentry(child_dentry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a `Dentry_` by making an inode of the `type_` with the `mode`.
|
/// Creates a `Dentry_` by making an inode of the `type_` with the `mode`.
|
||||||
pub fn mknod(&self, name: &str, mode: InodeMode, type_: MknodType) -> Result<Arc<Self>> {
|
pub fn mknod(&self, name: &str, mode: InodeMode, type_: MknodType) -> Result<Arc<Self>> {
|
||||||
if self.inode.type_() != InodeType::Dir {
|
if self.type_() != InodeType::Dir {
|
||||||
return_errno!(Errno::ENOTDIR);
|
return_errno!(Errno::ENOTDIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
let children = self.children.upread();
|
let children = self.children.upread();
|
||||||
if children.find_dentry(name).is_some() {
|
if children.contains(name) {
|
||||||
return_errno!(Errno::EEXIST);
|
return_errno!(Errno::EEXIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
let child = {
|
|
||||||
let inode = self.inode.mknod(name, mode, type_)?;
|
let inode = self.inode.mknod(name, mode, type_)?;
|
||||||
let dentry = Self::new(
|
let name = String::from(name);
|
||||||
inode,
|
let new_child = Dentry_::new(inode, DentryOptions::Leaf((name.clone(), self.this())));
|
||||||
DentryOptions::Leaf((String::from(name), self.this())),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut children = children.upgrade();
|
let mut children = children.upgrade();
|
||||||
children.insert_dentry(&dentry);
|
children.insert(name, new_child.clone());
|
||||||
dentry
|
Ok(new_child)
|
||||||
};
|
|
||||||
Ok(child)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Links a new name for the `Dentry_` by `link()` the inner inode.
|
/// Links a new name for the `Dentry_` by `link()` the inner inode.
|
||||||
pub fn link(&self, old: &Arc<Self>, name: &str) -> Result<()> {
|
pub fn link(&self, old: &Arc<Self>, name: &str) -> Result<()> {
|
||||||
if self.inode.type_() != InodeType::Dir {
|
if self.type_() != InodeType::Dir {
|
||||||
return_errno!(Errno::ENOTDIR);
|
return_errno!(Errno::ENOTDIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
let children = self.children.upread();
|
let children = self.children.upread();
|
||||||
if children.find_dentry(name).is_some() {
|
if children.contains(name) {
|
||||||
return_errno!(Errno::EEXIST);
|
return_errno!(Errno::EEXIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
let old_inode = old.inode();
|
let old_inode = old.inode();
|
||||||
self.inode.link(old_inode, name)?;
|
self.inode.link(old_inode, name)?;
|
||||||
let dentry = Self::new(
|
let name = String::from(name);
|
||||||
|
let dentry = Dentry_::new(
|
||||||
old_inode.clone(),
|
old_inode.clone(),
|
||||||
DentryOptions::Leaf((String::from(name), self.this())),
|
DentryOptions::Leaf((name.clone(), self.this())),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut children = children.upgrade();
|
let mut children = children.upgrade();
|
||||||
children.insert_dentry(&dentry);
|
children.insert(name, dentry);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deletes a `Dentry_` by `unlink()` the inner inode.
|
/// Deletes a `Dentry_` by `unlink()` the inner inode.
|
||||||
pub fn unlink(&self, name: &str) -> Result<()> {
|
pub fn unlink(&self, name: &str) -> Result<()> {
|
||||||
if self.inode.type_() != InodeType::Dir {
|
if self.type_() != InodeType::Dir {
|
||||||
return_errno!(Errno::ENOTDIR);
|
return_errno!(Errno::ENOTDIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
let children = self.children.upread();
|
let children = self.children.upread();
|
||||||
let _ = children.find_dentry_with_checking_mountpoint(name)?;
|
children.check_mountpoint(name)?;
|
||||||
|
|
||||||
self.inode.unlink(name)?;
|
self.inode.unlink(name)?;
|
||||||
|
|
||||||
let mut children = children.upgrade();
|
let mut children = children.upgrade();
|
||||||
children.delete_dentry(name);
|
children.delete(name);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deletes a directory `Dentry_` by `rmdir()` the inner inode.
|
/// Deletes a directory `Dentry_` by `rmdir()` the inner inode.
|
||||||
pub fn rmdir(&self, name: &str) -> Result<()> {
|
pub fn rmdir(&self, name: &str) -> Result<()> {
|
||||||
if self.inode.type_() != InodeType::Dir {
|
if self.type_() != InodeType::Dir {
|
||||||
return_errno!(Errno::ENOTDIR);
|
return_errno!(Errno::ENOTDIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
let children = self.children.upread();
|
let children = self.children.upread();
|
||||||
let _ = children.find_dentry_with_checking_mountpoint(name)?;
|
children.check_mountpoint(name)?;
|
||||||
|
|
||||||
self.inode.rmdir(name)?;
|
self.inode.rmdir(name)?;
|
||||||
|
|
||||||
let mut children = children.upgrade();
|
let mut children = children.upgrade();
|
||||||
children.delete_dentry(name);
|
children.delete(name);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,7 +256,7 @@ impl Dentry_ {
|
|||||||
if old_name == "." || old_name == ".." || new_name == "." || new_name == ".." {
|
if old_name == "." || old_name == ".." || new_name == "." || new_name == ".." {
|
||||||
return_errno_with_message!(Errno::EISDIR, "old_name or new_name is a directory");
|
return_errno_with_message!(Errno::EISDIR, "old_name or new_name is a directory");
|
||||||
}
|
}
|
||||||
if self.inode.type_() != InodeType::Dir || new_dir.inode.type_() != InodeType::Dir {
|
if self.type_() != InodeType::Dir || new_dir.type_() != InodeType::Dir {
|
||||||
return_errno!(Errno::ENOTDIR);
|
return_errno!(Errno::ENOTDIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,37 +267,38 @@ impl Dentry_ {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let children = self.children.upread();
|
let children = self.children.upread();
|
||||||
let old_dentry = children.find_dentry_with_checking_mountpoint(old_name)?;
|
let old_dentry = children.check_mountpoint_then_find(old_name)?;
|
||||||
let _ = children.find_dentry_with_checking_mountpoint(new_name)?;
|
children.check_mountpoint(new_name)?;
|
||||||
|
|
||||||
self.inode.rename(old_name, &self.inode, new_name)?;
|
self.inode.rename(old_name, &self.inode, new_name)?;
|
||||||
|
|
||||||
let mut children = children.upgrade();
|
let mut children = children.upgrade();
|
||||||
match old_dentry.as_ref() {
|
match old_dentry.as_ref() {
|
||||||
Some(dentry) => {
|
Some(dentry) => {
|
||||||
children.delete_dentry(old_name);
|
children.delete(old_name);
|
||||||
dentry.set_name_and_parent(new_name, self.this());
|
dentry.set_name_and_parent(new_name, self.this());
|
||||||
children.insert_dentry(dentry);
|
children.insert(new_name.to_string(), dentry.clone());
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
children.delete_dentry(new_name);
|
children.delete(new_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// The two are different dentries
|
// The two are different dentries
|
||||||
let (mut self_children, mut new_dir_children) =
|
let (mut self_children, mut new_dir_children) =
|
||||||
write_lock_children_on_two_dentries(self, new_dir);
|
write_lock_children_on_two_dentries(self, new_dir);
|
||||||
let old_dentry = self_children.find_dentry_with_checking_mountpoint(old_name)?;
|
let old_dentry = self_children.check_mountpoint_then_find(old_name)?;
|
||||||
let _ = new_dir_children.find_dentry_with_checking_mountpoint(new_name)?;
|
new_dir_children.check_mountpoint(new_name)?;
|
||||||
|
|
||||||
self.inode.rename(old_name, &new_dir.inode, new_name)?;
|
self.inode.rename(old_name, &new_dir.inode, new_name)?;
|
||||||
match old_dentry.as_ref() {
|
match old_dentry.as_ref() {
|
||||||
Some(dentry) => {
|
Some(dentry) => {
|
||||||
self_children.delete_dentry(old_name);
|
self_children.delete(old_name);
|
||||||
dentry.set_name_and_parent(new_name, new_dir.this());
|
dentry.set_name_and_parent(new_name, new_dir.this());
|
||||||
new_dir_children.insert_dentry(dentry);
|
new_dir_children.insert(new_name.to_string(), dentry.clone());
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
new_dir_children.delete_dentry(new_name);
|
new_dir_children.delete(new_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -387,41 +374,60 @@ enum DentryOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Children {
|
struct Children {
|
||||||
inner: HashMap<String, Arc<Dentry_>>,
|
dentries: HashMap<String, Arc<Dentry_>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Children {
|
impl Children {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: HashMap::new(),
|
dentries: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_dentry(&mut self, dentry: &Arc<Dentry_>) {
|
pub fn len(&self) -> usize {
|
||||||
|
self.dentries.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn contains(&self, name: &str) -> bool {
|
||||||
|
self.dentries.contains_key(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find(&self, name: &str) -> Option<Arc<Dentry_>> {
|
||||||
|
self.dentries.get(name).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, name: String, dentry: Arc<Dentry_>) {
|
||||||
// Do not cache it in the children if is not cacheable.
|
// Do not cache it in the children if is not cacheable.
|
||||||
// When we lookup it from the parent, it will always be newly created.
|
// When we lookup it from the parent, it will always be newly created.
|
||||||
if !dentry.inode().is_dentry_cacheable() {
|
if !dentry.inode.is_dentry_cacheable() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = self.inner.insert(dentry.name(), dentry.clone());
|
let _ = self.dentries.insert(name, dentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete_dentry(&mut self, name: &str) -> Option<Arc<Dentry_>> {
|
pub fn delete(&mut self, name: &str) -> Option<Arc<Dentry_>> {
|
||||||
self.inner.remove(name)
|
self.dentries.remove(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_dentry(&self, name: &str) -> Option<Arc<Dentry_>> {
|
pub fn check_mountpoint(&self, name: &str) -> Result<()> {
|
||||||
self.inner.get(name).cloned()
|
if let Some(dentry) = self.dentries.get(name) {
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_dentry_with_checking_mountpoint(&self, name: &str) -> Result<Option<Arc<Dentry_>>> {
|
|
||||||
let dentry = self.find_dentry(name);
|
|
||||||
if let Some(dentry) = dentry.as_ref() {
|
|
||||||
if dentry.is_mountpoint() {
|
if dentry.is_mountpoint() {
|
||||||
return_errno_with_message!(Errno::EBUSY, "dentry is mountpint");
|
return_errno_with_message!(Errno::EBUSY, "dentry is mountpint");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_mountpoint_then_find(&self, name: &str) -> Result<Option<Arc<Dentry_>>> {
|
||||||
|
let dentry = if let Some(dentry) = self.dentries.get(name) {
|
||||||
|
if dentry.is_mountpoint() {
|
||||||
|
return_errno_with_message!(Errno::EBUSY, "dentry is mountpint");
|
||||||
|
}
|
||||||
|
Some(dentry.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
Ok(dentry)
|
Ok(dentry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -448,52 +454,50 @@ fn write_lock_children_on_two_dentries<'a>(
|
|||||||
|
|
||||||
impl Dentry {
|
impl Dentry {
|
||||||
/// Creates a new `Dentry` to represent the root directory of a file system.
|
/// Creates a new `Dentry` to represent the root directory of a file system.
|
||||||
pub fn new_fs_root(mount_node: Arc<MountNode>) -> Arc<Self> {
|
pub fn new_fs_root(mount_node: Arc<MountNode>) -> Self {
|
||||||
Self::new(mount_node.clone(), mount_node.root_dentry().clone())
|
let inner = mount_node.root_dentry().clone();
|
||||||
|
Self::new(mount_node, inner)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new `Dentry` to represent the child directory of a file system.
|
/// Creates a new `Dentry` to represent the child directory of a file system.
|
||||||
pub fn new_fs_child(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<Self>> {
|
pub fn new_fs_child(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Self> {
|
||||||
let new_child_dentry = self.inner.create(name, type_, mode)?;
|
let new_child_dentry = self.inner.create(name, type_, mode)?;
|
||||||
Ok(Self::new(self.mount_node.clone(), new_child_dentry.clone()))
|
Ok(Self::new(self.mount_node.clone(), new_child_dentry))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(mount_node: Arc<MountNode>, inner: Arc<Dentry_>) -> Arc<Self> {
|
fn new(mount_node: Arc<MountNode>, inner: Arc<Dentry_>) -> Self {
|
||||||
Arc::new_cyclic(|weak_self| Self {
|
Self { mount_node, inner }
|
||||||
mount_node,
|
|
||||||
inner,
|
|
||||||
this: weak_self.clone(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lookups the target `Dentry` given the `name`.
|
/// Lookups the target `Dentry` given the `name`.
|
||||||
pub fn lookup(&self, name: &str) -> Result<Arc<Self>> {
|
pub fn lookup(&self, name: &str) -> Result<Self> {
|
||||||
if self.inner.inode().type_() != InodeType::Dir {
|
if self.type_() != InodeType::Dir {
|
||||||
return_errno!(Errno::ENOTDIR);
|
return_errno!(Errno::ENOTDIR);
|
||||||
}
|
}
|
||||||
if !self.inner.inode().mode()?.is_executable() {
|
if !self.mode()?.is_executable() {
|
||||||
return_errno!(Errno::EACCES);
|
return_errno!(Errno::EACCES);
|
||||||
}
|
}
|
||||||
if name.len() > NAME_MAX {
|
if name.len() > NAME_MAX {
|
||||||
return_errno!(Errno::ENAMETOOLONG);
|
return_errno!(Errno::ENAMETOOLONG);
|
||||||
}
|
}
|
||||||
|
|
||||||
let dentry = match name {
|
let target_dentry = match name {
|
||||||
"." => self.this(),
|
"." => self.this(),
|
||||||
".." => self.effective_parent().unwrap_or_else(|| self.this()),
|
".." => self.effective_parent().unwrap_or_else(|| self.this()),
|
||||||
name => {
|
name => {
|
||||||
let children_inner = self.inner.lookup_via_cache(name);
|
let target_inner_opt = self.inner.lookup_via_cache(name);
|
||||||
match children_inner {
|
match target_inner_opt {
|
||||||
Some(inner) => Self::new(self.mount_node().clone(), inner.clone()),
|
Some(target_inner) => Self::new(self.mount_node.clone(), target_inner),
|
||||||
None => {
|
None => {
|
||||||
let fs_inner = self.inner.lookup_via_fs(name)?;
|
let target_inner = self.inner.lookup_via_fs(name)?;
|
||||||
Self::new(self.mount_node().clone(), fs_inner.clone())
|
Self::new(self.mount_node.clone(), target_inner)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let dentry = dentry.get_top_dentry();
|
|
||||||
Ok(dentry)
|
let target_dentry = target_dentry.get_top_dentry();
|
||||||
|
Ok(target_dentry)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the absolute path.
|
/// Gets the absolute path.
|
||||||
@ -535,8 +539,8 @@ impl Dentry {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let parent_inner = Self::new(
|
let parent_inner = Self::new(
|
||||||
self.mount_node.parent().unwrap().upgrade().unwrap().clone(),
|
self.mount_node.parent().unwrap().upgrade().unwrap(),
|
||||||
self.mount_node.mountpoint_dentry().unwrap().clone(),
|
self.mount_node.mountpoint_dentry().unwrap(),
|
||||||
);
|
);
|
||||||
parent_inner.effective_name()
|
parent_inner.effective_name()
|
||||||
}
|
}
|
||||||
@ -545,18 +549,18 @@ impl Dentry {
|
|||||||
///
|
///
|
||||||
/// If it is the root of a mount, it will go up to the mountpoint
|
/// If it is the root of a mount, it will go up to the mountpoint
|
||||||
/// to get the parent of the mountpoint recursively.
|
/// to get the parent of the mountpoint recursively.
|
||||||
fn effective_parent(&self) -> Option<Arc<Self>> {
|
fn effective_parent(&self) -> Option<Self> {
|
||||||
if !self.inner.is_root_of_mount() {
|
if !self.inner.is_root_of_mount() {
|
||||||
return Some(Self::new(
|
return Some(Self::new(
|
||||||
self.mount_node.clone(),
|
self.mount_node.clone(),
|
||||||
self.inner.parent().unwrap().clone(),
|
self.inner.parent().unwrap(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let parent = self.mount_node.parent()?;
|
let parent = self.mount_node.parent()?;
|
||||||
let mountpoint = self.mount_node.mountpoint_dentry()?;
|
let mountpoint = self.mount_node.mountpoint_dentry()?;
|
||||||
|
|
||||||
let parent_dentry = Self::new(parent.upgrade().unwrap(), mountpoint.clone());
|
let parent_dentry = Self::new(parent.upgrade().unwrap(), mountpoint);
|
||||||
parent_dentry.effective_parent()
|
parent_dentry.effective_parent()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -567,15 +571,17 @@ impl Dentry {
|
|||||||
/// For example, first `mount /dev/sda1 /mnt` and then `mount /dev/sda2 /mnt`.
|
/// For example, first `mount /dev/sda1 /mnt` and then `mount /dev/sda2 /mnt`.
|
||||||
/// After the second mount is completed, the content of the first mount will be overridden.
|
/// After the second mount is completed, the content of the first mount will be overridden.
|
||||||
/// We need to recursively obtain the top `Dentry`.
|
/// We need to recursively obtain the top `Dentry`.
|
||||||
fn get_top_dentry(&self) -> Arc<Self> {
|
fn get_top_dentry(self) -> Self {
|
||||||
if !self.inner.is_mountpoint() {
|
if !self.inner.is_mountpoint() {
|
||||||
return self.this();
|
return self;
|
||||||
}
|
}
|
||||||
match self.mount_node.get(self) {
|
|
||||||
|
match self.mount_node.get(&self) {
|
||||||
Some(child_mount) => {
|
Some(child_mount) => {
|
||||||
Self::new(child_mount.clone(), child_mount.root_dentry().clone()).get_top_dentry()
|
let inner = child_mount.root_dentry().clone();
|
||||||
|
Self::new(child_mount, inner).get_top_dentry()
|
||||||
}
|
}
|
||||||
None => self.this(),
|
None => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -594,14 +600,14 @@ impl Dentry {
|
|||||||
///
|
///
|
||||||
/// Returns the mounted child mount.
|
/// Returns the mounted child mount.
|
||||||
pub fn mount(&self, fs: Arc<dyn FileSystem>) -> Result<Arc<MountNode>> {
|
pub fn mount(&self, fs: Arc<dyn FileSystem>) -> Result<Arc<MountNode>> {
|
||||||
if self.inner.inode().type_() != InodeType::Dir {
|
if self.type_() != InodeType::Dir {
|
||||||
return_errno!(Errno::ENOTDIR);
|
return_errno!(Errno::ENOTDIR);
|
||||||
}
|
}
|
||||||
if self.effective_parent().is_none() {
|
if self.effective_parent().is_none() {
|
||||||
return_errno_with_message!(Errno::EINVAL, "can not mount on root");
|
return_errno_with_message!(Errno::EINVAL, "can not mount on root");
|
||||||
}
|
}
|
||||||
|
|
||||||
let child_mount = self.mount_node().mount(fs, &self.this())?;
|
let child_mount = self.mount_node.mount(fs, &self.this())?;
|
||||||
self.set_mountpoint(child_mount.clone());
|
self.set_mountpoint(child_mount.clone());
|
||||||
Ok(child_mount)
|
Ok(child_mount)
|
||||||
}
|
}
|
||||||
@ -614,12 +620,11 @@ impl Dentry {
|
|||||||
return_errno_with_message!(Errno::EINVAL, "not mounted");
|
return_errno_with_message!(Errno::EINVAL, "not mounted");
|
||||||
}
|
}
|
||||||
|
|
||||||
let mount_node = self.mount_node.clone();
|
let Some(mountpoint_dentry) = self.mount_node.mountpoint_dentry() else {
|
||||||
let Some(mountpoint_dentry) = mount_node.mountpoint_dentry() else {
|
|
||||||
return_errno_with_message!(Errno::EINVAL, "cannot umount root mount");
|
return_errno_with_message!(Errno::EINVAL, "cannot umount root mount");
|
||||||
};
|
};
|
||||||
|
|
||||||
let mountpoint_mount_node = mount_node.parent().unwrap().upgrade().unwrap();
|
let mountpoint_mount_node = self.mount_node.parent().unwrap().upgrade().unwrap();
|
||||||
let mountpoint = Self::new(mountpoint_mount_node.clone(), mountpoint_dentry.clone());
|
let mountpoint = Self::new(mountpoint_mount_node.clone(), mountpoint_dentry.clone());
|
||||||
|
|
||||||
let child_mount = mountpoint_mount_node.unmount(&mountpoint)?;
|
let child_mount = mountpoint_mount_node.unmount(&mountpoint)?;
|
||||||
@ -628,13 +633,13 @@ impl Dentry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a `Dentry` by making an inode of the `type_` with the `mode`.
|
/// Creates a `Dentry` by making an inode of the `type_` with the `mode`.
|
||||||
pub fn mknod(&self, name: &str, mode: InodeMode, type_: MknodType) -> Result<Arc<Self>> {
|
pub fn mknod(&self, name: &str, mode: InodeMode, type_: MknodType) -> Result<Self> {
|
||||||
let inner = self.inner.mknod(name, mode, type_)?;
|
let inner = self.inner.mknod(name, mode, type_)?;
|
||||||
Ok(Self::new(self.mount_node.clone(), inner.clone()))
|
Ok(Self::new(self.mount_node.clone(), inner))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Links a new name for the `Dentry`.
|
/// Links a new name for the `Dentry`.
|
||||||
pub fn link(&self, old: &Arc<Self>, name: &str) -> Result<()> {
|
pub fn link(&self, old: &Self, name: &str) -> Result<()> {
|
||||||
if !Arc::ptr_eq(&old.mount_node, &self.mount_node) {
|
if !Arc::ptr_eq(&old.mount_node, &self.mount_node) {
|
||||||
return_errno_with_message!(Errno::EXDEV, "cannot cross mount");
|
return_errno_with_message!(Errno::EXDEV, "cannot cross mount");
|
||||||
}
|
}
|
||||||
@ -652,7 +657,7 @@ impl Dentry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Renames a `Dentry` to the new `Dentry` by `rename()` the inner inode.
|
/// Renames a `Dentry` to the new `Dentry` by `rename()` the inner inode.
|
||||||
pub fn rename(&self, old_name: &str, new_dir: &Arc<Self>, new_name: &str) -> Result<()> {
|
pub fn rename(&self, old_name: &str, new_dir: &Self, new_name: &str) -> Result<()> {
|
||||||
if !Arc::ptr_eq(&self.mount_node, &new_dir.mount_node) {
|
if !Arc::ptr_eq(&self.mount_node, &new_dir.mount_node) {
|
||||||
return_errno_with_message!(Errno::EXDEV, "cannot cross mount");
|
return_errno_with_message!(Errno::EXDEV, "cannot cross mount");
|
||||||
}
|
}
|
||||||
@ -664,7 +669,7 @@ impl Dentry {
|
|||||||
/// If `recursive` is true, it will bind mount the whole mount tree
|
/// If `recursive` is true, it will bind mount the whole mount tree
|
||||||
/// to the destination `Dentry`. Otherwise, it will only bind mount
|
/// to the destination `Dentry`. Otherwise, it will only bind mount
|
||||||
/// the root mount node.
|
/// the root mount node.
|
||||||
pub fn bind_mount_to(&self, dst_dentry: &Arc<Self>, recursive: bool) -> Result<()> {
|
pub fn bind_mount_to(&self, dst_dentry: &Self, recursive: bool) -> Result<()> {
|
||||||
let src_mount = self
|
let src_mount = self
|
||||||
.mount_node
|
.mount_node
|
||||||
.clone_mount_node_tree(&self.inner, recursive);
|
.clone_mount_node_tree(&self.inner, recursive);
|
||||||
@ -672,8 +677,8 @@ impl Dentry {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn this(&self) -> Arc<Self> {
|
fn this(&self) -> Self {
|
||||||
self.this.upgrade().unwrap()
|
self.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the mount node of current `Dentry`.
|
/// Gets the mount node of current `Dentry`.
|
||||||
|
@ -69,7 +69,7 @@ impl MountNode {
|
|||||||
/// mountpoint. It is the fs's responsibility to ensure the data consistency.
|
/// mountpoint. It is the fs's responsibility to ensure the data consistency.
|
||||||
///
|
///
|
||||||
/// Return the mounted child mount.
|
/// Return the mounted child mount.
|
||||||
pub fn mount(&self, fs: Arc<dyn FileSystem>, mountpoint: &Arc<Dentry>) -> Result<Arc<Self>> {
|
pub fn mount(&self, fs: Arc<dyn FileSystem>, mountpoint: &Dentry) -> Result<Arc<Self>> {
|
||||||
if !Arc::ptr_eq(mountpoint.mount_node(), &self.this()) {
|
if !Arc::ptr_eq(mountpoint.mount_node(), &self.this()) {
|
||||||
return_errno_with_message!(Errno::EINVAL, "mountpoint not belongs to this");
|
return_errno_with_message!(Errno::EINVAL, "mountpoint not belongs to this");
|
||||||
}
|
}
|
||||||
@ -129,13 +129,13 @@ impl MountNode {
|
|||||||
) -> Arc<Self> {
|
) -> Arc<Self> {
|
||||||
let new_root_mount = self.clone_mount_node(root_dentry);
|
let new_root_mount = self.clone_mount_node(root_dentry);
|
||||||
if !recursive {
|
if !recursive {
|
||||||
return new_root_mount.clone();
|
return new_root_mount;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut stack = vec![self.this()];
|
let mut stack = vec![self.this()];
|
||||||
let mut new_stack = vec![new_root_mount.clone()];
|
let mut new_stack = vec![new_root_mount.clone()];
|
||||||
|
|
||||||
while let Some(old_mount) = stack.pop() {
|
while let Some(old_mount) = stack.pop() {
|
||||||
let new_parent_mount = new_stack.pop().unwrap().clone();
|
let new_parent_mount = new_stack.pop().unwrap();
|
||||||
let old_children = old_mount.children.read();
|
let old_children = old_mount.children.read();
|
||||||
for old_child_mount in old_children.values() {
|
for old_child_mount in old_children.values() {
|
||||||
let mountpoint_dentry = old_child_mount.mountpoint_dentry().unwrap();
|
let mountpoint_dentry = old_child_mount.mountpoint_dentry().unwrap();
|
||||||
@ -153,10 +153,11 @@ impl MountNode {
|
|||||||
new_child_mount
|
new_child_mount
|
||||||
.set_mountpoint_dentry(&old_child_mount.mountpoint_dentry().unwrap());
|
.set_mountpoint_dentry(&old_child_mount.mountpoint_dentry().unwrap());
|
||||||
stack.push(old_child_mount.clone());
|
stack.push(old_child_mount.clone());
|
||||||
new_stack.push(new_child_mount.clone());
|
new_stack.push(new_child_mount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
new_root_mount.clone()
|
|
||||||
|
new_root_mount
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Detaches the mount node from the parent mount node.
|
/// Detaches the mount node from the parent mount node.
|
||||||
@ -171,7 +172,7 @@ impl MountNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Attaches the mount node to the mountpoint.
|
/// Attaches the mount node to the mountpoint.
|
||||||
fn attach_mount_node(&self, mountpoint: &Arc<Dentry>) {
|
fn attach_mount_node(&self, mountpoint: &Dentry) {
|
||||||
let key = mountpoint.key();
|
let key = mountpoint.key();
|
||||||
mountpoint
|
mountpoint
|
||||||
.mount_node()
|
.mount_node()
|
||||||
@ -183,7 +184,7 @@ impl MountNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Grafts 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<()> {
|
pub fn graft_mount_node_tree(&self, mountpoint: &Dentry) -> Result<()> {
|
||||||
if mountpoint.type_() != InodeType::Dir {
|
if mountpoint.type_() != InodeType::Dir {
|
||||||
return_errno!(Errno::ENOTDIR);
|
return_errno!(Errno::ENOTDIR);
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ impl TryFrom<SocketAddr> for UnixSocketAddr {
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(super) enum UnixSocketAddrBound {
|
pub(super) enum UnixSocketAddrBound {
|
||||||
Path(Arc<str>, Arc<Dentry>),
|
Path(Arc<str>, Dentry),
|
||||||
Abstract(Arc<AbstractHandle>),
|
Abstract(Arc<AbstractHandle>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ use crate::{
|
|||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn lookup_socket_file(path: &str) -> Result<Arc<Dentry>> {
|
pub fn lookup_socket_file(path: &str) -> Result<Dentry> {
|
||||||
let dentry = {
|
let dentry = {
|
||||||
let current = current!();
|
let current = current!();
|
||||||
let fs = current.fs().read();
|
let fs = current.fs().read();
|
||||||
@ -31,7 +31,7 @@ pub fn lookup_socket_file(path: &str) -> Result<Arc<Dentry>> {
|
|||||||
Ok(dentry)
|
Ok(dentry)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_socket_file(path: &str) -> Result<Arc<Dentry>> {
|
pub fn create_socket_file(path: &str) -> Result<Dentry> {
|
||||||
let (parent_pathname, file_name) = split_path(path);
|
let (parent_pathname, file_name) = split_path(path);
|
||||||
|
|
||||||
let parent = {
|
let parent = {
|
||||||
|
@ -34,7 +34,7 @@ use crate::{
|
|||||||
pub fn load_elf_to_vm(
|
pub fn load_elf_to_vm(
|
||||||
process_vm: &ProcessVm,
|
process_vm: &ProcessVm,
|
||||||
file_header: &[u8],
|
file_header: &[u8],
|
||||||
elf_file: Arc<Dentry>,
|
elf_file: Dentry,
|
||||||
fs_resolver: &FsResolver,
|
fs_resolver: &FsResolver,
|
||||||
argv: Vec<CString>,
|
argv: Vec<CString>,
|
||||||
envp: Vec<CString>,
|
envp: Vec<CString>,
|
||||||
@ -85,7 +85,7 @@ fn lookup_and_parse_ldso(
|
|||||||
elf: &Elf,
|
elf: &Elf,
|
||||||
file_header: &[u8],
|
file_header: &[u8],
|
||||||
fs_resolver: &FsResolver,
|
fs_resolver: &FsResolver,
|
||||||
) -> Result<Option<(Arc<Dentry>, Elf)>> {
|
) -> Result<Option<(Dentry, Elf)>> {
|
||||||
let ldso_file = {
|
let ldso_file = {
|
||||||
let Some(ldso_path) = elf.ldso_path(file_header)? else {
|
let Some(ldso_path) = elf.ldso_path(file_header)? else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
@ -112,7 +112,7 @@ fn load_ldso(root_vmar: &Vmar<Full>, ldso_file: &Dentry, ldso_elf: &Elf) -> Resu
|
|||||||
|
|
||||||
fn init_and_map_vmos(
|
fn init_and_map_vmos(
|
||||||
process_vm: &ProcessVm,
|
process_vm: &ProcessVm,
|
||||||
ldso: Option<(Arc<Dentry>, Elf)>,
|
ldso: Option<(Dentry, Elf)>,
|
||||||
parsed_elf: &Elf,
|
parsed_elf: &Elf,
|
||||||
elf_file: &Dentry,
|
elf_file: &Dentry,
|
||||||
) -> Result<(Vaddr, AuxVec)> {
|
) -> Result<(Vaddr, AuxVec)> {
|
||||||
|
@ -25,7 +25,7 @@ use crate::{
|
|||||||
/// because the interpreter is usually an elf binary(e.g., /bin/bash)
|
/// because the interpreter is usually an elf binary(e.g., /bin/bash)
|
||||||
pub fn load_program_to_vm(
|
pub fn load_program_to_vm(
|
||||||
process_vm: &ProcessVm,
|
process_vm: &ProcessVm,
|
||||||
elf_file: Arc<Dentry>,
|
elf_file: Dentry,
|
||||||
argv: Vec<CString>,
|
argv: Vec<CString>,
|
||||||
envp: Vec<CString>,
|
envp: Vec<CString>,
|
||||||
fs_resolver: &FsResolver,
|
fs_resolver: &FsResolver,
|
||||||
@ -68,7 +68,7 @@ pub fn load_program_to_vm(
|
|||||||
Ok((abs_path, elf_load_info))
|
Ok((abs_path, elf_load_info))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_executable_file(dentry: &Arc<Dentry>) -> Result<()> {
|
pub fn check_executable_file(dentry: &Dentry) -> Result<()> {
|
||||||
if dentry.type_().is_directory() {
|
if dentry.type_().is_directory() {
|
||||||
return_errno_with_message!(Errno::EISDIR, "the file is a directory");
|
return_errno_with_message!(Errno::EISDIR, "the file is a directory");
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ fn lookup_executable_file(
|
|||||||
filename: String,
|
filename: String,
|
||||||
flags: OpenFlags,
|
flags: OpenFlags,
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
) -> Result<Arc<Dentry>> {
|
) -> Result<Dentry> {
|
||||||
let fs_resolver = ctx.process.fs().read();
|
let fs_resolver = ctx.process.fs().read();
|
||||||
let dentry = if flags.contains(OpenFlags::AT_EMPTY_PATH) && filename.is_empty() {
|
let dentry = if flags.contains(OpenFlags::AT_EMPTY_PATH) && filename.is_empty() {
|
||||||
fs_resolver.lookup_from_fd(dfd)
|
fs_resolver.lookup_from_fd(dfd)
|
||||||
@ -79,7 +79,7 @@ fn lookup_executable_file(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn do_execve(
|
fn do_execve(
|
||||||
elf_file: Arc<Dentry>,
|
elf_file: Dentry,
|
||||||
argv_ptr_ptr: Vaddr,
|
argv_ptr_ptr: Vaddr,
|
||||||
envp_ptr_ptr: Vaddr,
|
envp_ptr_ptr: Vaddr,
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
@ -193,7 +193,7 @@ fn read_cstring_vec(
|
|||||||
fn set_uid_from_elf(
|
fn set_uid_from_elf(
|
||||||
current: &Process,
|
current: &Process,
|
||||||
credentials: &Credentials<WriteOp>,
|
credentials: &Credentials<WriteOp>,
|
||||||
elf_file: &Arc<Dentry>,
|
elf_file: &Dentry,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if elf_file.mode()?.has_set_uid() {
|
if elf_file.mode()?.has_set_uid() {
|
||||||
let uid = elf_file.owner()?;
|
let uid = elf_file.owner()?;
|
||||||
@ -211,7 +211,7 @@ fn set_uid_from_elf(
|
|||||||
fn set_gid_from_elf(
|
fn set_gid_from_elf(
|
||||||
current: &Process,
|
current: &Process,
|
||||||
credentials: &Credentials<WriteOp>,
|
credentials: &Credentials<WriteOp>,
|
||||||
elf_file: &Arc<Dentry>,
|
elf_file: &Dentry,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if elf_file.mode()?.has_set_gid() {
|
if elf_file.mode()?.has_set_gid() {
|
||||||
let gid = elf_file.group()?;
|
let gid = elf_file.group()?;
|
||||||
|
@ -83,7 +83,7 @@ fn do_remount() -> Result<()> {
|
|||||||
/// Such as use user command `mount --rbind src dst`.
|
/// Such as use user command `mount --rbind src dst`.
|
||||||
fn do_bind_mount(
|
fn do_bind_mount(
|
||||||
src_name: CString,
|
src_name: CString,
|
||||||
dst_dentry: Arc<Dentry>,
|
dst_dentry: Dentry,
|
||||||
recursive: bool,
|
recursive: bool,
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
@ -109,7 +109,7 @@ fn do_change_type() -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Move a mount from src location to dst location.
|
/// Move a mount from src location to dst location.
|
||||||
fn do_move_mount_old(src_name: CString, dst_dentry: Arc<Dentry>, ctx: &Context) -> Result<()> {
|
fn do_move_mount_old(src_name: CString, dst_dentry: Dentry, ctx: &Context) -> Result<()> {
|
||||||
let src_dentry = {
|
let src_dentry = {
|
||||||
let src_name = src_name.to_string_lossy();
|
let src_name = src_name.to_string_lossy();
|
||||||
if src_name.is_empty() {
|
if src_name.is_empty() {
|
||||||
@ -135,7 +135,7 @@ fn do_move_mount_old(src_name: CString, dst_dentry: Arc<Dentry>, ctx: &Context)
|
|||||||
fn do_new_mount(
|
fn do_new_mount(
|
||||||
devname: CString,
|
devname: CString,
|
||||||
fs_type: Vaddr,
|
fs_type: Vaddr,
|
||||||
target_dentry: Arc<Dentry>,
|
target_dentry: Dentry,
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if target_dentry.type_() != InodeType::Dir {
|
if target_dentry.type_() != InodeType::Dir {
|
||||||
|
@ -109,7 +109,7 @@ struct Utimbuf {
|
|||||||
modtime: i64,
|
modtime: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vfs_utimes(dentry: &Arc<Dentry>, times: Option<TimeSpecPair>) -> Result<SyscallReturn> {
|
fn vfs_utimes(dentry: &Dentry, times: Option<TimeSpecPair>) -> Result<SyscallReturn> {
|
||||||
let (atime, mtime, ctime) = match times {
|
let (atime, mtime, ctime) = match times {
|
||||||
Some(times) => {
|
Some(times) => {
|
||||||
if !times.atime.is_valid() || !times.mtime.is_valid() {
|
if !times.atime.is_valid() || !times.mtime.is_valid() {
|
||||||
|
Reference in New Issue
Block a user