From 789b57c6f7572848f652c0b256551f29469225a3 Mon Sep 17 00:00:00 2001 From: LI Qing Date: Thu, 15 Apr 2021 15:55:42 +0800 Subject: [PATCH] Add statfs and fstatfs syscall --- deps/sefs | 2 +- src/libos/src/fs/file.rs | 4 + src/libos/src/fs/fs_ops/mod.rs | 2 + src/libos/src/fs/fs_ops/statfs.rs | 80 ++++++++++++++++++++ src/libos/src/fs/hostfs.rs | 3 +- src/libos/src/fs/inode_file.rs | 4 + src/libos/src/fs/mod.rs | 1 + src/libos/src/fs/procfs/mod.rs | 10 ++- src/libos/src/fs/syscalls.rs | 21 ++++++ src/libos/src/syscall/mod.rs | 16 ++-- test/Makefile | 3 +- test/procfs/main.c | 18 +++++ test/statfs/Makefile | 5 ++ test/statfs/main.c | 117 ++++++++++++++++++++++++++++++ 14 files changed, 272 insertions(+), 14 deletions(-) create mode 100644 src/libos/src/fs/fs_ops/statfs.rs create mode 100644 test/statfs/Makefile create mode 100644 test/statfs/main.c diff --git a/deps/sefs b/deps/sefs index 63306049..6df33e6e 160000 --- a/deps/sefs +++ b/deps/sefs @@ -1 +1 @@ -Subproject commit 633060491f1e2a5c61cd331520c83d588eb5926b +Subproject commit 6df33e6e415be7b17d6d46babf74ef15c044fba9 diff --git a/src/libos/src/fs/file.rs b/src/libos/src/fs/file.rs index b60d0239..d9d8924d 100644 --- a/src/libos/src/fs/file.rs +++ b/src/libos/src/fs/file.rs @@ -95,6 +95,10 @@ pub trait File: Debug + Sync + Send + Any { return_op_unsupported_error!("fallocate") } + fn fs(&self) -> Result> { + return_op_unsupported_error!("fs") + } + // TODO: remove this function after all users of this code are removed fn poll(&self) -> Result<(crate::net::PollEventFlags)> { return_op_unsupported_error!("poll") diff --git a/src/libos/src/fs/fs_ops/mod.rs b/src/libos/src/fs/fs_ops/mod.rs index edbfa372..ed8a09b4 100644 --- a/src/libos/src/fs/fs_ops/mod.rs +++ b/src/libos/src/fs/fs_ops/mod.rs @@ -3,9 +3,11 @@ use super::*; pub use self::chdir::do_chdir; pub use self::getcwd::do_getcwd; pub use self::mount::do_mount_rootfs; +pub use self::statfs::{do_fstatfs, do_statfs, Statfs}; pub use self::sync::do_sync; mod chdir; mod getcwd; mod mount; +mod statfs; mod sync; diff --git a/src/libos/src/fs/fs_ops/statfs.rs b/src/libos/src/fs/fs_ops/statfs.rs new file mode 100644 index 00000000..983938b2 --- /dev/null +++ b/src/libos/src/fs/fs_ops/statfs.rs @@ -0,0 +1,80 @@ +use super::*; +use rcore_fs::vfs::FsInfo; + +pub fn do_fstatfs(fd: FileDesc) -> Result { + debug!("fstatfs: fd: {}", fd); + + let file_ref = current!().file(fd)?; + let statfs = Statfs::from(file_ref.fs()?.info()); + trace!("fstatfs result: {:?}", statfs); + Ok(statfs) +} + +pub fn do_statfs(path: &str) -> Result { + debug!("statfs: path: {:?}", path); + + let inode = { + let current = current!(); + let fs = current.fs().read().unwrap(); + fs.lookup_inode(path)? + }; + let statfs = Statfs::from(inode.fs().info()); + trace!("statfs result: {:?}", statfs); + Ok(statfs) +} + +#[derive(Debug)] +#[repr(C)] +pub struct Statfs { + /// Type of filesystem + f_type: usize, + /// Optimal transfer block size + f_bsize: usize, + /// Total data blocks in filesystem + f_blocks: usize, + /// Free blocks in filesystem + f_bfree: usize, + /// Free blocks available to unprivileged user + f_bavail: usize, + /// Total inodes in filesystem + f_files: usize, + /// Free inodes in filesystem + f_ffree: usize, + /// Filesystem ID + f_fsid: [i32; 2], + /// Maximum length of filenames + f_namelen: usize, + /// Fragment size + f_frsize: usize, + /// Mount flags of filesystem + f_flags: usize, + /// Padding bytes reserved for future use + f_spare: [usize; 4], +} + +impl From for Statfs { + fn from(info: FsInfo) -> Self { + Self { + f_type: match info.magic { + // The "/dev" and "/dev/shm" are tmpfs on Linux, so we transform the + // magic number to TMPFS_MAGIC. + rcore_fs_ramfs::RAMFS_MAGIC | rcore_fs_devfs::DEVFS_MAGIC => { + const TMPFS_MAGIC: usize = 0x0102_1994; + TMPFS_MAGIC + } + val => val, + }, + f_bsize: info.bsize, + f_blocks: info.blocks, + f_bfree: info.bfree, + f_bavail: info.bavail, + f_files: info.files, + f_ffree: info.ffree, + f_fsid: [0i32; 2], + f_namelen: info.namemax, + f_frsize: info.frsize, + f_flags: 0, + f_spare: [0usize; 4], + } + } +} diff --git a/src/libos/src/fs/hostfs.rs b/src/libos/src/fs/hostfs.rs index 6bf0fda1..0829de42 100644 --- a/src/libos/src/fs/hostfs.rs +++ b/src/libos/src/fs/hostfs.rs @@ -36,7 +36,8 @@ impl FileSystem for HostFS { } fn info(&self) -> FsInfo { - unimplemented!() + warn!("HostFS: FsInfo is unimplemented"); + Default::default() } } diff --git a/src/libos/src/fs/inode_file.rs b/src/libos/src/fs/inode_file.rs index 00126eb6..338f8ad2 100644 --- a/src/libos/src/fs/inode_file.rs +++ b/src/libos/src/fs/inode_file.rs @@ -221,6 +221,10 @@ impl File for INodeFile { } } + fn fs(&self) -> Result> { + Ok(self.inode.fs()) + } + fn as_any(&self) -> &dyn Any { self } diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index 9d7f9c08..efbf9150 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -20,6 +20,7 @@ pub use self::file_ops::{ IfConf, IoctlCmd, Stat, StatusFlags, StructuredIoctlArgType, StructuredIoctlNum, }; pub use self::file_table::{FileDesc, FileTable, FileTableEvent, FileTableNotifier}; +pub use self::fs_ops::Statfs; pub use self::fs_view::FsView; pub use self::host_fd::HostFd; pub use self::inode_file::{AsINodeFile, INodeExt, INodeFile}; diff --git a/src/libos/src/fs/procfs/mod.rs b/src/libos/src/fs/procfs/mod.rs index b454d08f..12be004f 100644 --- a/src/libos/src/fs/procfs/mod.rs +++ b/src/libos/src/fs/procfs/mod.rs @@ -16,6 +16,9 @@ mod pid_inode; mod proc_inode; mod self_inode; +// Same with the procfs on Linux +const PROC_SUPER_MAGIC: usize = 0x9fa0; + /// Proc file system pub struct ProcFS { root: Arc>, @@ -33,14 +36,15 @@ impl FileSystem for ProcFS { fn info(&self) -> vfs::FsInfo { vfs::FsInfo { - bsize: 0, - frsize: 0, + magic: PROC_SUPER_MAGIC, + bsize: 4096, + frsize: 4096, blocks: 0, bfree: 0, bavail: 0, files: 0, ffree: 0, - namemax: 0, + namemax: 255, } } } diff --git a/src/libos/src/fs/syscalls.rs b/src/libos/src/fs/syscalls.rs index 21996c8e..0d6e5185 100644 --- a/src/libos/src/fs/syscalls.rs +++ b/src/libos/src/fs/syscalls.rs @@ -553,3 +553,24 @@ pub fn do_fallocate(fd: FileDesc, mode: u32, offset: off_t, len: off_t) -> Resul file_ops::do_fallocate(fd, mode, offset as u64, len as u64)?; Ok(0) } + +pub fn do_fstatfs(fd: FileDesc, statfs_buf: *mut Statfs) -> Result { + from_user::check_mut_ptr(statfs_buf)?; + + let statfs = fs_ops::do_fstatfs(fd)?; + unsafe { + statfs_buf.write(statfs); + } + Ok(0) +} + +pub fn do_statfs(path: *const i8, statfs_buf: *mut Statfs) -> Result { + let path = from_user::clone_cstring_safely(path)? + .to_string_lossy() + .into_owned(); + let statfs = fs_ops::do_statfs(&path)?; + unsafe { + statfs_buf.write(statfs); + } + Ok(0) +} diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index 19f863aa..b3cea49a 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -24,12 +24,12 @@ use crate::exception::do_handle_exception; use crate::fs::{ do_access, do_chdir, do_chmod, do_chown, do_close, do_dup, do_dup2, do_dup3, do_eventfd, do_eventfd2, do_faccessat, do_fallocate, do_fchmod, do_fchmodat, do_fchown, do_fchownat, - do_fcntl, do_fdatasync, do_fstat, do_fstatat, do_fsync, do_ftruncate, do_getcwd, do_getdents, - do_getdents64, do_ioctl, do_lchown, do_link, do_linkat, do_lseek, do_lstat, do_mkdir, - do_mkdirat, do_mount_rootfs, do_open, do_openat, do_pipe, do_pipe2, do_pread, do_pwrite, - do_read, do_readlink, do_readlinkat, do_readv, do_rename, do_renameat, do_rmdir, do_sendfile, - do_stat, do_symlink, do_symlinkat, do_sync, do_truncate, do_unlink, do_unlinkat, do_write, - do_writev, iovec_t, File, FileDesc, FileRef, HostStdioFds, Stat, + do_fcntl, do_fdatasync, do_fstat, do_fstatat, do_fstatfs, do_fsync, do_ftruncate, do_getcwd, + do_getdents, do_getdents64, do_ioctl, do_lchown, do_link, do_linkat, do_lseek, do_lstat, + do_mkdir, do_mkdirat, do_mount_rootfs, do_open, do_openat, do_pipe, do_pipe2, do_pread, + do_pwrite, do_read, do_readlink, do_readlinkat, do_readv, do_rename, do_renameat, do_rmdir, + do_sendfile, do_stat, do_statfs, do_symlink, do_symlinkat, do_sync, do_truncate, do_unlink, + do_unlinkat, do_write, do_writev, iovec_t, File, FileDesc, FileRef, HostStdioFds, Stat, Statfs, }; use crate::interrupt::{do_handle_interrupt, sgx_interrupt_info_t}; use crate::misc::{resource_t, rlimit_t, sysinfo_t, utsname_t}; @@ -222,8 +222,8 @@ macro_rules! process_syscall_table_with_callback { (Uselib = 134) => handle_unsupported(), (Personality = 135) => handle_unsupported(), (Ustat = 136) => handle_unsupported(), - (Statfs = 137) => handle_unsupported(), - (Fstatfs = 138) => handle_unsupported(), + (Statfs = 137) => do_statfs(path: *const i8, statfs_buf: *mut Statfs), + (Fstatfs = 138) => do_fstatfs(fd: FileDesc, statfs_buf: *mut Statfs), (SysFs = 139) => handle_unsupported(), (Getpriority = 140) => handle_unsupported(), (Setpriority = 141) => handle_unsupported(), diff --git a/test/Makefile b/test/Makefile index ec7eda82..7c86f58d 100644 --- a/test/Makefile +++ b/test/Makefile @@ -18,7 +18,8 @@ TEST_DEPS := client data_sink naughty_child TESTS ?= env empty hello_world malloc mmap file fs_perms getpid spawn sched pipe time \ truncate readdir mkdir open stat link symlink chmod chown tls pthread uname rlimit \ server server_epoll unix_socket cout hostfs cpuid rdtsc device sleep exit_group \ - ioctl fcntl eventfd emulate_syscall access signal sysinfo prctl rename procfs wait spawn_attribute + ioctl fcntl eventfd emulate_syscall access signal sysinfo prctl rename procfs wait \ + spawn_attribute statfs # Benchmarks: need to be compiled and run by bench-% target BENCHES := spawn_and_exit_latency pipe_throughput unix_socket_throughput diff --git a/test/procfs/main.c b/test/procfs/main.c index 21670678..46ed5cf9 100644 --- a/test/procfs/main.c +++ b/test/procfs/main.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -142,6 +143,22 @@ static int test_read_from_proc_cpuinfo() { return 0; } +#define PROC_SUPER_MAGIC 0x9fa0 +static int test_statfs() { + const char *file_path = "/proc/cpuinfo"; + struct statfs statfs_buf; + int ret; + + ret = statfs(file_path, &statfs_buf); + if (ret < 0) { + THROW_ERROR("failed to statfs the file"); + } + if (statfs_buf.f_type != PROC_SUPER_MAGIC) { + THROW_ERROR("failed to check the f_type"); + } + return 0; +} + // ============================================================================ // Test suite main // ============================================================================ @@ -154,6 +171,7 @@ static test_case_t test_cases[] = { TEST_CASE(test_read_from_proc_self_cmdline), TEST_CASE(test_read_from_proc_meminfo), TEST_CASE(test_read_from_proc_cpuinfo), + TEST_CASE(test_statfs), }; int main(int argc, const char *argv[]) { diff --git a/test/statfs/Makefile b/test/statfs/Makefile new file mode 100644 index 00000000..9e1b6dec --- /dev/null +++ b/test/statfs/Makefile @@ -0,0 +1,5 @@ +include ../test_common.mk + +EXTRA_C_FLAGS := +EXTRA_LINK_FLAGS := +BIN_ARGS := diff --git a/test/statfs/main.c b/test/statfs/main.c new file mode 100644 index 00000000..ffca51fd --- /dev/null +++ b/test/statfs/main.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include +#include "test_fs.h" + +// ============================================================================ +// Helper function +// ============================================================================ + +static int create_file(const char *file_path) { + int fd; + int flags = O_RDONLY | O_CREAT | O_TRUNC; + int mode = 00666; + + fd = open(file_path, flags, mode); + if (fd < 0) { + THROW_ERROR("failed to create a file"); + } + close(fd); + return 0; +} + +static int remove_file(const char *file_path) { + int ret; + + ret = unlink(file_path); + if (ret < 0) { + THROW_ERROR("failed to unlink the created file"); + } + return 0; +} + +// ============================================================================ +// Test cases for statfs +// ============================================================================ + +static int __test_statfs(const char *file_path, unsigned long expected_type) { + struct statfs statfs_buf; + int ret; + + ret = statfs(file_path, &statfs_buf); + if (ret < 0) { + THROW_ERROR("failed to statfs the file"); + } + if (statfs_buf.f_type != expected_type) { + THROW_ERROR("failed to check the f_type"); + } + return 0; +} + +static int __test_fstatfs(const char *file_path, unsigned long expected_type) { + struct statfs statfs_buf; + int fd, ret; + int flags = O_RDONLY; + + fd = open(file_path, flags); + if (fd < 0) { + THROW_ERROR("failed to open file"); + } + ret = fstatfs(fd, &statfs_buf); + if (ret < 0) { + THROW_ERROR("failed to fstatfs the file"); + } + if (statfs_buf.f_type != expected_type) { + THROW_ERROR("failed to check the f_type"); + } + close(fd); + return 0; +} + +typedef int(*test_statfs_func_t)(const char *, unsigned long); + +static int test_statfs_framework(test_statfs_func_t fn, const char *file_path, + unsigned long expected_type) { + if (create_file(file_path) < 0) { + return -1; + } + if (fn(file_path, expected_type) < 0) { + return -1; + } + if (remove_file(file_path) < 0) { + return -1; + } + return 0; +} + +#define UNIONFS_MAGIC 0x2f8dbe2f +#define TMPFS_MAGIC 0x01021994 + +static int test_statfs_on_root() { + const char *file_path = "/root/test_fs_statfs.txt"; + unsigned long expected_type = UNIONFS_MAGIC; + return test_statfs_framework(__test_statfs, file_path, expected_type) + + test_statfs_framework(__test_fstatfs, file_path, expected_type); +} + +static int test_statfs_on_dev_shm() { + const char *file_path = "/dev/shm/test_fs_statfs.txt"; + unsigned long expected_type = TMPFS_MAGIC; + return test_statfs_framework(__test_statfs, file_path, expected_type) + + test_statfs_framework(__test_fstatfs, file_path, expected_type); +} + +// ============================================================================ +// Test suite main +// ============================================================================ + +static test_case_t test_cases[] = { + TEST_CASE(test_statfs_on_root), + TEST_CASE(test_statfs_on_dev_shm), +}; + +int main(int argc, const char *argv[]) { + return test_suite_run(test_cases, ARRAY_SIZE(test_cases)); +}