From f8694029ab55cc847f13de9f4233362e38531205 Mon Sep 17 00:00:00 2001 From: Matheus Date: Fri, 20 Mar 2026 21:28:59 -0300 Subject: [PATCH] syscalls: statvfs --- kernel-src/arch/x86-64/syscall.asm | 6 +- kernel-src/arch/x86-64/syscalllog.c | 10 ++- kernel-src/fs/ext2.c | 27 +++++- kernel-src/fs/tmpfs.c | 25 +++++- kernel-src/include/kernel/vfs.h | 16 ++++ kernel-src/sys/syscalls/statvfs.c | 133 ++++++++++++++++++++++++++++ 6 files changed, 212 insertions(+), 5 deletions(-) create mode 100644 kernel-src/sys/syscalls/statvfs.c diff --git a/kernel-src/arch/x86-64/syscall.asm b/kernel-src/arch/x86-64/syscall.asm index b756aea3..ba17b970 100644 --- a/kernel-src/arch/x86-64/syscall.asm +++ b/kernel-src/arch/x86-64/syscall.asm @@ -99,6 +99,8 @@ extern syscall_sysinfo extern syscall_writev extern syscall_readv extern syscall_yield +extern syscall_fstatvfs +extern syscall_fstatvfsat syscalltab: dq syscall_print dq syscall_mmap @@ -200,7 +202,9 @@ dq syscall_sysinfo dq syscall_writev dq syscall_readv dq syscall_yield -syscallcount equ 100 +dq syscall_fstatvfs +dq syscall_fstatvfsat +syscallcount equ 102 section .text global arch_syscall_entry ; on entry: diff --git a/kernel-src/arch/x86-64/syscalllog.c b/kernel-src/arch/x86-64/syscalllog.c index c4bfc9a2..07202c44 100644 --- a/kernel-src/arch/x86-64/syscalllog.c +++ b/kernel-src/arch/x86-64/syscalllog.c @@ -8,7 +8,7 @@ void arch_interrupt_disable(); void arch_interrupt_enable(); -#define SYSCALL_COUNT 99 +#define SYSCALL_COUNT 102 #define LOGSTR(x) arch_e9_puts(x) static char *name[] = { @@ -110,7 +110,10 @@ static char *name[] = { "getcpu", "sysinfo", "writev", - "readv" + "readv", + "yield", + "fstatvfs", + "fstatvfsat", }; static char *args[] = { @@ -213,6 +216,9 @@ static char *args[] = { "ptr %p", // sysinfo "fd %d iov %p iovcnt %d", // writev "fd %d iov %p iovcnt %d", // readv + "N/A", // yield + "fd %d ustat %p", // fstatvfs + "dirfd %d path %s ustat %p flags %d", // fstatvfsat }; #endif diff --git a/kernel-src/fs/ext2.c b/kernel-src/fs/ext2.c index 3d12f61c..a975e5dd 100644 --- a/kernel-src/fs/ext2.c +++ b/kernel-src/fs/ext2.c @@ -1969,6 +1969,30 @@ static int ext2_inactive(vnode_t *vnode) { return 0; } +static int ext2_statfs(vfs_t *vfs, fsattr_t *fsattr) { + ext2fs_t *ext2fs = (ext2fs_t *)vfs; + + fsattr->io_size = ext2fs->blocksize; + fsattr->block_size = ext2fs->blocksize; + fsattr->block_count = ext2fs->superblock.blockcount; + fsattr->inode_count = ext2fs->superblock.inodecount; + + MUTEX_ACQUIRE(&ext2fs->superblocklock); + + fsattr->free_blocks = ext2fs->superblock.unallocatedblocks; + fsattr->free_blocks_unprivileged = ext2fs->superblock.unallocatedblocks; + fsattr->free_inode_count = ext2fs->superblock.unallocatedinodes; + fsattr->free_inode_count_unprivileged = ext2fs->superblock.unallocatedinodes; + + MUTEX_RELEASE(&ext2fs->superblocklock); + + fsattr->fsid = 0; // TODO + fsattr->flags = 0; + fsattr->max_name_size = 255; + + return 0; +} + // TODO move root variable to vfs static int ext2_root(vfs_t *vfs, vnode_t **vnodep) { ext2fs_t *fs = (ext2fs_t *)vfs; @@ -2102,7 +2126,8 @@ static int ext2_mount(vfs_t **vfs, vnode_t *mountpoint, vnode_t *backing, void * static vfsops_t vfsops = { .mount = ext2_mount, - .root = ext2_root + .root = ext2_root, + .statfs = ext2_statfs }; static vops_t vnops = { diff --git a/kernel-src/fs/tmpfs.c b/kernel-src/fs/tmpfs.c index e509a8a5..e70c06df 100644 --- a/kernel-src/fs/tmpfs.c +++ b/kernel-src/fs/tmpfs.c @@ -560,9 +560,32 @@ static int tmpfs_unlock(vnode_t *node) { return 0; } +static int tmpfs_statfs(vfs_t *vfs, fsattr_t *fsattr) { + tmpfs_t *tmpfs = (tmpfs_t *)vfs; + + size_t total_pages, free_pages; + pmm_getinfo(&total_pages, &free_pages); + + fsattr->io_size = PAGE_SIZE; + fsattr->block_size = PAGE_SIZE; + fsattr->block_count = total_pages; + fsattr->free_blocks = free_pages; + fsattr->free_blocks_unprivileged = free_pages; + fsattr->inode_count = INT64_MAX; + fsattr->free_inode_count = INT64_MAX; + fsattr->free_inode_count_unprivileged = INT64_MAX; + + fsattr->fsid = tmpfs->id; + fsattr->flags = 0; + fsattr->max_name_size = 255; + + return 0; +} + static vfsops_t vfsops = { .mount = tmpfs_mount, - .root = tmpfs_root + .root = tmpfs_root, + .statfs = tmpfs_statfs }; static vops_t vnops = { diff --git a/kernel-src/include/kernel/vfs.h b/kernel-src/include/kernel/vfs.h index 12c87d0e..c1a368b4 100644 --- a/kernel-src/include/kernel/vfs.h +++ b/kernel-src/include/kernel/vfs.h @@ -65,6 +65,20 @@ typedef struct { size_t blocksused; } vattr_t; +typedef struct { + size_t io_size; + size_t block_size; + size_t block_count; + size_t free_blocks; + size_t free_blocks_unprivileged; + size_t inode_count; + size_t free_inode_count; + size_t free_inode_count_unprivileged; + unsigned long fsid; + unsigned long flags; + size_t max_name_size; +} fsattr_t; + typedef struct vfs_t { struct vfs_t *next; struct vfsops_t *ops; @@ -131,6 +145,7 @@ typedef struct vfsops_t { int (*unmount)(vfs_t *vfs); int (*sync)(vfs_t *vfs); int (*root)(vfs_t *vfs, vnode_t **root); + int (*statfs)(vfs_t *vfs, fsattr_t *fsattr); } vfsops_t; struct polldata; @@ -178,6 +193,7 @@ typedef struct vops_t { #define VFS_UNMOUNT(vfs) (vfs)->ops->unmount(vfs) #define VFS_ROOT(vfs, r) (vfs)->ops->root(vfs, r) #define VFS_SYNC(vfs) (vfs)->ops->sync(vfs) +#define VFS_STATFS(vfs, f) ((vfs)->ops->statfs ? (vfs)->ops->statfs(vfs, f) : ENOSYS) #define VOP_INIT(vn, o, f, t, v) \ (vn)->ops = o; \ diff --git a/kernel-src/sys/syscalls/statvfs.c b/kernel-src/sys/syscalls/statvfs.c new file mode 100644 index 00000000..efd25c6a --- /dev/null +++ b/kernel-src/sys/syscalls/statvfs.c @@ -0,0 +1,133 @@ +#include +#include +#include +#include +#include +#include +#include + +typedef uint64_t fsblkcnt_t; +typedef uint64_t fsfilcnt_t; + +typedef struct { + unsigned long f_bsize; + unsigned long f_frsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsfilcnt_t f_favail; + + unsigned long f_fsid; + unsigned long f_flag; + unsigned long f_namemax; +} statvfs_t; + +syscallret_t syscall_fstatvfs(context_t *ctx, int fd, statvfs_t *ustatvfs) { + syscallret_t ret = { + .ret = -1 + }; + + file_t *file = fd_get(fd); + if (file == NULL) { + ret.errno = EBADF; + return ret; + } + + fsattr_t buf; + ret.errno = VFS_STATFS(file->vnode->vfs, &buf); + if (ret.errno) + goto cleanup; + + statvfs_t output = { + .f_bsize = buf.io_size, + .f_frsize = buf.block_size, + .f_blocks = buf.block_count, + .f_bfree = buf.free_blocks, + .f_bavail = buf.free_blocks_unprivileged, + .f_files = buf.inode_count, + .f_ffree = buf.free_inode_count, + .f_favail = buf.free_inode_count_unprivileged, + .f_fsid = buf.fsid, + .f_flag = buf.flags, + .f_namemax = buf.max_name_size + }; + + ret.errno = usercopy_touser(ustatvfs, &output, sizeof(statvfs_t)); + ret.ret = ret.errno ? -1 : 0; + + cleanup: + fd_release(file); + return ret; +} + +syscallret_t syscall_fstatvfsat(context_t *ctx, int dirfd, char *upath, stat_t *ustatvfs, int flags) { + syscallret_t ret = { + .ret = -1 + }; + + size_t pathlen; + ret.errno = usercopy_strlen(upath, &pathlen); + if (ret.errno) + return ret; + + char *path = alloc(pathlen + 1); + if (path == NULL) { + ret.errno = ENOMEM; + return ret; + } + + ret.errno = usercopy_fromuser(path, upath, pathlen); + if (ret.errno) { + free(path); + return ret; + } + + vnode_t *dirnode = NULL; + file_t *file = NULL; + ret.errno = dirfd_enter(path, dirfd, &file, &dirnode); + if (ret.errno) + goto cleanup; + + vnode_t *node = NULL; + ret.errno = vfs_lookup(&node, dirnode, path, NULL, flags & AT_SYMLINK_NOFOLLOW ? VFS_LOOKUP_NOLINK : 0); + if (ret.errno) + goto cleanup; + // locked by vfs_lookup + VOP_UNLOCK(node); + + fsattr_t buf; + ret.errno = VFS_STATFS(node->vfs, &buf); + if (ret.errno) + goto cleanup; + + statvfs_t output = { + .f_bsize = buf.io_size, + .f_frsize = buf.block_size, + .f_blocks = buf.block_count, + .f_bfree = buf.free_blocks, + .f_bavail = buf.free_blocks_unprivileged, + .f_files = buf.inode_count, + .f_ffree = buf.free_inode_count, + .f_favail = buf.free_inode_count_unprivileged, + .f_fsid = buf.fsid, + .f_flag = buf.flags, + .f_namemax = buf.max_name_size + }; + + ret.errno = usercopy_touser(ustatvfs, &output, sizeof(statvfs_t)); + ret.ret = ret.errno ? -1 : 0; + + cleanup: + if (node) + VOP_RELEASE(node); + + if (dirnode) + dirfd_leave(dirnode, file); + + free(path); + + return ret; +}