Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion etc/syscalls_linux_aarch64.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
| 0x25 (37) | linkat | (int olddfd, const char *oldname, int newdfd, const char *newname, int flags) | __arm64_sys_linkat | true |
| 0x26 (38) | renameat | (int olddfd, const char *oldname, int newdfd, const char *newname) | __arm64_sys_renameat | true |
| 0x27 (39) | umount | (char *name, int flags) | __arm64_sys_umount | false |
| 0x28 (40) | mount | (char *dev_name, char *dir_name, char *type, unsigned long flags, void *data) | __arm64_sys_mount | false |
| 0x28 (40) | mount | (char *dev_name, char *dir_name, char *type, unsigned long flags, void *data) | __arm64_sys_mount | partial |
| 0x29 (41) | pivot_root | (const char *new_root, const char *put_old) | __arm64_sys_pivot_root | false |
| 0x2b (43) | statfs | (const char *pathname, struct statfs *buf) | __arm64_sys_statfs | partial |
| 0x2c (44) | fstatfs | (unsigned int fd, struct statfs *buf) | __arm64_sys_fstatfs | partial |
Expand Down
11 changes: 11 additions & 0 deletions src/arch/arm64/exceptions/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use crate::{
ioctl::sys_ioctl,
iov::{sys_preadv, sys_preadv2, sys_pwritev, sys_pwritev2, sys_readv, sys_writev},
listxattr::{sys_flistxattr, sys_listxattr, sys_llistxattr},
mount::sys_mount,
removexattr::{sys_fremovexattr, sys_lremovexattr, sys_removexattr},
rw::{sys_pread64, sys_pwrite64, sys_read, sys_write},
seek::sys_lseek,
Expand Down Expand Up @@ -231,6 +232,16 @@ pub async fn handle_syscall() {
)
.await
}
0x28 => {
sys_mount(
TUA::from_value(arg1 as _),
TUA::from_value(arg2 as _),
TUA::from_value(arg3 as _),
arg4 as _,
TUA::from_value(arg5 as _),
)
.await
}
0x2b => sys_statfs(TUA::from_value(arg1 as _), TUA::from_value(arg2 as _)).await,
0x2c => sys_fstatfs(arg1.into(), TUA::from_value(arg2 as _)).await,
0x2d => sys_truncate(TUA::from_value(arg1 as _), arg2 as _).await,
Expand Down
20 changes: 20 additions & 0 deletions src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ impl VfsState {
self.mounts.insert(mount_point_id, mount);
}

/// Removes a mount point by its inode ID.
fn remove_mount(&mut self, mount_point_id: &InodeId) -> Option<()> {
let mount = self.mounts.remove(mount_point_id)?;
self.filesystems.remove(&mount.fs.id())?;
Some(())
}

/// Checks if an inode is a mount point and returns the root inode of the
/// mounted filesystem if it is.
fn get_mount_root(&self, inode_id: &InodeId) -> Option<Arc<dyn Inode>> {
Expand Down Expand Up @@ -177,6 +184,19 @@ impl VFS {
Ok(())
}

#[expect(unused)]
pub async fn unmount(&self, mount_point: Arc<dyn Inode>) -> Result<()> {
let mount_point_id = mount_point.id();

// Lock the state and remove the mount.
self.state
.lock_save_irq()
.remove_mount(&mount_point_id)
.ok_or(FsError::NotFound)?;

Ok(())
}

pub async fn get_fs(&self, inode: Arc<dyn Inode>) -> Result<Arc<dyn Filesystem>> {
self.state
.lock_save_irq()
Expand Down
1 change: 1 addition & 0 deletions src/fs/syscalls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub mod getxattr;
pub mod ioctl;
pub mod iov;
pub mod listxattr;
pub mod mount;
pub mod open;
pub mod removexattr;
pub mod rw;
Expand Down
99 changes: 99 additions & 0 deletions src/fs/syscalls/mount.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use crate::fs::VFS;
use crate::memory::uaccess::cstr::UserCStr;
use crate::sched::current::current_task_shared;
use bitflags::bitflags;
use core::ffi::c_char;
use libkernel::error::{KernelError, Result};
use libkernel::fs::path::Path;
use libkernel::memory::address::{TUA, UA};

bitflags! {
#[derive(Debug)]
pub struct MountFlags: u64 {
const MS_RDONLY = 1;
const MS_NOSUID = 2;
const MS_NODEV = 4;
const MS_NOEXEC = 8;
const MS_SYNCHRONOUS = 16;
const MS_REMOUNT = 32;
const MS_MANDLOCK = 64;
const MS_DIRSYNC = 128;
const NOSYMFOLLOW = 256;
const MS_NOATIME = 1024;
const MS_NODIRATIME = 2048;
const MS_BIND = 4096;
const MS_MOVE = 8192;
const MS_REC = 16384;
const MS_VERBOSE = 32768;
const MS_SILENT = 65536;
const MS_POSIXACL = 1 << 16;
const MS_UNBINDABLE = 1 << 17;
const MS_PRIVATE = 1 << 18;
const MS_SLAVE = 1 << 19;
const MS_SHARED = 1 << 20;
const MS_RELATIME = 1 << 21;
const MS_KERNMOUNT = 1 << 22;
const MS_I_VERSION = 1 << 23;
const MS_STRICTATIME = 1 << 24;
const MS_LAZYTIME = 1 << 25;
const MS_SUBMOUNT = 1 << 26;
const MS_NOREMOTELOCK = 1 << 27;
const MS_NOSEC = 1 << 28;
const MS_BORN = 1 << 29;
const MS_ACTIVE = 1 << 30;
const MS_NOUSER = 1 << 31;
}
}

pub async fn sys_mount(
dev_name: TUA<c_char>,
dir_name: TUA<c_char>,
type_: TUA<c_char>,
Comment on lines +49 to +51
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little confused by the args. According to the man page, mount looks like:

       int mount(const char *source, const char *target,
                 const char *filesystemtype, unsigned long mountflags,
                 const void *_Nullable data);

But the following code looks as though it's inspecting the source argument for the filesystem type. Shouldn't that be type?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the table in etc/ it says:

(char *dev_name, char *dir_name, char *type, unsigned long flags, void *data)

filesystemtype (or type) is null when systemd calls this (which was what led to the EFAULT errors). I've got no clue why systemd calls this API the way does. Perhaps source could also be a device file, in which case type is used to specify the filesystem type?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, odd. I can understand why type could be null, you'd read the FS type from /etc/fstab, or inspect the block device to see if any of your FS driver match the magic and try to mount. Odd that it's not specified as nullable in the man page through.

flags: i64,
_data: UA,
) -> Result<usize> {
let flags = MountFlags::from_bits_truncate(flags as u64);
if flags.contains(MountFlags::MS_REC) {
// TODO: Handle later
return Ok(0);
}
let mut buf = [0u8; 1024];
let dev_name = if dev_name.is_null() {
None
} else {
Some(
UserCStr::from_ptr(dev_name)
.copy_from_user(&mut buf)
.await?,
)
};
let mut buf = [0u8; 1024];
let dir_name = UserCStr::from_ptr(dir_name)
.copy_from_user(&mut buf)
.await?;
let mount_point = VFS
.resolve_path(
Path::new(dir_name),
VFS.root_inode(),
&current_task_shared(),
)
.await?;
let mut buf = [0u8; 1024];
let _type = if type_.is_null() {
None
} else {
Some(UserCStr::from_ptr(type_).copy_from_user(&mut buf).await?)
};
if let Some(dev_name) = dev_name {
let dev_name = match dev_name {
"proc" => "procfs",
"devtmpfs" => "devfs",
"cgroup2" => "cgroupfs",
s => s,
};
VFS.mount(mount_point, dev_name, None).await?;
Ok(0)
} else {
Err(KernelError::NotSupported)
}
}
Loading