Merge pull request #203 from arihant2math/statfs

Implement `sys_statfs` and `sys_fstatfs`
This commit is contained in:
Matthew Leach
2026-02-15 20:05:13 +00:00
committed by GitHub
13 changed files with 134 additions and 3 deletions

View File

@@ -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 |

View File

@@ -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<Arc<dyn Inode>> {
let root = self.inner.read_root_inode().await?;

View File

@@ -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<Arc<dyn Inode>> {
Ok(Arc::new(Fat32DirNode::new(

View File

@@ -821,6 +821,10 @@ where
fn id(&self) -> u64 {
self.id
}
fn magic(&self) -> u64 {
0x01021994 // Tmpfs magic number
}
}
#[cfg(test)]

View File

@@ -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

View File

@@ -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,

View File

@@ -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<Arc<CgroupFs>> = OnceLock::new();

View File

@@ -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 {

View File

@@ -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<Arc<ProcFs>> = OnceLock::new();

View File

@@ -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<Arc<SysFs>> = OnceLock::new();

View File

@@ -177,6 +177,13 @@ impl VFS {
Ok(())
}
pub async fn get_fs(&self, inode: Arc<dyn Inode>) -> Result<Arc<dyn Filesystem>> {
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(

View File

@@ -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;

88
src/fs/syscalls/statfs.rs Normal file
View File

@@ -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<dyn Inode>) -> libkernel::error::Result<StatFs> {
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<c_char>, stat: TUA<StatFs>) -> libkernel::error::Result<usize> {
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(), &current_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<StatFs>) -> libkernel::error::Result<usize> {
let fd = current_task()
.fd_table
.lock_save_irq()
.get(fd)
.ok_or(KernelError::BadFd)?;
let statfs = statfs_impl(fd.inode().ok_or(KernelError::InvalidValue)?).await?;
copy_to_user(stat, statfs).await?;
Ok(0)
}