mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-21 00:06:34 +00:00
Add sys_fdatasync and sync_data
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
5edc110f9d
commit
212dd562a0
@ -95,7 +95,7 @@ provided by Linux on x86-64 architecture.
|
|||||||
| 72 | fcntl | ✅ |
|
| 72 | fcntl | ✅ |
|
||||||
| 73 | flock | ❌ |
|
| 73 | flock | ❌ |
|
||||||
| 74 | fsync | ✅ |
|
| 74 | fsync | ✅ |
|
||||||
| 75 | fdatasync | ❌ |
|
| 75 | fdatasync | ✅ |
|
||||||
| 76 | truncate | ✅ |
|
| 76 | truncate | ✅ |
|
||||||
| 77 | ftruncate | ✅ |
|
| 77 | ftruncate | ✅ |
|
||||||
| 78 | getdents | ✅ |
|
| 78 | getdents | ✅ |
|
||||||
|
@ -135,7 +135,7 @@ impl ExfatFS {
|
|||||||
if inode.is_deleted() {
|
if inode.is_deleted() {
|
||||||
inode.reclaim_space()?;
|
inode.reclaim_space()?;
|
||||||
} else {
|
} else {
|
||||||
inode.sync()?;
|
inode.sync_all()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.inodes.write().remove(&hash);
|
self.inodes.write().remove(&hash);
|
||||||
@ -392,7 +392,7 @@ impl PageCacheBackend for ExfatFS {
|
|||||||
impl FileSystem for ExfatFS {
|
impl FileSystem for ExfatFS {
|
||||||
fn sync(&self) -> Result<()> {
|
fn sync(&self) -> Result<()> {
|
||||||
for inode in self.inodes.read().values() {
|
for inode in self.inodes.read().values() {
|
||||||
inode.sync()?;
|
inode.sync_all()?;
|
||||||
}
|
}
|
||||||
self.meta_cache.evict_range(0..self.fs_size())?;
|
self.meta_cache.evict_range(0..self.fs_size())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -573,9 +573,14 @@ impl ExfatInodeInner {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sync(&self, fs_guard: &MutexGuard<()>) -> Result<()> {
|
fn sync_data(&self, fs_guard: &MutexGuard<()>) -> Result<()> {
|
||||||
self.page_cache.evict_range(0..self.size)?;
|
self.page_cache.evict_range(0..self.size)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync_all(&self, fs_guard: &MutexGuard<()>) -> Result<()> {
|
||||||
self.sync_metadata(fs_guard)?;
|
self.sync_metadata(fs_guard)?;
|
||||||
|
self.sync_data(fs_guard)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1328,7 +1333,7 @@ impl Inode for ExfatInode {
|
|||||||
if inner.is_sync() {
|
if inner.is_sync() {
|
||||||
let fs = inner.fs();
|
let fs = inner.fs();
|
||||||
let fs_guard = fs.lock();
|
let fs_guard = fs.lock();
|
||||||
inner.sync(&fs_guard)?;
|
inner.sync_all(&fs_guard)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(buf.len())
|
Ok(buf.len())
|
||||||
@ -1435,7 +1440,7 @@ impl Inode for ExfatInode {
|
|||||||
let inner = self.inner.read();
|
let inner = self.inner.read();
|
||||||
|
|
||||||
if inner.is_sync() {
|
if inner.is_sync() {
|
||||||
inner.sync(&fs_guard)?;
|
inner.sync_all(&fs_guard)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
@ -1530,7 +1535,7 @@ impl Inode for ExfatInode {
|
|||||||
|
|
||||||
let inner = self.inner.read();
|
let inner = self.inner.read();
|
||||||
if inner.is_sync() {
|
if inner.is_sync() {
|
||||||
inner.sync(&fs_guard)?;
|
inner.sync_all(&fs_guard)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -1567,7 +1572,7 @@ impl Inode for ExfatInode {
|
|||||||
let inner = self.inner.read();
|
let inner = self.inner.read();
|
||||||
// Sync this inode since size has changed.
|
// Sync this inode since size has changed.
|
||||||
if inner.is_sync() {
|
if inner.is_sync() {
|
||||||
inner.sync(&fs_guard)?;
|
inner.sync_all(&fs_guard)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -1656,9 +1661,9 @@ impl Inode for ExfatInode {
|
|||||||
// Sync
|
// Sync
|
||||||
if self.inner.read().is_sync() || target_.inner.read().is_sync() {
|
if self.inner.read().is_sync() || target_.inner.read().is_sync() {
|
||||||
// TODO: what if fs crashed between syncing?
|
// TODO: what if fs crashed between syncing?
|
||||||
old_inode.inner.read().sync(&fs_guard)?;
|
old_inode.inner.read().sync_all(&fs_guard)?;
|
||||||
target_.inner.read().sync(&fs_guard)?;
|
target_.inner.read().sync_all(&fs_guard)?;
|
||||||
self.inner.read().sync(&fs_guard)?;
|
self.inner.read().sync_all(&fs_guard)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -1675,11 +1680,20 @@ impl Inode for ExfatInode {
|
|||||||
return_errno_with_message!(Errno::EINVAL, "unsupported operation")
|
return_errno_with_message!(Errno::EINVAL, "unsupported operation")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sync(&self) -> Result<()> {
|
fn sync_all(&self) -> Result<()> {
|
||||||
let inner = self.inner.read();
|
let inner = self.inner.read();
|
||||||
let fs = inner.fs();
|
let fs = inner.fs();
|
||||||
let fs_guard = fs.lock();
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -176,10 +176,14 @@ impl Inode for Ext2Inode {
|
|||||||
Err(Error::new(Errno::EINVAL))
|
Err(Error::new(Errno::EINVAL))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sync(&self) -> Result<()> {
|
fn sync_all(&self) -> Result<()> {
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sync_data(&self) -> Result<()> {
|
||||||
|
self.sync_data()
|
||||||
|
}
|
||||||
|
|
||||||
fn fs(&self) -> Arc<dyn FileSystem> {
|
fn fs(&self) -> Arc<dyn FileSystem> {
|
||||||
self.fs()
|
self.fs()
|
||||||
}
|
}
|
||||||
|
@ -299,7 +299,8 @@ impl Dentry_ {
|
|||||||
#[inherit_methods(from = "self.inode")]
|
#[inherit_methods(from = "self.inode")]
|
||||||
impl Dentry_ {
|
impl Dentry_ {
|
||||||
pub fn fs(&self) -> Arc<dyn FileSystem>;
|
pub fn fs(&self) -> Arc<dyn FileSystem>;
|
||||||
pub fn sync(&self) -> Result<()>;
|
pub fn sync_all(&self) -> Result<()>;
|
||||||
|
pub fn sync_data(&self) -> Result<()>;
|
||||||
pub fn metadata(&self) -> Metadata;
|
pub fn metadata(&self) -> Metadata;
|
||||||
pub fn type_(&self) -> InodeType;
|
pub fn type_(&self) -> InodeType;
|
||||||
pub fn mode(&self) -> Result<InodeMode>;
|
pub fn mode(&self) -> Result<InodeMode>;
|
||||||
@ -680,7 +681,8 @@ impl Dentry {
|
|||||||
#[inherit_methods(from = "self.inner")]
|
#[inherit_methods(from = "self.inner")]
|
||||||
impl Dentry {
|
impl Dentry {
|
||||||
pub fn fs(&self) -> Arc<dyn FileSystem>;
|
pub fn fs(&self) -> Arc<dyn FileSystem>;
|
||||||
pub fn sync(&self) -> Result<()>;
|
pub fn sync_all(&self) -> Result<()>;
|
||||||
|
pub fn sync_data(&self) -> Result<()>;
|
||||||
pub fn metadata(&self) -> Metadata;
|
pub fn metadata(&self) -> Metadata;
|
||||||
pub fn type_(&self) -> InodeType;
|
pub fn type_(&self) -> InodeType;
|
||||||
pub fn mode(&self) -> Result<InodeMode>;
|
pub fn mode(&self) -> Result<InodeMode>;
|
||||||
|
@ -183,10 +183,6 @@ impl<D: DirOps + 'static> Inode for ProcDir<D> {
|
|||||||
Err(Error::new(Errno::EPERM))
|
Err(Error::new(Errno::EPERM))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sync(&self) -> Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_dentry_cacheable(&self) -> bool {
|
fn is_dentry_cacheable(&self) -> bool {
|
||||||
!self.common.is_volatile()
|
!self.common.is_volatile()
|
||||||
}
|
}
|
||||||
|
@ -95,10 +95,6 @@ impl<F: FileOps + 'static> Inode for ProcFile<F> {
|
|||||||
Err(Error::new(Errno::EPERM))
|
Err(Error::new(Errno::EPERM))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sync(&self) -> Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_dentry_cacheable(&self) -> bool {
|
fn is_dentry_cacheable(&self) -> bool {
|
||||||
!self.common.is_volatile()
|
!self.common.is_volatile()
|
||||||
}
|
}
|
||||||
|
@ -87,10 +87,6 @@ impl<S: SymOps + 'static> Inode for ProcSym<S> {
|
|||||||
Err(Error::new(Errno::EPERM))
|
Err(Error::new(Errno::EPERM))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sync(&self) -> Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_dentry_cacheable(&self) -> bool {
|
fn is_dentry_cacheable(&self) -> bool {
|
||||||
!self.common.is_volatile()
|
!self.common.is_volatile()
|
||||||
}
|
}
|
||||||
|
@ -993,11 +993,6 @@ impl Inode for RamInode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sync(&self) -> Result<()> {
|
|
||||||
// do nothing
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents {
|
fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents {
|
||||||
if let Some(device) = self.node.read().inner.as_device() {
|
if let Some(device) = self.node.read().inner.as_device() {
|
||||||
device.poll(mask, poller)
|
device.poll(mask, poller)
|
||||||
|
@ -340,7 +340,11 @@ pub trait Inode: Any + Sync + Send {
|
|||||||
Err(Error::new(Errno::EISDIR))
|
Err(Error::new(Errno::EISDIR))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sync(&self) -> Result<()> {
|
fn sync_all(&self) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync_data(&self) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ use crate::syscall::{
|
|||||||
exit_group::sys_exit_group,
|
exit_group::sys_exit_group,
|
||||||
fcntl::sys_fcntl,
|
fcntl::sys_fcntl,
|
||||||
fork::sys_fork,
|
fork::sys_fork,
|
||||||
fsync::sys_fsync,
|
fsync::{sys_fdatasync, sys_fsync},
|
||||||
futex::sys_futex,
|
futex::sys_futex,
|
||||||
getcwd::sys_getcwd,
|
getcwd::sys_getcwd,
|
||||||
getdents64::{sys_getdents, sys_getdents64},
|
getdents64::{sys_getdents, sys_getdents64},
|
||||||
@ -182,6 +182,7 @@ impl_syscall_nums_and_dispatch_fn! {
|
|||||||
SYS_UNAME = 63 => sys_uname(args[..1]);
|
SYS_UNAME = 63 => sys_uname(args[..1]);
|
||||||
SYS_FCNTL = 72 => sys_fcntl(args[..3]);
|
SYS_FCNTL = 72 => sys_fcntl(args[..3]);
|
||||||
SYS_FSYNC = 74 => sys_fsync(args[..1]);
|
SYS_FSYNC = 74 => sys_fsync(args[..1]);
|
||||||
|
SYS_FDATASYNC = 75 => sys_fdatasync(args[..1]);
|
||||||
SYS_TRUNCATE = 76 => sys_truncate(args[..2]);
|
SYS_TRUNCATE = 76 => sys_truncate(args[..2]);
|
||||||
SYS_FTRUNCATE = 77 => sys_ftruncate(args[..2]);
|
SYS_FTRUNCATE = 77 => sys_ftruncate(args[..2]);
|
||||||
SYS_GETDENTS = 78 => sys_getdents(args[..3]);
|
SYS_GETDENTS = 78 => sys_getdents(args[..3]);
|
||||||
|
@ -18,6 +18,22 @@ pub fn sys_fsync(fd: FileDesc) -> Result<SyscallReturn> {
|
|||||||
.ok_or(Error::with_message(Errno::EINVAL, "not inode"))?;
|
.ok_or(Error::with_message(Errno::EINVAL, "not inode"))?;
|
||||||
inode_handle.dentry().clone()
|
inode_handle.dentry().clone()
|
||||||
};
|
};
|
||||||
dentry.sync()?;
|
dentry.sync_all()?;
|
||||||
|
Ok(SyscallReturn::Return(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_fdatasync(fd: FileDesc) -> Result<SyscallReturn> {
|
||||||
|
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::<InodeHandle>()
|
||||||
|
.ok_or(Error::with_message(Errno::EINVAL, "not inode"))?;
|
||||||
|
inode_handle.dentry().clone()
|
||||||
|
};
|
||||||
|
dentry.sync_data()?;
|
||||||
Ok(SyscallReturn::Return(0))
|
Ok(SyscallReturn::Return(0))
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ TEST_APPS := \
|
|||||||
epoll \
|
epoll \
|
||||||
eventfd2 \
|
eventfd2 \
|
||||||
execve \
|
execve \
|
||||||
|
fdatasync \
|
||||||
file_io \
|
file_io \
|
||||||
fork \
|
fork \
|
||||||
fork_c \
|
fork_c \
|
||||||
|
5
regression/apps/fdatasync/Makefile
Normal file
5
regression/apps/fdatasync/Makefile
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
include ../test_common.mk
|
||||||
|
|
||||||
|
EXTRA_C_FLAGS := -static
|
49
regression/apps/fdatasync/fdatasync.c
Normal file
49
regression/apps/fdatasync/fdatasync.c
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
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 <directory>\n", argv[0]);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
test_fdatasync_on_fs(argv[1]);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
@ -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."
|
|
62
regression/apps/scripts/fs.sh
Executable file
62
regression/apps/scripts/fs.sh
Executable file
@ -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."
|
@ -8,7 +8,7 @@ SCRIPT_DIR=/regression
|
|||||||
cd ${SCRIPT_DIR}
|
cd ${SCRIPT_DIR}
|
||||||
|
|
||||||
./shell_cmd.sh
|
./shell_cmd.sh
|
||||||
./ext2.sh
|
./fs.sh
|
||||||
./process.sh
|
./process.sh
|
||||||
./network.sh
|
./network.sh
|
||||||
./test_epoll_pwait.sh
|
./test_epoll_pwait.sh
|
||||||
|
Reference in New Issue
Block a user