Add statfs and fstatfs syscall

This commit is contained in:
LI Qing 2021-04-15 15:55:42 +08:00 committed by Tate, Hongliang Tian
parent f2968799ae
commit 789b57c6f7
14 changed files with 272 additions and 14 deletions

2
deps/sefs vendored

@ -1 +1 @@
Subproject commit 633060491f1e2a5c61cd331520c83d588eb5926b Subproject commit 6df33e6e415be7b17d6d46babf74ef15c044fba9

@ -95,6 +95,10 @@ pub trait File: Debug + Sync + Send + Any {
return_op_unsupported_error!("fallocate") return_op_unsupported_error!("fallocate")
} }
fn fs(&self) -> Result<Arc<dyn FileSystem>> {
return_op_unsupported_error!("fs")
}
// TODO: remove this function after all users of this code are removed // TODO: remove this function after all users of this code are removed
fn poll(&self) -> Result<(crate::net::PollEventFlags)> { fn poll(&self) -> Result<(crate::net::PollEventFlags)> {
return_op_unsupported_error!("poll") return_op_unsupported_error!("poll")

@ -3,9 +3,11 @@ use super::*;
pub use self::chdir::do_chdir; pub use self::chdir::do_chdir;
pub use self::getcwd::do_getcwd; pub use self::getcwd::do_getcwd;
pub use self::mount::do_mount_rootfs; pub use self::mount::do_mount_rootfs;
pub use self::statfs::{do_fstatfs, do_statfs, Statfs};
pub use self::sync::do_sync; pub use self::sync::do_sync;
mod chdir; mod chdir;
mod getcwd; mod getcwd;
mod mount; mod mount;
mod statfs;
mod sync; mod sync;

@ -0,0 +1,80 @@
use super::*;
use rcore_fs::vfs::FsInfo;
pub fn do_fstatfs(fd: FileDesc) -> Result<Statfs> {
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<Statfs> {
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<FsInfo> 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],
}
}
}

@ -36,7 +36,8 @@ impl FileSystem for HostFS {
} }
fn info(&self) -> FsInfo { fn info(&self) -> FsInfo {
unimplemented!() warn!("HostFS: FsInfo is unimplemented");
Default::default()
} }
} }

@ -221,6 +221,10 @@ impl File for INodeFile {
} }
} }
fn fs(&self) -> Result<Arc<dyn FileSystem>> {
Ok(self.inode.fs())
}
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self self
} }

@ -20,6 +20,7 @@ pub use self::file_ops::{
IfConf, IoctlCmd, Stat, StatusFlags, StructuredIoctlArgType, StructuredIoctlNum, IfConf, IoctlCmd, Stat, StatusFlags, StructuredIoctlArgType, StructuredIoctlNum,
}; };
pub use self::file_table::{FileDesc, FileTable, FileTableEvent, FileTableNotifier}; pub use self::file_table::{FileDesc, FileTable, FileTableEvent, FileTableNotifier};
pub use self::fs_ops::Statfs;
pub use self::fs_view::FsView; pub use self::fs_view::FsView;
pub use self::host_fd::HostFd; pub use self::host_fd::HostFd;
pub use self::inode_file::{AsINodeFile, INodeExt, INodeFile}; pub use self::inode_file::{AsINodeFile, INodeExt, INodeFile};

@ -16,6 +16,9 @@ mod pid_inode;
mod proc_inode; mod proc_inode;
mod self_inode; mod self_inode;
// Same with the procfs on Linux
const PROC_SUPER_MAGIC: usize = 0x9fa0;
/// Proc file system /// Proc file system
pub struct ProcFS { pub struct ProcFS {
root: Arc<Dir<LockedProcRootINode>>, root: Arc<Dir<LockedProcRootINode>>,
@ -33,14 +36,15 @@ impl FileSystem for ProcFS {
fn info(&self) -> vfs::FsInfo { fn info(&self) -> vfs::FsInfo {
vfs::FsInfo { vfs::FsInfo {
bsize: 0, magic: PROC_SUPER_MAGIC,
frsize: 0, bsize: 4096,
frsize: 4096,
blocks: 0, blocks: 0,
bfree: 0, bfree: 0,
bavail: 0, bavail: 0,
files: 0, files: 0,
ffree: 0, ffree: 0,
namemax: 0, namemax: 255,
} }
} }
} }

@ -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)?; file_ops::do_fallocate(fd, mode, offset as u64, len as u64)?;
Ok(0) Ok(0)
} }
pub fn do_fstatfs(fd: FileDesc, statfs_buf: *mut Statfs) -> Result<isize> {
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<isize> {
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)
}

@ -24,12 +24,12 @@ use crate::exception::do_handle_exception;
use crate::fs::{ use crate::fs::{
do_access, do_chdir, do_chmod, do_chown, do_close, do_dup, do_dup2, do_dup3, do_eventfd, 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_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_fcntl, do_fdatasync, do_fstat, do_fstatat, do_fstatfs, do_fsync, do_ftruncate, do_getcwd,
do_getdents64, do_ioctl, do_lchown, do_link, do_linkat, do_lseek, do_lstat, do_mkdir, do_getdents, do_getdents64, do_ioctl, do_lchown, do_link, do_linkat, do_lseek, do_lstat,
do_mkdirat, do_mount_rootfs, do_open, do_openat, do_pipe, do_pipe2, do_pread, do_pwrite, do_mkdir, do_mkdirat, do_mount_rootfs, do_open, do_openat, do_pipe, do_pipe2, do_pread,
do_read, do_readlink, do_readlinkat, do_readv, do_rename, do_renameat, do_rmdir, do_sendfile, do_pwrite, do_read, do_readlink, do_readlinkat, do_readv, do_rename, do_renameat, do_rmdir,
do_stat, do_symlink, do_symlinkat, do_sync, do_truncate, do_unlink, do_unlinkat, do_write, do_sendfile, do_stat, do_statfs, do_symlink, do_symlinkat, do_sync, do_truncate, do_unlink,
do_writev, iovec_t, File, FileDesc, FileRef, HostStdioFds, Stat, 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::interrupt::{do_handle_interrupt, sgx_interrupt_info_t};
use crate::misc::{resource_t, rlimit_t, sysinfo_t, utsname_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(), (Uselib = 134) => handle_unsupported(),
(Personality = 135) => handle_unsupported(), (Personality = 135) => handle_unsupported(),
(Ustat = 136) => handle_unsupported(), (Ustat = 136) => handle_unsupported(),
(Statfs = 137) => handle_unsupported(), (Statfs = 137) => do_statfs(path: *const i8, statfs_buf: *mut Statfs),
(Fstatfs = 138) => handle_unsupported(), (Fstatfs = 138) => do_fstatfs(fd: FileDesc, statfs_buf: *mut Statfs),
(SysFs = 139) => handle_unsupported(), (SysFs = 139) => handle_unsupported(),
(Getpriority = 140) => handle_unsupported(), (Getpriority = 140) => handle_unsupported(),
(Setpriority = 141) => handle_unsupported(), (Setpriority = 141) => handle_unsupported(),

@ -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 \ 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 \ 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 \ 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 # Benchmarks: need to be compiled and run by bench-% target
BENCHES := spawn_and_exit_latency pipe_throughput unix_socket_throughput BENCHES := spawn_and_exit_latency pipe_throughput unix_socket_throughput

@ -1,4 +1,5 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/vfs.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h> #include <limits.h>
#include <stdlib.h> #include <stdlib.h>
@ -142,6 +143,22 @@ static int test_read_from_proc_cpuinfo() {
return 0; 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 // 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_self_cmdline),
TEST_CASE(test_read_from_proc_meminfo), TEST_CASE(test_read_from_proc_meminfo),
TEST_CASE(test_read_from_proc_cpuinfo), TEST_CASE(test_read_from_proc_cpuinfo),
TEST_CASE(test_statfs),
}; };
int main(int argc, const char *argv[]) { int main(int argc, const char *argv[]) {

5
test/statfs/Makefile Normal file

@ -0,0 +1,5 @@
include ../test_common.mk
EXTRA_C_FLAGS :=
EXTRA_LINK_FLAGS :=
BIN_ARGS :=

117
test/statfs/main.c Normal file

@ -0,0 +1,117 @@
#include <sys/vfs.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#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));
}