From 3e32a38316a9b134bea3121fb89887c41eb93dc8 Mon Sep 17 00:00:00 2001 From: Cautreoxit Date: Sun, 1 Jun 2025 18:11:06 +0800 Subject: [PATCH] Add sys_close_range --- docs/src/kernel/linux-compatibility.md | 1 + .../src/process/posix_thread/thread_local.rs | 5 ++ kernel/src/syscall/arch/riscv.rs | 3 +- kernel/src/syscall/arch/x86.rs | 3 +- kernel/src/syscall/close.rs | 71 ++++++++++++++++++- ostd/src/sync/rwarc.rs | 8 +++ test/syscall_test/ltp/testcases/all.txt | 2 +- 7 files changed, 89 insertions(+), 4 deletions(-) diff --git a/docs/src/kernel/linux-compatibility.md b/docs/src/kernel/linux-compatibility.md index 2523d0a6e..c7f927b54 100644 --- a/docs/src/kernel/linux-compatibility.md +++ b/docs/src/kernel/linux-compatibility.md @@ -342,6 +342,7 @@ provided by Linux on x86-64 architecture. | 328 | pwritev2 | ✅ | | 332 | statx | ✅ | | 435 | clone3 | ✅ | +| 436 | close_range | ✅ | | 439 | faccessat2 | ✅ | | 441 | epoll_pwait2 | ✅ | diff --git a/kernel/src/process/posix_thread/thread_local.rs b/kernel/src/process/posix_thread/thread_local.rs index 591c11380..5d2ea69ea 100644 --- a/kernel/src/process/posix_thread/thread_local.rs +++ b/kernel/src/process/posix_thread/thread_local.rs @@ -116,6 +116,11 @@ impl FileTableRefMut<'_> { pub(super) fn remove(&mut self) { *self.0 = None; } + + /// Replaces the file table with a new one, returning the old one. + pub fn replace(&mut self, new_table: Option>) -> Option> { + core::mem::replace(&mut *self.0, new_table) + } } /// A trait to provide the `as_thread_local` method for tasks. diff --git a/kernel/src/syscall/arch/riscv.rs b/kernel/src/syscall/arch/riscv.rs index 1b8db7e8c..67265e34b 100644 --- a/kernel/src/syscall/arch/riscv.rs +++ b/kernel/src/syscall/arch/riscv.rs @@ -13,7 +13,7 @@ use crate::syscall::{ chroot::sys_chroot, clock_gettime::sys_clock_gettime, clone::{sys_clone, sys_clone3}, - close::sys_close, + close::{sys_close, sys_close_range}, connect::sys_connect, dup::{sys_dup, sys_dup3}, epoll::{sys_epoll_create1, sys_epoll_ctl, sys_epoll_pwait, sys_epoll_pwait2}, @@ -302,6 +302,7 @@ impl_syscall_nums_and_dispatch_fn! { SYS_UTIMENSAT = 412 => sys_utimensat(args[..4]); SYS_SEMTIMEDOP = 420 => sys_semtimedop(args[..4]); SYS_CLONE3 = 435 => sys_clone3(args[..2], &user_ctx); + SYS_CLOSE_RANGE = 436 => sys_close_range(args[..3]); SYS_FACCESSAT2 = 439 => sys_faccessat2(args[..4]); SYS_EPOLL_PWAIT2 = 441 => sys_epoll_pwait2(args[..5]); } diff --git a/kernel/src/syscall/arch/x86.rs b/kernel/src/syscall/arch/x86.rs index 9433102ca..c4e8060e7 100644 --- a/kernel/src/syscall/arch/x86.rs +++ b/kernel/src/syscall/arch/x86.rs @@ -15,7 +15,7 @@ use crate::syscall::{ chroot::sys_chroot, clock_gettime::sys_clock_gettime, clone::{sys_clone, sys_clone3}, - close::sys_close, + close::{sys_close, sys_close_range}, connect::sys_connect, dup::{sys_dup, sys_dup2, sys_dup3}, epoll::{ @@ -371,6 +371,7 @@ impl_syscall_nums_and_dispatch_fn! { SYS_PWRITEV2 = 328 => sys_pwritev2(args[..5]); SYS_STATX = 332 => sys_statx(args[..5]); SYS_CLONE3 = 435 => sys_clone3(args[..2], &user_ctx); + SYS_CLOSE_RANGE = 436 => sys_close_range(args[..3]); SYS_FACCESSAT2 = 439 => sys_faccessat2(args[..4]); SYS_EPOLL_PWAIT2 = 441 => sys_epoll_pwait2(args[..5]); } diff --git a/kernel/src/syscall/close.rs b/kernel/src/syscall/close.rs index 12f1b2b9f..7ceb173d2 100644 --- a/kernel/src/syscall/close.rs +++ b/kernel/src/syscall/close.rs @@ -1,7 +1,20 @@ // SPDX-License-Identifier: MPL-2.0 +use bitflags::bitflags; +use ostd::sync::RwArc; + use super::SyscallReturn; -use crate::{fs::file_table::FileDesc, prelude::*}; +use crate::{ + fs::file_table::{FdFlags, FileDesc}, + prelude::*, +}; + +bitflags! { + struct CloseRangeFlags: u32 { + const UNSHARE = 1 << 1; + const CLOEXEC = 1 << 2; + } +} pub fn sys_close(fd: FileDesc, ctx: &Context) -> Result { debug!("fd = {}", fd); @@ -29,3 +42,59 @@ pub fn sys_close(fd: FileDesc, ctx: &Context) -> Result { // . Ok(SyscallReturn::Return(0)) } + +pub fn sys_close_range( + first: u32, + last: u32, + raw_flags: u32, + ctx: &Context, +) -> Result { + debug!("first = {}, last = {}, flags = {}", first, last, raw_flags); + + if last < first { + return_errno!(Errno::EINVAL); + } + + let flags = CloseRangeFlags::from_bits(raw_flags).ok_or_else(|| Error::new(Errno::EINVAL))?; + + let original_table = ctx.thread_local.borrow_file_table().unwrap().clone(); + + let file_table = if flags.contains(CloseRangeFlags::UNSHARE) { + let new_table = RwArc::new(original_table.get_cloned()); + let _ = ctx + .thread_local + .borrow_file_table_mut() + .replace(Some(new_table.clone())); + new_table + } else { + original_table + }; + + let mut files_to_drop = Vec::new(); + + { + let mut file_table_locked = file_table.write(); + + let table_len = file_table_locked.len() as u32; + if first >= table_len { + return Ok(SyscallReturn::Return(0)); + } + let actual_last = last.min(table_len - 1); + + for fd in first..=actual_last { + let fd = fd as FileDesc; + + if flags.contains(CloseRangeFlags::CLOEXEC) { + if let Ok(entry) = file_table_locked.get_entry_mut(fd) { + entry.set_flags(entry.flags() | FdFlags::CLOEXEC); + } + } else if let Some(file) = file_table_locked.close_file(fd) { + files_to_drop.push(file); + } + } + } + + drop(files_to_drop); + + Ok(SyscallReturn::Return(0)) +} diff --git a/ostd/src/sync/rwarc.rs b/ostd/src/sync/rwarc.rs index c89c622d7..8895cb491 100644 --- a/ostd/src/sync/rwarc.rs +++ b/ostd/src/sync/rwarc.rs @@ -98,6 +98,14 @@ impl Drop for RwArc { } } +impl RwArc { + /// Returns the contained value by cloning it. + pub fn get_cloned(&self) -> T { + let guard = self.read(); + guard.clone() + } +} + impl RoArc { /// Acquires the read lock for immutable access. pub fn read(&self) -> RwLockReadGuard { diff --git a/test/syscall_test/ltp/testcases/all.txt b/test/syscall_test/ltp/testcases/all.txt index 5f520717c..0120e02d5 100644 --- a/test/syscall_test/ltp/testcases/all.txt +++ b/test/syscall_test/ltp/testcases/all.txt @@ -133,7 +133,7 @@ close01 close02 # close_range01 -# close_range02 +close_range02 confstr01