From f1c0cba3b88e1fd23b01699687ac391fefd9970e Mon Sep 17 00:00:00 2001 From: Ashwin Naren Date: Sat, 7 Feb 2026 14:24:17 -0800 Subject: [PATCH 1/2] statfs --- etc/syscalls_linux_aarch64.md | 4 +- libkernel/src/fs/filesystems/ext4/mod.rs | 5 ++ libkernel/src/fs/filesystems/fat32/mod.rs | 4 ++ libkernel/src/fs/filesystems/tmpfs.rs | 4 ++ libkernel/src/fs/mod.rs | 3 + src/arch/arm64/exceptions/syscall.rs | 4 +- src/drivers/fs/cgroup/mod.rs | 4 ++ src/drivers/fs/dev.rs | 5 ++ src/drivers/fs/proc.rs | 4 ++ src/drivers/fs/sys/mod.rs | 4 ++ src/fs/mod.rs | 7 ++ src/fs/syscalls/mod.rs | 1 + src/fs/syscalls/statfs.rs | 88 +++++++++++++++++++++++ 13 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 src/fs/syscalls/statfs.rs diff --git a/etc/syscalls_linux_aarch64.md b/etc/syscalls_linux_aarch64.md index 2b925b08..bfd3028b 100644 --- a/etc/syscalls_linux_aarch64.md +++ b/etc/syscalls_linux_aarch64.md @@ -43,8 +43,8 @@ | 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 | | 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 | dummy | -| 0x2c (44) | fstatfs | (unsigned int fd, struct statfs *buf) | __arm64_sys_fstatfs | dummy | +| 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 | | 0x2d (45) | truncate | (const char *path, long length) | __arm64_sys_truncate | true | | 0x2e (46) | ftruncate | (unsigned int fd, off_t length) | __arm64_sys_ftruncate | true | | 0x2f (47) | fallocate | (int fd, int mode, loff_t offset, loff_t len) | __arm64_sys_fallocate | false | diff --git a/libkernel/src/fs/filesystems/ext4/mod.rs b/libkernel/src/fs/filesystems/ext4/mod.rs index b0f7bcb2..5445244f 100644 --- a/libkernel/src/fs/filesystems/ext4/mod.rs +++ b/libkernel/src/fs/filesystems/ext4/mod.rs @@ -362,6 +362,11 @@ where self.id } + fn magic(&self) -> u64 { + // TODO: retrieve magic from superblock instead of hardcoding + 0xef53 // EXT4 magic number + } + /// Returns the root inode of the mounted EXT4 filesystem. async fn root_inode(&self) -> Result> { let root = self.inner.read_root_inode().await?; diff --git a/libkernel/src/fs/filesystems/fat32/mod.rs b/libkernel/src/fs/filesystems/fat32/mod.rs index defe4431..8e524ff4 100644 --- a/libkernel/src/fs/filesystems/fat32/mod.rs +++ b/libkernel/src/fs/filesystems/fat32/mod.rs @@ -168,6 +168,10 @@ impl Filesystem for Fat32Filesystem { self.id } + fn magic(&self) -> u64 { + 0x4D44 // MSDOS magic number + } + /// Get the root inode of this filesystem. async fn root_inode(&self) -> Result> { Ok(Arc::new(Fat32DirNode::new( diff --git a/libkernel/src/fs/filesystems/tmpfs.rs b/libkernel/src/fs/filesystems/tmpfs.rs index 453f80b8..fcbd75aa 100644 --- a/libkernel/src/fs/filesystems/tmpfs.rs +++ b/libkernel/src/fs/filesystems/tmpfs.rs @@ -821,6 +821,10 @@ where fn id(&self) -> u64 { self.id } + + fn magic(&self) -> u64 { + 0x01021994 // Tmpfs magic number + } } #[cfg(test)] diff --git a/libkernel/src/fs/mod.rs b/libkernel/src/fs/mod.rs index a27c3985..ad795a85 100644 --- a/libkernel/src/fs/mod.rs +++ b/libkernel/src/fs/mod.rs @@ -65,6 +65,9 @@ pub trait Filesystem: Send + Sync { /// Returns the instance ID for this FS. fn id(&self) -> u64; + /// Get magic + fn magic(&self) -> u64; + /// Flushes all pending data to the underlying storage device(s). /// /// The default implementation is a no-op so that read-only filesystems do diff --git a/src/arch/arm64/exceptions/syscall.rs b/src/arch/arm64/exceptions/syscall.rs index 1038e19e..ec6e1dbe 100644 --- a/src/arch/arm64/exceptions/syscall.rs +++ b/src/arch/arm64/exceptions/syscall.rs @@ -38,6 +38,7 @@ use crate::{ setxattr::{sys_fsetxattr, sys_lsetxattr, sys_setxattr}, splice::sys_sendfile, stat::sys_fstat, + statfs::{sys_fstatfs, sys_statfs}, sync::{sys_fdatasync, sys_fsync, sys_sync, sys_syncfs}, trunc::{sys_ftruncate, sys_truncate}, }, @@ -227,7 +228,8 @@ pub async fn handle_syscall() { ) .await } - 0x2b | 0x2c => Err(KernelError::NotSupported), + 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, 0x2e => sys_ftruncate(arg1.into(), arg2 as _).await, 0x30 => sys_faccessat(arg1.into(), TUA::from_value(arg2 as _), arg3 as _).await, diff --git a/src/drivers/fs/cgroup/mod.rs b/src/drivers/fs/cgroup/mod.rs index 772e6276..bbfd4ab0 100644 --- a/src/drivers/fs/cgroup/mod.rs +++ b/src/drivers/fs/cgroup/mod.rs @@ -127,6 +127,10 @@ impl Filesystem for CgroupFs { fn id(&self) -> u64 { CGROUPFS_ID } + + fn magic(&self) -> u64 { + 0x63677270 // v2 magic number + } } static SYSFS_INSTANCE: OnceLock> = OnceLock::new(); diff --git a/src/drivers/fs/dev.rs b/src/drivers/fs/dev.rs index 1077bfbf..3f8ed7f5 100644 --- a/src/drivers/fs/dev.rs +++ b/src/drivers/fs/dev.rs @@ -88,6 +88,11 @@ impl Filesystem for DevFs { fn id(&self) -> u64 { DEVFS_ID } + + fn magic(&self) -> u64 { + // TODO: Is this the right value + 0x01021994 // TMPFS_MAGIC + } } enum InodeKind { diff --git a/src/drivers/fs/proc.rs b/src/drivers/fs/proc.rs index 3ac32f8d..fa44f56e 100644 --- a/src/drivers/fs/proc.rs +++ b/src/drivers/fs/proc.rs @@ -51,6 +51,10 @@ impl Filesystem for ProcFs { fn id(&self) -> u64 { PROCFS_ID } + + fn magic(&self) -> u64 { + 0x9fa0 // procfs magic number + } } static PROCFS_INSTANCE: OnceLock> = OnceLock::new(); diff --git a/src/drivers/fs/sys/mod.rs b/src/drivers/fs/sys/mod.rs index 178d3c3e..17c4244c 100644 --- a/src/drivers/fs/sys/mod.rs +++ b/src/drivers/fs/sys/mod.rs @@ -176,6 +176,10 @@ impl Filesystem for SysFs { fn id(&self) -> u64 { SYSFS_ID } + + fn magic(&self) -> u64 { + 0x62656572 // sysfs magic number + } } static SYSFS_INSTANCE: OnceLock> = OnceLock::new(); diff --git a/src/fs/mod.rs b/src/fs/mod.rs index 7b51269b..4566f191 100644 --- a/src/fs/mod.rs +++ b/src/fs/mod.rs @@ -177,6 +177,13 @@ impl VFS { Ok(()) } + pub async fn get_fs(&self, inode: Arc) -> Result> { + self.state + .lock_save_irq() + .get_fs(inode.id()) + .ok_or(KernelError::from(FsError::NoDevice)) + } + /// Resolves a path string to an Inode, starting from a given root for /// relative paths. pub async fn resolve_path( diff --git a/src/fs/syscalls/mod.rs b/src/fs/syscalls/mod.rs index 0cc93561..19085927 100644 --- a/src/fs/syscalls/mod.rs +++ b/src/fs/syscalls/mod.rs @@ -14,5 +14,6 @@ pub mod seek; pub mod setxattr; pub mod splice; pub mod stat; +pub mod statfs; pub mod sync; pub mod trunc; diff --git a/src/fs/syscalls/statfs.rs b/src/fs/syscalls/statfs.rs new file mode 100644 index 00000000..74a5861b --- /dev/null +++ b/src/fs/syscalls/statfs.rs @@ -0,0 +1,88 @@ +use crate::fs::VFS; +use crate::memory::uaccess::cstr::UserCStr; +use crate::memory::uaccess::{UserCopyable, copy_to_user}; +use crate::process::fd_table::Fd; +use crate::sched::current::{current_task, current_task_shared}; +use alloc::sync::Arc; +use core::ffi::c_char; +use libkernel::error::KernelError; +use libkernel::fs::Inode; +use libkernel::fs::path::Path; +use libkernel::memory::address::TUA; +use libkernel::pod::Pod; + +type FswordT = u32; +type FsBlockCntT = u64; + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct StatFs { + /// Type of filesystem + f_type: FswordT, + /// Optimal transfer block size + f_bsize: FswordT, + /// Total data blocks in filesystem + f_blocks: FsBlockCntT, + /// Free blocks in filesystem + f_bfree: FsBlockCntT, + /// Free blocks available to unprivileged user + f_bavail: FsBlockCntT, + /// Total inodes in filesystem + f_files: FsBlockCntT, + /// Free inodes in filesystem + f_ffree: FsBlockCntT, + /// Filesystem ID + f_fsid: u64, + /// Maximum length of filenames + f_namelen: FswordT, + /// Fragment size (since Linux 2.6) + f_frsize: FswordT, + /// Mount flags of filesystem (since Linux 2.6.36) + f_flags: FswordT, + /// Padding bytes reserved for future use + f_spare: [FswordT; 6], +} + +unsafe impl Pod for StatFs {} + +unsafe impl UserCopyable for StatFs {} + +async fn statfs_impl(inode: Arc) -> libkernel::error::Result { + let fs = VFS.get_fs(inode).await?; + Ok(StatFs { + f_type: fs.magic() as _, + f_bsize: 0, + f_blocks: 0, + f_bfree: 0, + f_bavail: 0, + f_files: 0, + f_ffree: 0, + f_fsid: fs.id(), + f_namelen: 0, + f_frsize: 0, + f_flags: 0, + f_spare: [0; 6], + }) +} + +pub async fn sys_statfs(path: TUA, stat: TUA) -> libkernel::error::Result { + let mut buf = [0; 1024]; + let path = Path::new(UserCStr::from_ptr(path).copy_from_user(&mut buf).await?); + let inode = VFS + .resolve_path(path, VFS.root_inode(), ¤t_task_shared()) + .await?; + let statfs = statfs_impl(inode).await?; + copy_to_user(stat, statfs).await?; + Ok(0) +} + +pub async fn sys_fstatfs(fd: Fd, stat: TUA) -> libkernel::error::Result { + let fd = current_task() + .fd_table + .lock_save_irq() + .get(fd) + .ok_or(KernelError::BadFd)?; + let statfs = statfs_impl(fd.inode().unwrap()).await?; + copy_to_user(stat, statfs).await?; + Ok(0) +} From 5408932bb9189d1964a98014e79d6b7fea844fa4 Mon Sep 17 00:00:00 2001 From: Ashwin Naren Date: Sat, 7 Feb 2026 15:55:44 -0800 Subject: [PATCH 2/2] fix fstatfs --- src/fs/syscalls/statfs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fs/syscalls/statfs.rs b/src/fs/syscalls/statfs.rs index 74a5861b..0b2dce49 100644 --- a/src/fs/syscalls/statfs.rs +++ b/src/fs/syscalls/statfs.rs @@ -82,7 +82,7 @@ pub async fn sys_fstatfs(fd: Fd, stat: TUA) -> libkernel::error::Result< .lock_save_irq() .get(fd) .ok_or(KernelError::BadFd)?; - let statfs = statfs_impl(fd.inode().unwrap()).await?; + let statfs = statfs_impl(fd.inode().ok_or(KernelError::InvalidValue)?).await?; copy_to_user(stat, statfs).await?; Ok(0) }