vfs: check mountpoint before instantiating a new filesystem

This commit is contained in:
Mark Poliakov 2025-01-02 21:29:02 +02:00
parent df0a48ca42
commit 595504b371
5 changed files with 33 additions and 24 deletions

View File

@ -91,7 +91,7 @@ impl Filesystem for Ext2Fs {
}
impl Ext2Fs {
pub async fn create<'a, I: Iterator<Item = FilesystemMountOption<'a>>>(
pub async fn create<'a, I: IntoIterator<Item = FilesystemMountOption<'a>>>(
device: Arc<dyn BlockDevice>,
options: I,
) -> Result<NodeRef, Error> {

View File

@ -158,7 +158,11 @@ impl IoContext {
/// Makes a directory at given path become a "mountpoint" for the given filesystem root.
/// When accessed, the target directory will return contents of the filesystem root instead of
/// its own. Both the `target` path and `fs_root` Node must be directories.
pub fn mount<P: AsRef<Path>>(&mut self, target: P, fs_root: NodeRef) -> Result<(), Error> {
pub fn mount<P: AsRef<Path>, F: FnOnce() -> Result<NodeRef, Error>>(
&mut self,
target: P,
create_fs: F,
) -> Result<(), Error> {
if !self.uid.is_root() {
return Err(Error::PermissionDenied);
}
@ -169,7 +173,7 @@ impl IoContext {
}
let target_node = self._find(self.root.clone(), target.trim_start_separators(), true)?;
target_node.set_mountpoint_target(fs_root)
target_node.mount(create_fs)
}
/// Locates a [crate::Node] at given path and opens it with requested access options. If no

View File

@ -410,25 +410,24 @@ impl Node {
}
}
pub(crate) fn set_mountpoint_target(self: &NodeRef, target: NodeRef) -> Result<(), Error> {
pub(crate) fn mount<F: FnOnce() -> Result<NodeRef, Error>>(
self: &NodeRef,
create_fs: F,
) -> Result<(), Error> {
let directory = self.as_directory()?;
let mut mountpoint = directory.mountpoint.lock();
let mut target_parent_lock = target.parent.lock();
if mountpoint.is_some() {
// TODO Busy
todo!();
}
if target_parent_lock.is_some() {
// TODO mount a filesystem more than once?
return Err(Error::AlreadyExists);
}
if !target.is_directory() {
return Err(Error::NotADirectory);
}
mountpoint.replace(target.clone());
target_parent_lock.replace(self.clone());
let fs_root = create_fs()?;
let mut parent = fs_root.parent.lock();
assert!(fs_root.is_directory());
assert!(parent.is_none());
mountpoint.replace(fs_root.clone());
parent.replace(self.clone());
Ok(())
}
@ -436,7 +435,7 @@ impl Node {
pub(crate) fn as_directory(&self) -> Result<&DirectoryData, Error> {
match &self.data {
NodeImpl::Directory(dir) => Ok(dir),
_ => Err(Error::InvalidFile),
_ => Err(Error::NotADirectory),
}
}

View File

@ -7,7 +7,7 @@ use ext2::Ext2Fs;
use libk::{
block,
fs::{devfs, sysfs},
vfs::{self, register_root, IoContext, NodeRef},
vfs::{self, register_root, FilesystemMountOption, IoContext, NodeRef},
};
use libk_mm::{
address::{PhysicalAddress, Virtualize},
@ -55,8 +55,8 @@ unsafe impl BlockAllocator for FileBlockAllocator {
}
}
/// Constructs an instance of a filesystem for given set of [MountOptions]
pub fn create_filesystem(ioctx: &mut IoContext, options: &MountOptions) -> Result<NodeRef, Error> {
/// Mounts an instance of a filesystem for given set of [MountOptions].
pub fn mount_filesystem(ioctx: &mut IoContext, options: &MountOptions) -> Result<(), Error> {
let Some(fs_name) = options.filesystem else {
log::warn!("TODO: mount without filesystem type/fs probing not yet implemented");
return Err(Error::NotImplemented);
@ -69,8 +69,17 @@ pub fn create_filesystem(ioctx: &mut IoContext, options: &MountOptions) -> Resul
}
ioctx.find(None, path, true)
});
let target = options.target;
let options = vfs::parse_mount_options(options.options);
ioctx.mount(target, move || create_filesystem(fs_name, source, options))
}
fn create_filesystem<'a, I: IntoIterator<Item = FilesystemMountOption<'a>>>(
fs_name: &str,
source: Option<Result<NodeRef, Error>>,
options: I,
) -> Result<NodeRef, Error> {
let root = match fs_name {
"devfs" => devfs::root().clone(),
"sysfs" => sysfs::root().clone(),
@ -86,4 +95,3 @@ pub fn create_filesystem(ioctx: &mut IoContext, options: &MountOptions) -> Resul
Ok(root)
}
// }

View File

@ -47,9 +47,7 @@ pub(crate) fn mount(options: &MountOptions<'_>) -> Result<(), Error> {
let process = thread.process();
run_with_io(&process, |mut io| {
let fs_root = fs::create_filesystem(io.ioctx_mut(), options)?;
io.ioctx_mut().mount(options.target, fs_root)?;
Ok(())
fs::mount_filesystem(io.ioctx_mut(), options)
})
}