mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-18 03:56:42 +00:00
Add mount and umount fs support
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
9cb759efa2
commit
1bfd6ea2f8
@ -17,7 +17,7 @@ all: build
|
|||||||
$(INITRAMFS):
|
$(INITRAMFS):
|
||||||
@rm -rf $@ && mkdir -p $@
|
@rm -rf $@ && mkdir -p $@
|
||||||
@# Mkdir necessary folders
|
@# 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
|
@# Install busybox
|
||||||
@/bin/busybox --install -s $@/bin
|
@/bin/busybox --install -s $@/bin
|
||||||
@cp /usr/bin/busybox $@/usr/bin
|
@cp /usr/bin/busybox $@/usr/bin
|
||||||
|
@ -3,29 +3,14 @@ use alloc::str;
|
|||||||
|
|
||||||
use super::file_table::FileDescripter;
|
use super::file_table::FileDescripter;
|
||||||
use super::inode_handle::InodeHandle;
|
use super::inode_handle::InodeHandle;
|
||||||
use super::procfs::ProcFS;
|
|
||||||
use super::ramfs::RamFS;
|
use super::ramfs::RamFS;
|
||||||
use super::utils::{
|
use super::utils::{
|
||||||
AccessMode, CreationFlags, Dentry, FileSystem, InodeMode, InodeType, StatusFlags, Vnode,
|
AccessMode, CreationFlags, Dentry, InodeMode, InodeType, MountNode, StatusFlags, PATH_MAX,
|
||||||
PATH_MAX, SYMLINKS_MAX,
|
SYMLINKS_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref ROOT_FS: Arc<dyn FileSystem> = RamFS::new(true);
|
static ref ROOT_MOUNT: Arc<MountNode> = MountNode::new_root(RamFS::new(true)).unwrap();
|
||||||
static ref ROOT_DENTRY: Arc<Dentry> = {
|
|
||||||
let vnode = Vnode::new(ROOT_FS.root_inode()).unwrap();
|
|
||||||
Dentry::new_root(vnode)
|
|
||||||
};
|
|
||||||
static ref PROC_FS: Arc<dyn FileSystem> = ProcFS::new();
|
|
||||||
static ref PROC_DENTRY: Arc<Dentry> = {
|
|
||||||
let vnode = Vnode::new(PROC_FS.root_inode()).unwrap();
|
|
||||||
Dentry::new_root(vnode)
|
|
||||||
};
|
|
||||||
static ref DEV_FS: Arc<dyn FileSystem> = RamFS::new(false);
|
|
||||||
static ref DEV_DENTRY: Arc<Dentry> = {
|
|
||||||
let vnode = Vnode::new(DEV_FS.root_inode()).unwrap();
|
|
||||||
Dentry::new_root(vnode)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FsResolver {
|
pub struct FsResolver {
|
||||||
@ -45,8 +30,8 @@ impl Clone for FsResolver {
|
|||||||
impl FsResolver {
|
impl FsResolver {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
root: ROOT_DENTRY.clone(),
|
root: ROOT_MOUNT.root_dentry().clone(),
|
||||||
cwd: 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<Arc<Dentry>> {
|
fn lookup_inner(&self, path: &FsPath, follow_tail_link: bool) -> Result<Arc<Dentry>> {
|
||||||
let dentry = match path.inner {
|
let dentry = match path.inner {
|
||||||
FsPathInner::Absolute(path) => {
|
FsPathInner::Absolute(path) => {
|
||||||
// TODO: Mount procfs at "/proc" if mount feature is ready
|
self.lookup_from_parent(&self.root, path.trim_start_matches('/'), follow_tail_link)?
|
||||||
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,
|
|
||||||
)?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
FsPathInner::CwdRelative(path) => {
|
FsPathInner::CwdRelative(path) => {
|
||||||
self.lookup_from_parent(&self.cwd, path, follow_tail_link)?
|
self.lookup_from_parent(&self.cwd, path, follow_tail_link)?
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
use super::fs_resolver::{FsPath, FsResolver};
|
|
||||||
use super::utils::{InodeMode, InodeType};
|
|
||||||
use crate::prelude::*;
|
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 cpio_decoder::{CpioDecoder, FileType};
|
||||||
use lending_iterator::LendingIterator;
|
use lending_iterator::LendingIterator;
|
||||||
use libflate::gzip::Decoder as GZipDecoder;
|
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");
|
println!("[kernel] initramfs is ready");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -2,9 +2,10 @@ use crate::fs::device::Device;
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
|
use core::sync::atomic::{AtomicU32, Ordering};
|
||||||
use core::time::Duration;
|
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! {
|
lazy_static! {
|
||||||
static ref DCACHE: Mutex<BTreeMap<DentryKey, Arc<Dentry>>> = Mutex::new(BTreeMap::new());
|
static ref DCACHE: Mutex<BTreeMap<DentryKey, Arc<Dentry>>> = Mutex::new(BTreeMap::new());
|
||||||
@ -13,60 +14,156 @@ lazy_static! {
|
|||||||
/// The dentry cache to accelerate path lookup
|
/// The dentry cache to accelerate path lookup
|
||||||
pub struct Dentry {
|
pub struct Dentry {
|
||||||
vnode: Vnode,
|
vnode: Vnode,
|
||||||
name_and_parent: RwLock<(String, Option<Arc<Dentry>>)>,
|
name_and_parent: RwLock<Option<(String, Arc<Dentry>)>>,
|
||||||
this: Weak<Dentry>,
|
this: Weak<Dentry>,
|
||||||
children: Mutex<Children>,
|
children: Mutex<Children>,
|
||||||
|
mount_node: Weak<MountNode>,
|
||||||
|
flags: AtomicU32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dentry {
|
impl Dentry {
|
||||||
/// Create a new dentry cache with root inode
|
/// Create a new root dentry with the giving vnode and mount node.
|
||||||
pub fn new_root(root_vnode: Vnode) -> Arc<Self> {
|
///
|
||||||
let root = Self::new("/", None, root_vnode);
|
/// 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<MountNode>) -> Arc<Self> {
|
||||||
|
let root = Self::new(vnode, DentryOptions::Root(mount));
|
||||||
DCACHE.lock().insert(root.key(), root.clone());
|
DCACHE.lock().insert(root.key(), root.clone());
|
||||||
root
|
root
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal constructor
|
/// Internal constructor.
|
||||||
fn new(name: &str, parent: Option<Arc<Dentry>>, vnode: Vnode) -> Arc<Self> {
|
fn new(vnode: Vnode, options: DentryOptions) -> Arc<Self> {
|
||||||
Arc::new_cyclic(|weak_self| Self {
|
Arc::new_cyclic(|weak_self| Self {
|
||||||
vnode,
|
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(),
|
this: weak_self.clone(),
|
||||||
children: Mutex::new(Children::new()),
|
children: Mutex::new(Children::new()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the name of Dentry.
|
/// Get the overlaid dentry of self.
|
||||||
pub fn name(&self) -> String {
|
///
|
||||||
self.name_and_parent.read().0.clone()
|
/// It will jump into the child mount if it is a mountpoint.
|
||||||
|
fn overlaid_dentry(&self) -> Arc<Self> {
|
||||||
|
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.
|
/// Returns None if it is root dentry.
|
||||||
pub fn parent(&self) -> Option<Arc<Dentry>> {
|
fn parent(&self) -> Option<Arc<Self>> {
|
||||||
self.name_and_parent.read().1.clone()
|
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<Arc<Dentry>>) {
|
/// 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<Arc<Self>> {
|
||||||
|
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<Self>) {
|
||||||
let mut name_and_parent = self.name_and_parent.write();
|
let mut name_and_parent = self.name_and_parent.write();
|
||||||
name_and_parent.0 = String::from(name);
|
*name_and_parent = Some((String::from(name), parent));
|
||||||
name_and_parent.1 = parent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn this(&self) -> Arc<Dentry> {
|
/// Get the arc reference to self.
|
||||||
|
fn this(&self) -> Arc<Self> {
|
||||||
self.this.upgrade().unwrap()
|
self.this.upgrade().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn key(&self) -> DentryKey {
|
/// Get the DentryKey.
|
||||||
let parent = self.parent().unwrap_or(self.this());
|
pub fn key(&self) -> DentryKey {
|
||||||
DentryKey::new(&self.name_and_parent.read().0, &parent)
|
DentryKey::new(&self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the vnode.
|
||||||
pub fn vnode(&self) -> &Vnode {
|
pub fn vnode(&self) -> &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<MountNode> {
|
||||||
|
self.mount_node.upgrade().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a dentry by making inode.
|
/// Create a dentry by making inode.
|
||||||
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.vnode.inode_type() != InodeType::Dir {
|
if self.vnode.inode_type() != InodeType::Dir {
|
||||||
@ -79,7 +176,10 @@ impl Dentry {
|
|||||||
|
|
||||||
let child = {
|
let child = {
|
||||||
let vnode = self.vnode.create(name, type_, mode)?;
|
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);
|
children.insert_dentry(&dentry);
|
||||||
dentry
|
dentry
|
||||||
};
|
};
|
||||||
@ -98,7 +198,10 @@ impl Dentry {
|
|||||||
|
|
||||||
let child = {
|
let child = {
|
||||||
let vnode = self.vnode.mknod(name, mode, device)?;
|
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);
|
children.insert_dentry(&dentry);
|
||||||
dentry
|
dentry
|
||||||
};
|
};
|
||||||
@ -119,14 +222,17 @@ impl Dentry {
|
|||||||
|
|
||||||
let dentry = match name {
|
let dentry = match name {
|
||||||
"." => self.this(),
|
"." => self.this(),
|
||||||
".." => self.parent().unwrap_or(self.this()),
|
".." => self.effective_parent().unwrap_or(self.this()),
|
||||||
name => {
|
name => {
|
||||||
let mut children = self.children.lock();
|
let mut children = self.children.lock();
|
||||||
match children.find_dentry(name) {
|
match children.find_dentry(name) {
|
||||||
Some(dentry) => dentry.clone(),
|
Some(dentry) => dentry.overlaid_dentry(),
|
||||||
None => {
|
None => {
|
||||||
let vnode = self.vnode.lookup(name)?;
|
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);
|
children.insert_dentry(&dentry);
|
||||||
dentry
|
dentry
|
||||||
}
|
}
|
||||||
@ -145,9 +251,15 @@ impl Dentry {
|
|||||||
if children.find_dentry(name).is_some() {
|
if children.find_dentry(name).is_some() {
|
||||||
return_errno!(Errno::EEXIST);
|
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();
|
let old_vnode = old.vnode();
|
||||||
self.vnode.link(old_vnode, name)?;
|
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);
|
children.insert_dentry(&dentry);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -158,6 +270,7 @@ impl Dentry {
|
|||||||
return_errno!(Errno::ENOTDIR);
|
return_errno!(Errno::ENOTDIR);
|
||||||
}
|
}
|
||||||
let mut children = self.children.lock();
|
let mut children = self.children.lock();
|
||||||
|
let _ = children.find_dentry_with_checking_mountpoint(name)?;
|
||||||
self.vnode.unlink(name)?;
|
self.vnode.unlink(name)?;
|
||||||
children.delete_dentry(name);
|
children.delete_dentry(name);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -169,6 +282,7 @@ impl Dentry {
|
|||||||
return_errno!(Errno::ENOTDIR);
|
return_errno!(Errno::ENOTDIR);
|
||||||
}
|
}
|
||||||
let mut children = self.children.lock();
|
let mut children = self.children.lock();
|
||||||
|
let _ = children.find_dentry_with_checking_mountpoint(name)?;
|
||||||
self.vnode.rmdir(name)?;
|
self.vnode.rmdir(name)?;
|
||||||
children.delete_dentry(name);
|
children.delete_dentry(name);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -206,11 +320,13 @@ impl Dentry {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let mut children = self.children.lock();
|
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)?;
|
self.vnode.rename(old_name, &self.vnode, new_name)?;
|
||||||
match children.find_dentry(old_name) {
|
match old_dentry.as_ref() {
|
||||||
Some(dentry) => {
|
Some(dentry) => {
|
||||||
children.delete_dentry(old_name);
|
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);
|
children.insert_dentry(&dentry);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@ -219,13 +335,18 @@ impl Dentry {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Self and new_dir are different Dentry
|
// 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) =
|
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 _ = new_dir_children.find_dentry_with_checking_mountpoint(new_name)?;
|
||||||
self.vnode.rename(old_name, &new_dir.vnode, 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) => {
|
Some(dentry) => {
|
||||||
self_children.delete_dentry(old_name);
|
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);
|
new_dir_children.insert_dentry(&dentry);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@ -236,6 +357,44 @@ impl Dentry {
|
|||||||
Ok(())
|
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<dyn FileSystem>) -> Result<Arc<MountNode>> {
|
||||||
|
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<Arc<MountNode>> {
|
||||||
|
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
|
/// Get the filesystem the inode belongs to
|
||||||
pub fn fs(&self) -> Arc<dyn FileSystem> {
|
pub fn fs(&self) -> Arc<dyn FileSystem> {
|
||||||
self.vnode.fs()
|
self.vnode.fs()
|
||||||
@ -287,16 +446,18 @@ impl Dentry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the absolute path.
|
/// Get the absolute path.
|
||||||
|
///
|
||||||
|
/// It will resolve the mountpoint automatically.
|
||||||
pub fn abs_path(&self) -> String {
|
pub fn abs_path(&self) -> String {
|
||||||
let mut path = self.name();
|
let mut path = self.effective_name();
|
||||||
let mut dentry = self.this();
|
let mut dentry = self.this();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match dentry.parent() {
|
match dentry.effective_parent() {
|
||||||
None => break,
|
None => break,
|
||||||
Some(parent_dentry) => {
|
Some(parent_dentry) => {
|
||||||
path = {
|
path = {
|
||||||
let parent_name = parent_dentry.name();
|
let parent_name = parent_dentry.effective_name();
|
||||||
if parent_name != "/" {
|
if parent_name != "/" {
|
||||||
parent_name + "/" + &path
|
parent_name + "/" + &path
|
||||||
} else {
|
} 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<MountNode>),
|
||||||
|
Leaf((String, Arc<Dentry>)),
|
||||||
|
}
|
||||||
|
|
||||||
struct Children {
|
struct Children {
|
||||||
inner: BTreeMap<String, Weak<Dentry>>,
|
inner: BTreeMap<String, Weak<Dentry>>,
|
||||||
}
|
}
|
||||||
@ -348,20 +544,18 @@ impl Children {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Hash, PartialOrd, Ord, Eq, PartialEq)]
|
pub fn find_dentry_with_checking_mountpoint(
|
||||||
struct DentryKey {
|
&mut self,
|
||||||
name: String,
|
name: &str,
|
||||||
parent_ptr: usize,
|
) -> Result<Option<Arc<Dentry>>> {
|
||||||
}
|
let dentry = self.find_dentry(name);
|
||||||
|
if let Some(dentry) = dentry.as_ref() {
|
||||||
impl DentryKey {
|
if dentry.is_mountpoint() {
|
||||||
pub fn new(name: &str, parent: &Arc<Dentry>) -> Self {
|
return_errno_with_message!(Errno::EBUSY, "dentry is mountpint");
|
||||||
Self {
|
}
|
||||||
name: String::from(name),
|
|
||||||
parent_ptr: Arc::as_ptr(parent) as usize,
|
|
||||||
}
|
}
|
||||||
|
Ok(dentry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,7 +3,7 @@
|
|||||||
pub use access_mode::AccessMode;
|
pub use access_mode::AccessMode;
|
||||||
pub use channel::{Channel, Consumer, Producer};
|
pub use channel::{Channel, Consumer, Producer};
|
||||||
pub use creation_flags::CreationFlags;
|
pub use creation_flags::CreationFlags;
|
||||||
pub use dentry_cache::Dentry;
|
pub use dentry::{Dentry, DentryKey};
|
||||||
pub use dirent_visitor::DirentVisitor;
|
pub use dirent_visitor::DirentVisitor;
|
||||||
pub use direntry_vec::DirEntryVecExt;
|
pub use direntry_vec::DirEntryVecExt;
|
||||||
pub use file_creation_mask::FileCreationMask;
|
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 inode::{Inode, InodeMode, InodeType, Metadata};
|
||||||
pub use io_events::IoEvents;
|
pub use io_events::IoEvents;
|
||||||
pub use ioctl::IoctlCmd;
|
pub use ioctl::IoctlCmd;
|
||||||
|
pub use mount::MountNode;
|
||||||
pub use page_cache::PageCache;
|
pub use page_cache::PageCache;
|
||||||
pub use poll::{Pollee, Poller};
|
pub use poll::{Pollee, Poller};
|
||||||
pub use status_flags::StatusFlags;
|
pub use status_flags::StatusFlags;
|
||||||
@ -19,7 +20,7 @@ pub use vnode::{Vnode, VnodeWriter};
|
|||||||
mod access_mode;
|
mod access_mode;
|
||||||
mod channel;
|
mod channel;
|
||||||
mod creation_flags;
|
mod creation_flags;
|
||||||
mod dentry_cache;
|
mod dentry;
|
||||||
mod dirent_visitor;
|
mod dirent_visitor;
|
||||||
mod direntry_vec;
|
mod direntry_vec;
|
||||||
mod file_creation_mask;
|
mod file_creation_mask;
|
||||||
@ -27,6 +28,7 @@ mod fs;
|
|||||||
mod inode;
|
mod inode;
|
||||||
mod io_events;
|
mod io_events;
|
||||||
mod ioctl;
|
mod ioctl;
|
||||||
|
mod mount;
|
||||||
mod page_cache;
|
mod page_cache;
|
||||||
mod poll;
|
mod poll;
|
||||||
mod status_flags;
|
mod status_flags;
|
||||||
|
121
services/libs/jinux-std/src/fs/utils/mount.rs
Normal file
121
services/libs/jinux-std/src/fs/utils/mount.rs
Normal file
@ -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<Dentry>,
|
||||||
|
/// 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<Arc<Dentry>>,
|
||||||
|
/// The associated FS.
|
||||||
|
fs: Arc<dyn FileSystem>,
|
||||||
|
/// Child mount nodes which are mounted on one dentry of self.
|
||||||
|
children: Mutex<BTreeMap<DentryKey, Arc<Self>>>,
|
||||||
|
/// Reference to self.
|
||||||
|
this: Weak<Self>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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<dyn FileSystem>) -> Result<Arc<Self>> {
|
||||||
|
Self::new(fs, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The internal constructor.
|
||||||
|
///
|
||||||
|
/// Root mount node has no mountpoint which other mount nodes must have mountpoint.
|
||||||
|
fn new(fs: Arc<dyn FileSystem>, mountpoint: Option<Arc<Dentry>>) -> Result<Arc<Self>> {
|
||||||
|
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<dyn FileSystem>, mountpoint: &Arc<Dentry>) -> Result<Arc<Self>> {
|
||||||
|
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<Arc<Self>> {
|
||||||
|
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<Arc<Self>> {
|
||||||
|
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<Dentry> {
|
||||||
|
&self.root_dentry
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try to get the mountpoint dentry of this mount node.
|
||||||
|
pub fn mountpoint_dentry(&self) -> Option<&Arc<Dentry>> {
|
||||||
|
self.mountpoint_dentry.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try to get the parent mount node.
|
||||||
|
pub fn parent(&self) -> Option<Arc<Self>> {
|
||||||
|
self.mountpoint_dentry
|
||||||
|
.as_ref()
|
||||||
|
.map(|dentry| dentry.mount_node())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get strong reference to self.
|
||||||
|
fn this(&self) -> Arc<Self> {
|
||||||
|
self.this.upgrade().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the associated fs.
|
||||||
|
pub fn fs(&self) -> &Arc<dyn FileSystem> {
|
||||||
|
&self.fs
|
||||||
|
}
|
||||||
|
}
|
@ -28,14 +28,15 @@ pub fn sys_renameat(
|
|||||||
let current = current!();
|
let current = current!();
|
||||||
let fs = current.fs().read();
|
let fs = current.fs().read();
|
||||||
|
|
||||||
let old_dentry = {
|
let (old_dir_dentry, old_name) = {
|
||||||
let old_pathname = old_pathname.to_string_lossy();
|
let old_pathname = old_pathname.to_string_lossy();
|
||||||
if old_pathname.is_empty() {
|
if old_pathname.is_empty() {
|
||||||
return_errno_with_message!(Errno::ENOENT, "oldpath is empty");
|
return_errno_with_message!(Errno::ENOENT, "oldpath is empty");
|
||||||
}
|
}
|
||||||
let old_fs_path = FsPath::new(old_dirfd, old_pathname.as_ref())?;
|
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_dir_dentry, new_name) = {
|
||||||
let new_pathname = new_pathname.to_string_lossy();
|
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_name, &new_dir_dentry, &new_name)?;
|
||||||
old_dir_dentry.rename(&old_dentry.name(), &new_dir_dentry, &new_name)?;
|
|
||||||
|
|
||||||
Ok(SyscallReturn::Return(0))
|
Ok(SyscallReturn::Return(0))
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user