Browse Source

feat: support fsync/sync/syncfs syscall (#1250)

Signed-off-by: Godones <chenlinfeng25@outlook.com>
linfeng 2 weeks ago
parent
commit
501d9f259a

+ 11 - 0
kernel/src/filesystem/page_cache.rs

@@ -316,6 +316,17 @@ impl InnerPageCache {
     pub fn pages_count(&self) -> usize {
         return self.pages.len();
     }
+
+    /// Synchronize the page cache with the storage device.
+    pub fn sync(&mut self) -> Result<(), SystemError> {
+        for page in self.pages.values() {
+            let mut guard = page.write_irqsave();
+            if guard.flags().contains(PageFlags::PG_DIRTY) {
+                crate::mm::page::PageReclaimer::page_writeback(&mut guard, false);
+            }
+        }
+        Ok(())
+    }
 }
 
 impl Drop for InnerPageCache {

+ 5 - 1
kernel/src/filesystem/vfs/mod.rs

@@ -561,7 +561,11 @@ pub trait IndexNode: Any + Sync + Send + Debug + CastFromSync {
 
     /// @brief 将当前inode的内容同步到具体设备上
     fn sync(&self) -> Result<(), SystemError> {
-        return Ok(());
+        let page_cache = self.page_cache();
+        if let Some(page_cache) = page_cache {
+            return page_cache.lock_irqsave().sync();
+        }
+        Ok(())
     }
 
     /// ## 创建一个特殊文件节点

+ 8 - 0
kernel/src/filesystem/vfs/mount.rs

@@ -620,6 +620,14 @@ impl IndexNode for MountFSInode {
     fn as_pollable_inode(&self) -> Result<&dyn PollableInode, SystemError> {
         self.inner_inode.as_pollable_inode()
     }
+
+    fn read_sync(&self, offset: usize, buf: &mut [u8]) -> Result<usize, SystemError> {
+        self.inner_inode.read_sync(offset, buf)
+    }
+
+    fn write_sync(&self, offset: usize, buf: &[u8]) -> Result<usize, SystemError> {
+        self.inner_inode.write_sync(offset, buf)
+    }
 }
 
 impl FileSystem for MountFS {

+ 3 - 0
kernel/src/filesystem/vfs/syscall/mod.rs

@@ -52,7 +52,9 @@ mod sys_epoll_ctl;
 mod sys_epoll_pwait;
 
 pub mod symlink_utils;
+mod sys_fsync;
 pub mod sys_mount;
+mod sys_sync;
 pub mod sys_umount2;
 
 #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))]
@@ -70,6 +72,7 @@ mod sys_dup2;
 mod sys_epoll_create;
 #[cfg(target_arch = "x86_64")]
 mod sys_epoll_wait;
+
 #[cfg(target_arch = "x86_64")]
 mod sys_futimesat;
 #[cfg(target_arch = "x86_64")]

+ 42 - 0
kernel/src/filesystem/vfs/syscall/sys_fsync.rs

@@ -0,0 +1,42 @@
+use alloc::string::ToString;
+
+use alloc::vec::Vec;
+
+use crate::{
+    arch::{interrupt::TrapFrame, syscall::nr::SYS_FSYNC},
+    syscall::table::{FormattedSyscallParam, Syscall},
+};
+
+/// synchronize a file's in-core state with storagedevice.
+///
+/// See https://man7.org/linux/man-pages/man2/fsync.2.html
+pub struct SysFsyncHandle;
+
+impl Syscall for SysFsyncHandle {
+    fn num_args(&self) -> usize {
+        1
+    }
+
+    fn handle(
+        &self,
+        args: &[usize],
+        _frame: &mut TrapFrame,
+    ) -> Result<usize, system_error::SystemError> {
+        let fd = args[0] as i32;
+        let binding = crate::process::ProcessManager::current_pcb().fd_table();
+        let fd_table_guard = binding.read();
+        let file = fd_table_guard
+            .get_file_by_fd(fd)
+            .ok_or(system_error::SystemError::EBADF)?;
+        drop(fd_table_guard);
+        let inode = file.inode();
+        inode.sync()?;
+        Ok(0)
+    }
+
+    fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
+        vec![FormattedSyscallParam::new("fd", args[0].to_string())]
+    }
+}
+
+syscall_table_macros::declare_syscall!(SYS_FSYNC, SysFsyncHandle);

+ 69 - 0
kernel/src/filesystem/vfs/syscall/sys_sync.rs

@@ -0,0 +1,69 @@
+use alloc::string::ToString;
+
+use alloc::vec::Vec;
+
+use crate::{
+    arch::{
+        interrupt::TrapFrame,
+        syscall::nr::{SYS_SYNC, SYS_SYNCFS},
+    },
+    mm::page::page_reclaimer_lock_irqsave,
+    syscall::table::{FormattedSyscallParam, Syscall},
+};
+
+/// sync() causes all pending modifications to filesystem metadata and
+/// cached file data to be written to the underlying filesystems.
+///
+/// See https://man7.org/linux/man-pages/man2/sync.2.html
+pub struct SysSyncHandle;
+
+impl Syscall for SysSyncHandle {
+    fn num_args(&self) -> usize {
+        0
+    }
+
+    fn handle(
+        &self,
+        _args: &[usize],
+        _frame: &mut TrapFrame,
+    ) -> Result<usize, system_error::SystemError> {
+        page_reclaimer_lock_irqsave().flush_dirty_pages();
+        Ok(0)
+    }
+
+    fn entry_format(&self, _args: &[usize]) -> Vec<FormattedSyscallParam> {
+        vec![FormattedSyscallParam::new(
+            "No arguments",
+            "sync()".to_string(),
+        )]
+    }
+}
+
+syscall_table_macros::declare_syscall!(SYS_SYNC, SysSyncHandle);
+
+/// syncfs() is like sync(), but synchronizes just the filesystem
+/// containing file referred to by the open file descriptor fd.
+pub struct SysSyncFsHandle;
+
+impl Syscall for SysSyncFsHandle {
+    fn num_args(&self) -> usize {
+        1
+    }
+
+    fn handle(
+        &self,
+        _args: &[usize],
+        _frame: &mut TrapFrame,
+    ) -> Result<usize, system_error::SystemError> {
+        // TODO: now, we ignore the fd and sync all filesystems.
+        // In the future, we should sync only the filesystem of the given fd.
+        page_reclaimer_lock_irqsave().flush_dirty_pages();
+        Ok(0)
+    }
+
+    fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
+        vec![FormattedSyscallParam::new("fd", format!("{}", args[0]))]
+    }
+}
+
+syscall_table_macros::declare_syscall!(SYS_SYNCFS, SysSyncHandle);