Skip to content
27 changes: 26 additions & 1 deletion components/rsext4/src/blockdev/cached_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,12 @@ impl<B: BlockDevice> BlockDev<B> {
}

/// Writes `count` blocks directly from `buffer` (bypasses the cache).
///
/// After writing, any cache entries for the written block range are
/// invalidated so that a subsequent `read_block` does not return stale
/// (pre-write) data. Without this, directory-entry modifications made
/// via `write_blocks` (DataBlockCache → `write_block_static`) can be
/// invisible to path lookups that go through `read_block`.
pub fn write_blocks(
&mut self,
buffer: &[u8],
Expand All @@ -171,7 +177,26 @@ impl<B: BlockDevice> BlockDev<B> {
return Err(Ext4Error::buffer_too_small(buffer.len(), required_size));
}

self.dev.write(buffer, block_id, count)
self.dev.write(buffer, block_id, count)?;

// Invalidate cache entries that overlap with the written block range.
// Otherwise a subsequent `read_block` hit would return the old data.
for entry in self.entries.iter_mut() {
if let Some(id) = entry.block_id {
for off in 0..count {
if let Ok(written) = block_id.checked_add(off) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cargo clippy -D warnings 报错:嵌套 if let Ok(written) = block_id.checked_add(off) + if id == written 应合并为 if let Ok(written) = block_id.checked_add(off) && id == written(collapsible_if lint)。

此外,@yeanwang666 提出的问题也值得注意:如果 overlapping dirty entries 不可能产生,建议添加 debug_assert! 说明不变量;如果可能,当前丢弃 dirty entry 但不做数据回写需要明确的理由。

if id == written {
entry.block_id = None;
entry.dirty = false;
entry.referenced = false;
Comment on lines +189 to +191
break;
}
}
}
}
}
Comment on lines +184 to +197

Ok(())
}

/// Returns the active buffer (read-only view of the last accessed block).
Expand Down
21 changes: 21 additions & 0 deletions os/StarryOS/kernel/src/syscall/io_mpx/epoll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,27 @@ fn do_epoll_wait(
Ok(count)
}

pub fn sys_epoll_wait(
epfd: i32,
events: UserPtr<epoll_event>,
maxevents: i32,
timeout: i32,
) -> AxResult<isize> {
let timeout = match timeout {
-1 => None,
t if t >= 0 => Some(Duration::from_millis(t as u64)),
_ => return Err(AxError::InvalidInput),
};
do_epoll_wait(
epfd,
events,
maxevents,
timeout,
UserConstPtr::<SignalSet>::default(),
0,
)
}

pub fn sys_epoll_pwait(
epfd: i32,
events: UserPtr<epoll_event>,
Expand Down
33 changes: 29 additions & 4 deletions os/StarryOS/kernel/src/syscall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,12 @@ pub fn handle_syscall(uctx: &mut UserContext) {
uctx.arg2() as _,
uctx.arg3().into(),
),
Sysno::epoll_wait => sys_epoll_wait(
uctx.arg0() as _,
uctx.arg1().into(),
uctx.arg2() as _,
uctx.arg3() as _,
),
Sysno::epoll_pwait => sys_epoll_pwait(
uctx.arg0() as _,
uctx.arg1().into(),
Expand Down Expand Up @@ -804,12 +810,31 @@ pub fn handle_syscall(uctx: &mut UserContext) {

// dummy fds
Sysno::userfaultfd
| Sysno::io_uring_setup
| Sysno::fsopen
| Sysno::fspick
| Sysno::open_tree
| Sysno::memfd_secret => sys_dummy_fd(sysno),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cargo fmt --check 失败:Sysno::userfaultfdSysno::memfd_secret 应合并为一行 Sysno::userfaultfd | Sysno::memfd_secret => sys_dummy_fd(sysno),。请运行 cargo fmt 修复。


// New mount API — return ENOSYS so mount(8) falls back to
// the traditional mount(2) syscall (which is implemented).
Sysno::fsopen | Sysno::fspick | Sysno::open_tree => {
warn!("new mount API not supported (sysno={sysno}), returning ENOSYS for fallback");
Err(AxError::Unsupported)
}

// io_uring: fake enough support so tokio 1.x creates its I/O
// driver without panicking, then falls back to blocking I/O.
// io_uring_setup returns a dummy fd (tokio thinks io_uring is
// available), io_uring_enter/register return 0 (no events /
// success). Without this, tokio calls io_uring_enter on the
// dummy fd, gets ENOSYS, and panics — corrupting cargo state.
Sysno::io_uring_setup => {
warn!("io_uring_setup: returning dummy fd for compatibility");
sys_dummy_fd(sysno)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

io_uring 的处理方式存在 ABI 语义问题(同 @yeanwang666 的意见):dummy fd + 恒返回 0 向用户态伪造 io_uring 可用,违反 Linux ABI。建议优先返回 ENOSYS 让运行时走回退路径,或实现带 fd 验证的伪 io_uring 类型。至少需要为 tokio/cargo 场景添加回归测试来证明该方案的稳定性。

}
Sysno::io_uring_enter | Sysno::io_uring_register => {
// Return 0 = "0 completions" / "successful registration"
// so tokio's io_uring driver keeps polling without errors.
Ok(0)
}
Comment on lines +832 to +836

#[cfg(feature = "ebpf")]
Sysno::bpf => crate::ebpf::sys_bpf(uctx.arg0() as _, uctx.arg1(), uctx.arg2() as _),
#[cfg(feature = "ebpf")]
Expand Down
29 changes: 20 additions & 9 deletions os/arceos/modules/axfs-ng/src/fs/ext4/rsext4/fs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use alloc::{boxed::Box, sync::Arc};
use core::cell::OnceCell;

use ax_kspin::{SpinNoIrq as Mutex, SpinNoIrqGuard as MutexGuard};
use ax_hal;
use ax_sync::{Mutex, MutexGuard};
use axfs_ng_vfs::{
DirEntry, DirNode, Filesystem, FilesystemOps, Reference, StatFs, VfsResult, path::MAX_NAME_LEN,
};
Expand Down Expand Up @@ -63,18 +64,28 @@ impl Ext4Filesystem {

/// Locks the shared rsext4 state.
///
/// rsext4 operations may allocate, flush caches, commit journal state, and
/// call into the block device while this guard is held. The current rootfs
/// setup can also run in early atomic contexts where a blocking mutex trips
/// `might_sleep()`, so use `SpinNoIrq` instead of the older
/// `SpinNoPreempt` to close same-CPU IRQ reentry without changing the
/// boot-time calling contract.
/// In task context (IRQs enabled) this uses the blocking
/// `ax_sync::Mutex::lock`, sleeping on contention and freeing the
/// CPU for other tasks. During boot / shutdown IRQs may still be
/// disabled — fall back to spinning with `try_lock` so that
/// `might_sleep()` does not panic.
pub(crate) fn lock(&self) -> MutexGuard<'_, Ext4State> {
self.inner.lock()
if ax_hal::asm::irqs_enabled() {
// Task context — sleep on contention.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SpinNoIrq 替换为 ax_sync::Mutex + irqs_enabled() 判断是一个并发策略的重大变更,PR 正文未提及。该变更影响并发文件系统操作和 shutdown 路径,建议拆分为单独 PR 并说明理由,或在当前 PR 中添加充分的并发测试覆盖。

self.inner.lock()
} else {
// Atomic context (boot / shutdown) — spin.
loop {
if let Some(guard) = self.inner.try_lock() {
return guard;
}
core::hint::spin_loop();
}
}
}

pub(crate) fn sync_to_disk(&self) -> VfsResult<()> {
let mut state = self.inner.lock();
let mut state = self.lock();
let (fs, dev) = state.split();
fs.datablock_cache.flush_all(dev).map_err(into_vfs_err)?;
fs.bitmap_cache.flush_all(dev).map_err(into_vfs_err)?;
Expand Down
Loading