From 212dd562a006c80a4071b962466a18900a14db49 Mon Sep 17 00:00:00 2001 From: Fabing Li Date: Thu, 27 Jun 2024 10:46:58 +0800 Subject: [PATCH] Add sys_fdatasync and sync_data --- docs/src/kernel/linux-compatibility.md | 2 +- kernel/aster-nix/src/fs/exfat/fs.rs | 4 +- kernel/aster-nix/src/fs/exfat/inode.rs | 34 +++++++--- .../src/fs/ext2/impl_for_vfs/inode.rs | 6 +- kernel/aster-nix/src/fs/path/dentry.rs | 6 +- .../aster-nix/src/fs/procfs/template/dir.rs | 4 -- .../aster-nix/src/fs/procfs/template/file.rs | 4 -- .../aster-nix/src/fs/procfs/template/sym.rs | 4 -- kernel/aster-nix/src/fs/ramfs/fs.rs | 5 -- kernel/aster-nix/src/fs/utils/inode.rs | 6 +- kernel/aster-nix/src/syscall/arch/x86.rs | 3 +- kernel/aster-nix/src/syscall/fsync.rs | 18 +++++- regression/apps/Makefile | 1 + regression/apps/fdatasync/Makefile | 5 ++ regression/apps/fdatasync/fdatasync.c | 49 +++++++++++++++ regression/apps/scripts/ext2.sh | 44 ------------- regression/apps/scripts/fs.sh | 62 +++++++++++++++++++ .../apps/scripts/run_regression_test.sh | 2 +- 18 files changed, 178 insertions(+), 81 deletions(-) create mode 100644 regression/apps/fdatasync/Makefile create mode 100644 regression/apps/fdatasync/fdatasync.c delete mode 100755 regression/apps/scripts/ext2.sh create mode 100755 regression/apps/scripts/fs.sh diff --git a/docs/src/kernel/linux-compatibility.md b/docs/src/kernel/linux-compatibility.md index 6ba38a9c0..be1afba88 100644 --- a/docs/src/kernel/linux-compatibility.md +++ b/docs/src/kernel/linux-compatibility.md @@ -95,7 +95,7 @@ provided by Linux on x86-64 architecture. | 72 | fcntl | ✅ | | 73 | flock | ❌ | | 74 | fsync | ✅ | -| 75 | fdatasync | ❌ | +| 75 | fdatasync | ✅ | | 76 | truncate | ✅ | | 77 | ftruncate | ✅ | | 78 | getdents | ✅ | diff --git a/kernel/aster-nix/src/fs/exfat/fs.rs b/kernel/aster-nix/src/fs/exfat/fs.rs index 077bdc507..6d50486fb 100644 --- a/kernel/aster-nix/src/fs/exfat/fs.rs +++ b/kernel/aster-nix/src/fs/exfat/fs.rs @@ -135,7 +135,7 @@ impl ExfatFS { if inode.is_deleted() { inode.reclaim_space()?; } else { - inode.sync()?; + inode.sync_all()?; } } self.inodes.write().remove(&hash); @@ -392,7 +392,7 @@ impl PageCacheBackend for ExfatFS { impl FileSystem for ExfatFS { fn sync(&self) -> Result<()> { for inode in self.inodes.read().values() { - inode.sync()?; + inode.sync_all()?; } self.meta_cache.evict_range(0..self.fs_size())?; Ok(()) diff --git a/kernel/aster-nix/src/fs/exfat/inode.rs b/kernel/aster-nix/src/fs/exfat/inode.rs index f4a96f66b..29ed19250 100644 --- a/kernel/aster-nix/src/fs/exfat/inode.rs +++ b/kernel/aster-nix/src/fs/exfat/inode.rs @@ -573,9 +573,14 @@ impl ExfatInodeInner { Ok(()) } - fn sync(&self, fs_guard: &MutexGuard<()>) -> Result<()> { + fn sync_data(&self, fs_guard: &MutexGuard<()>) -> Result<()> { self.page_cache.evict_range(0..self.size)?; + Ok(()) + } + + fn sync_all(&self, fs_guard: &MutexGuard<()>) -> Result<()> { self.sync_metadata(fs_guard)?; + self.sync_data(fs_guard)?; Ok(()) } @@ -1328,7 +1333,7 @@ impl Inode for ExfatInode { if inner.is_sync() { let fs = inner.fs(); let fs_guard = fs.lock(); - inner.sync(&fs_guard)?; + inner.sync_all(&fs_guard)?; } Ok(buf.len()) @@ -1435,7 +1440,7 @@ impl Inode for ExfatInode { let inner = self.inner.read(); if inner.is_sync() { - inner.sync(&fs_guard)?; + inner.sync_all(&fs_guard)?; } Ok(result) @@ -1530,7 +1535,7 @@ impl Inode for ExfatInode { let inner = self.inner.read(); if inner.is_sync() { - inner.sync(&fs_guard)?; + inner.sync_all(&fs_guard)?; } Ok(()) @@ -1567,7 +1572,7 @@ impl Inode for ExfatInode { let inner = self.inner.read(); // Sync this inode since size has changed. if inner.is_sync() { - inner.sync(&fs_guard)?; + inner.sync_all(&fs_guard)?; } Ok(()) @@ -1656,9 +1661,9 @@ impl Inode for ExfatInode { // Sync if self.inner.read().is_sync() || target_.inner.read().is_sync() { // TODO: what if fs crashed between syncing? - old_inode.inner.read().sync(&fs_guard)?; - target_.inner.read().sync(&fs_guard)?; - self.inner.read().sync(&fs_guard)?; + old_inode.inner.read().sync_all(&fs_guard)?; + target_.inner.read().sync_all(&fs_guard)?; + self.inner.read().sync_all(&fs_guard)?; } Ok(()) } @@ -1675,11 +1680,20 @@ impl Inode for ExfatInode { return_errno_with_message!(Errno::EINVAL, "unsupported operation") } - fn sync(&self) -> Result<()> { + fn sync_all(&self) -> Result<()> { let inner = self.inner.read(); let fs = inner.fs(); let fs_guard = fs.lock(); - inner.sync(&fs_guard)?; + inner.sync_all(&fs_guard)?; + + Ok(()) + } + + fn sync_data(&self) -> Result<()> { + let inner = self.inner.read(); + let fs = inner.fs(); + let fs_guard = fs.lock(); + inner.sync_data(&fs_guard)?; Ok(()) } diff --git a/kernel/aster-nix/src/fs/ext2/impl_for_vfs/inode.rs b/kernel/aster-nix/src/fs/ext2/impl_for_vfs/inode.rs index 63cfe6660..3054763f9 100644 --- a/kernel/aster-nix/src/fs/ext2/impl_for_vfs/inode.rs +++ b/kernel/aster-nix/src/fs/ext2/impl_for_vfs/inode.rs @@ -176,10 +176,14 @@ impl Inode for Ext2Inode { Err(Error::new(Errno::EINVAL)) } - fn sync(&self) -> Result<()> { + fn sync_all(&self) -> Result<()> { self.sync_all() } + fn sync_data(&self) -> Result<()> { + self.sync_data() + } + fn fs(&self) -> Arc { self.fs() } diff --git a/kernel/aster-nix/src/fs/path/dentry.rs b/kernel/aster-nix/src/fs/path/dentry.rs index 05b3c8c99..12bfa8a33 100644 --- a/kernel/aster-nix/src/fs/path/dentry.rs +++ b/kernel/aster-nix/src/fs/path/dentry.rs @@ -299,7 +299,8 @@ impl Dentry_ { #[inherit_methods(from = "self.inode")] impl Dentry_ { pub fn fs(&self) -> Arc; - pub fn sync(&self) -> Result<()>; + pub fn sync_all(&self) -> Result<()>; + pub fn sync_data(&self) -> Result<()>; pub fn metadata(&self) -> Metadata; pub fn type_(&self) -> InodeType; pub fn mode(&self) -> Result; @@ -680,7 +681,8 @@ impl Dentry { #[inherit_methods(from = "self.inner")] impl Dentry { pub fn fs(&self) -> Arc; - pub fn sync(&self) -> Result<()>; + pub fn sync_all(&self) -> Result<()>; + pub fn sync_data(&self) -> Result<()>; pub fn metadata(&self) -> Metadata; pub fn type_(&self) -> InodeType; pub fn mode(&self) -> Result; diff --git a/kernel/aster-nix/src/fs/procfs/template/dir.rs b/kernel/aster-nix/src/fs/procfs/template/dir.rs index 1ceca98ae..212ddc087 100644 --- a/kernel/aster-nix/src/fs/procfs/template/dir.rs +++ b/kernel/aster-nix/src/fs/procfs/template/dir.rs @@ -183,10 +183,6 @@ impl Inode for ProcDir { Err(Error::new(Errno::EPERM)) } - fn sync(&self) -> Result<()> { - Ok(()) - } - fn is_dentry_cacheable(&self) -> bool { !self.common.is_volatile() } diff --git a/kernel/aster-nix/src/fs/procfs/template/file.rs b/kernel/aster-nix/src/fs/procfs/template/file.rs index 7b7648fa4..f7a1832ef 100644 --- a/kernel/aster-nix/src/fs/procfs/template/file.rs +++ b/kernel/aster-nix/src/fs/procfs/template/file.rs @@ -95,10 +95,6 @@ impl Inode for ProcFile { Err(Error::new(Errno::EPERM)) } - fn sync(&self) -> Result<()> { - Ok(()) - } - fn is_dentry_cacheable(&self) -> bool { !self.common.is_volatile() } diff --git a/kernel/aster-nix/src/fs/procfs/template/sym.rs b/kernel/aster-nix/src/fs/procfs/template/sym.rs index 1f43a6a7b..4e724869c 100644 --- a/kernel/aster-nix/src/fs/procfs/template/sym.rs +++ b/kernel/aster-nix/src/fs/procfs/template/sym.rs @@ -87,10 +87,6 @@ impl Inode for ProcSym { Err(Error::new(Errno::EPERM)) } - fn sync(&self) -> Result<()> { - Ok(()) - } - fn is_dentry_cacheable(&self) -> bool { !self.common.is_volatile() } diff --git a/kernel/aster-nix/src/fs/ramfs/fs.rs b/kernel/aster-nix/src/fs/ramfs/fs.rs index af4027dbf..1ec638d4f 100644 --- a/kernel/aster-nix/src/fs/ramfs/fs.rs +++ b/kernel/aster-nix/src/fs/ramfs/fs.rs @@ -993,11 +993,6 @@ impl Inode for RamInode { } } - fn sync(&self) -> Result<()> { - // do nothing - Ok(()) - } - fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { if let Some(device) = self.node.read().inner.as_device() { device.poll(mask, poller) diff --git a/kernel/aster-nix/src/fs/utils/inode.rs b/kernel/aster-nix/src/fs/utils/inode.rs index e2ce9205f..c61596fa7 100644 --- a/kernel/aster-nix/src/fs/utils/inode.rs +++ b/kernel/aster-nix/src/fs/utils/inode.rs @@ -340,7 +340,11 @@ pub trait Inode: Any + Sync + Send { Err(Error::new(Errno::EISDIR)) } - fn sync(&self) -> Result<()> { + fn sync_all(&self) -> Result<()> { + Ok(()) + } + + fn sync_data(&self) -> Result<()> { Ok(()) } diff --git a/kernel/aster-nix/src/syscall/arch/x86.rs b/kernel/aster-nix/src/syscall/arch/x86.rs index 7bb7a289b..84c825847 100644 --- a/kernel/aster-nix/src/syscall/arch/x86.rs +++ b/kernel/aster-nix/src/syscall/arch/x86.rs @@ -25,7 +25,7 @@ use crate::syscall::{ exit_group::sys_exit_group, fcntl::sys_fcntl, fork::sys_fork, - fsync::sys_fsync, + fsync::{sys_fdatasync, sys_fsync}, futex::sys_futex, getcwd::sys_getcwd, getdents64::{sys_getdents, sys_getdents64}, @@ -182,6 +182,7 @@ impl_syscall_nums_and_dispatch_fn! { SYS_UNAME = 63 => sys_uname(args[..1]); SYS_FCNTL = 72 => sys_fcntl(args[..3]); SYS_FSYNC = 74 => sys_fsync(args[..1]); + SYS_FDATASYNC = 75 => sys_fdatasync(args[..1]); SYS_TRUNCATE = 76 => sys_truncate(args[..2]); SYS_FTRUNCATE = 77 => sys_ftruncate(args[..2]); SYS_GETDENTS = 78 => sys_getdents(args[..3]); diff --git a/kernel/aster-nix/src/syscall/fsync.rs b/kernel/aster-nix/src/syscall/fsync.rs index 270defb46..c73740617 100644 --- a/kernel/aster-nix/src/syscall/fsync.rs +++ b/kernel/aster-nix/src/syscall/fsync.rs @@ -18,6 +18,22 @@ pub fn sys_fsync(fd: FileDesc) -> Result { .ok_or(Error::with_message(Errno::EINVAL, "not inode"))?; inode_handle.dentry().clone() }; - dentry.sync()?; + dentry.sync_all()?; + Ok(SyscallReturn::Return(0)) +} + +pub fn sys_fdatasync(fd: FileDesc) -> Result { + debug!("fd = {}", fd); + + let dentry = { + let current = current!(); + let file_table = current.file_table().lock(); + let file = file_table.get_file(fd)?; + let inode_handle = file + .downcast_ref::() + .ok_or(Error::with_message(Errno::EINVAL, "not inode"))?; + inode_handle.dentry().clone() + }; + dentry.sync_data()?; Ok(SyscallReturn::Return(0)) } diff --git a/regression/apps/Makefile b/regression/apps/Makefile index bfe128d51..82a60d0c8 100644 --- a/regression/apps/Makefile +++ b/regression/apps/Makefile @@ -17,6 +17,7 @@ TEST_APPS := \ epoll \ eventfd2 \ execve \ + fdatasync \ file_io \ fork \ fork_c \ diff --git a/regression/apps/fdatasync/Makefile b/regression/apps/fdatasync/Makefile new file mode 100644 index 000000000..cd19ae20b --- /dev/null +++ b/regression/apps/fdatasync/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: MPL-2.0 + +include ../test_common.mk + +EXTRA_C_FLAGS := -static diff --git a/regression/apps/fdatasync/fdatasync.c b/regression/apps/fdatasync/fdatasync.c new file mode 100644 index 000000000..40744fb81 --- /dev/null +++ b/regression/apps/fdatasync/fdatasync.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MPL-2.0 + +#include +#include +#include +#include +#include + +void test_fdatasync_on_fs(const char *directory) +{ + char filepath[256]; + snprintf(filepath, sizeof(filepath), "%s/test_fdatasync.txt", + directory); + + int fd = + open(filepath, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (fd == -1) { + perror("Error opening file"); + exit(EXIT_FAILURE); + } + + char *data = "Hello, fdatasync test!\n"; + if (write(fd, data, strlen(data)) != strlen(data)) { + perror("Error writing data"); + close(fd); + exit(EXIT_FAILURE); + } + + if (fdatasync(fd) == -1) { + perror("Error syncing data"); + close(fd); + exit(EXIT_FAILURE); + } + + printf("Data written and synced on %s\n", directory); + close(fd); +} + +int main(int argc, char **argv) +{ + if (argc != 2) { + printf("Usage: %s \n", argv[0]); + return EXIT_FAILURE; + } + + test_fdatasync_on_fs(argv[1]); + + return EXIT_SUCCESS; +} diff --git a/regression/apps/scripts/ext2.sh b/regression/apps/scripts/ext2.sh deleted file mode 100755 index 001d30cd8..000000000 --- a/regression/apps/scripts/ext2.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh - -# SPDX-License-Identifier: MPL-2.0 - -set -e -set -x - -check_file_size() { - local file_name="$1" - local expected_size="$2" - - if [ ! -f "$file_name" ]; then - echo "Error: File does not exist." - return 1 - fi - - actual_size=$(du -b "$file_name" | cut -f1) - - if [ "$actual_size" -eq "$expected_size" ]; then - return 0 - else - echo "Error: File size is incorrect: expected ${expected_size}, but got ${actual_size}." - return 1 - fi -} - -EXT2_DIR=/ext2 -cd ${EXT2_DIR} - -echo "Start ext2 fs test......" - -# Test case for the big file feature -for i in $(seq 1 10); do - truncate -s 500M test_file.txt - check_file_size test_file.txt $((500 * 1024 * 1024)) - truncate -s 2K test_file.txt - check_file_size test_file.txt $((2 * 1024)) -done - -# Clean up -rm -f test_file.txt -sync - -echo "All ext2 fs test passed." \ No newline at end of file diff --git a/regression/apps/scripts/fs.sh b/regression/apps/scripts/fs.sh new file mode 100755 index 000000000..7132142da --- /dev/null +++ b/regression/apps/scripts/fs.sh @@ -0,0 +1,62 @@ +#!/bin/sh + +# SPDX-License-Identifier: MPL-2.0 + +set -e +set -x + +check_file_size() { + local file_name="$1" + local expected_size="$2" + + if [ ! -f "$file_name" ]; then + echo "Error: File does not exist." + return 1 + fi + + actual_size=$(du -b "$file_name" | cut -f1) + + if [ "$actual_size" -eq "$expected_size" ]; then + return 0 + else + echo "Error: File size is incorrect: expected ${expected_size}, but got ${actual_size}." + return 1 + fi +} + +test_ext2() { + local ext2_dir="$1" + local test_file="$2" + + cd ${ext2_dir} + + # Test case for the big file feature + for i in $(seq 1 10); do + truncate -s 500M ${test_file} + check_file_size ${test_file} $((500 * 1024 * 1024)) + truncate -s 2K ${test_file} + check_file_size ${test_file} $((2 * 1024)) + done + + # Clean up + rm -f ${test_file} + sync + cd - +} + +test_fdatasync() { + fdatasync/fdatasync / + rm -f /test_fdatasync.txt + fdatasync/fdatasync /ext2 + rm -f /ext2/test_fdatasync.txt + fdatasync/fdatasync /exfat + rm -f /exfat/test_fdatasync.txt +} + +echo "Start ext2 fs test......" +test_ext2 "/ext2" "test_file.txt" +echo "All ext2 fs test passed." + +echo "Start fdatasync test......" +test_fdatasync +echo "All fdatasync test passed." \ No newline at end of file diff --git a/regression/apps/scripts/run_regression_test.sh b/regression/apps/scripts/run_regression_test.sh index b07b234ee..3b30b0dc3 100755 --- a/regression/apps/scripts/run_regression_test.sh +++ b/regression/apps/scripts/run_regression_test.sh @@ -8,7 +8,7 @@ SCRIPT_DIR=/regression cd ${SCRIPT_DIR} ./shell_cmd.sh -./ext2.sh +./fs.sh ./process.sh ./network.sh ./test_epoll_pwait.sh