From 226ea2865ce87d3ecf59b0f326eaecdc0c59326b Mon Sep 17 00:00:00 2001 From: Tao Su Date: Thu, 14 Aug 2025 03:23:46 +0000 Subject: [PATCH] Resolve `semget01` failure by fixing key limit and adding `IPC_STAT` --- .../inter-process-communication.md | 11 +++- kernel/src/ipc/semaphore/system_v/sem_set.rs | 51 +++++++++++++++++++ kernel/src/syscall/semctl.rs | 6 +++ kernel/src/syscall/semget.rs | 4 +- test/src/syscall/ltp/testcases/all.txt | 2 +- 5 files changed, 69 insertions(+), 5 deletions(-) diff --git a/docs/src/kernel/linux-compatibility/limitations-on-system-calls/inter-process-communication.md b/docs/src/kernel/linux-compatibility/limitations-on-system-calls/inter-process-communication.md index 16c34107e..171d58ffd 100644 --- a/docs/src/kernel/linux-compatibility/limitations-on-system-calls/inter-process-communication.md +++ b/docs/src/kernel/linux-compatibility/limitations-on-system-calls/inter-process-communication.md @@ -7,7 +7,7 @@ futex, set_robust_list, and get_robust_list under this category. --> -## `System V semaphore` +## System V semaphore ### `semget` @@ -80,10 +80,17 @@ semctl( semnum, cmd = GETVAL | GETPID | GETNCNT | GETZCNT ); + +// Retrieve a copy of the `semid_ds` kernel structure for the specified semaphore set +semctl( + semid, + semnum, + cmd = IPC_STAT, + arg +); ``` Unsupported commands: -* `IPC_STAT` * `IPC_INFO` * `SEM_INFO` * `SEM_STAT` diff --git a/kernel/src/ipc/semaphore/system_v/sem_set.rs b/kernel/src/ipc/semaphore/system_v/sem_set.rs index fbd9b1cc0..cd64ad511 100644 --- a/kernel/src/ipc/semaphore/system_v/sem_set.rs +++ b/kernel/src/ipc/semaphore/system_v/sem_set.rs @@ -51,6 +51,37 @@ pub struct SemaphoreSet { sem_otime: AtomicU64, } +// https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/ipcbuf.h +#[repr(C)] +#[derive(Debug, Copy, Clone, Default, Pod)] +pub struct IpcPerm { + key: u32, + uid: u32, + gid: u32, + cuid: u32, + cgid: u32, + mode: u16, + _pad1: u16, + seq: u16, + _pad2: u16, + _unused1: u64, + _unused2: u64, +} + +// https://github.com/torvalds/linux/blob/master/arch/x86/include/uapi/asm/sembuf.h +#[repr(C)] +#[derive(Debug, Copy, Clone, Default, Pod)] +pub struct SemidDs { + sem_perm: IpcPerm, + sem_otime: u64, + _unused1: u64, + sem_ctime: u64, + _unused2: u64, + sem_nsems: u64, + _unused3: u64, + _unused4: u64, +} + #[derive(Debug)] pub(super) struct SemSetInner { /// Semaphores @@ -196,6 +227,26 @@ impl SemaphoreSet { }), }) } + + pub fn semid_ds(&self) -> SemidDs { + let ipc_perm = IpcPerm { + key: self.permission.key() as u32, + uid: self.permission.uid().into(), + gid: self.permission.gid().into(), + cuid: self.permission.cuid().into(), + cgid: self.permission.cguid().into(), + mode: self.permission.mode(), + ..IpcPerm::default() + }; + + SemidDs { + sem_perm: ipc_perm, + sem_otime: self.sem_otime.load(Ordering::Relaxed), + sem_ctime: self.sem_ctime.load(Ordering::Relaxed), + sem_nsems: self.nsems as u64, + ..SemidDs::default() + } + } } impl Drop for SemaphoreSet { diff --git a/kernel/src/syscall/semctl.rs b/kernel/src/syscall/semctl.rs index 8cb17b4e3..ef3c12ead 100644 --- a/kernel/src/syscall/semctl.rs +++ b/kernel/src/syscall/semctl.rs @@ -92,6 +92,12 @@ pub fn sys_semctl( return Ok(SyscallReturn::Return(cnt as isize)); } + IpcControlCmd::IPC_STAT => { + check_and_ctl(semid, PermissionMode::READ, |sem_set| { + let semid_ds = sem_set.semid_ds(); + ctx.user_space().write_val(arg as Vaddr, &semid_ds) + })?; + } _ => todo!("Need to support {:?} in SYS_SEMCTL", cmd), } diff --git a/kernel/src/syscall/semget.rs b/kernel/src/syscall/semget.rs index 9b5a99fa4..920da718f 100644 --- a/kernel/src/syscall/semget.rs +++ b/kernel/src/syscall/semget.rs @@ -4,7 +4,7 @@ use super::SyscallReturn; use crate::{ ipc::{ semaphore::system_v::{ - sem_set::{check_sem, create_sem_set, create_sem_set_with_id, SEMMSL}, + sem_set::{check_sem, create_sem_set, create_sem_set_with_id, SEMMNI, SEMMSL}, PermissionMode, }, IpcFlags, @@ -32,7 +32,7 @@ pub fn sys_semget(key: i32, nsems: i32, semflags: i32, ctx: &Context) -> Result< // Create a new semaphore set directly const IPC_NEW: i32 = 0; - if key == IPC_NEW { + if key == IPC_NEW || (key as usize > SEMMNI && flags.contains(IpcFlags::IPC_CREAT)) { if nsems == 0 { return_errno!(Errno::EINVAL); } diff --git a/test/src/syscall/ltp/testcases/all.txt b/test/src/syscall/ltp/testcases/all.txt index 8aa4aee6a..66cee0ceb 100644 --- a/test/src/syscall/ltp/testcases/all.txt +++ b/test/src/syscall/ltp/testcases/all.txt @@ -1290,7 +1290,7 @@ select03 # semctl08 # semctl09 -# semget01 +semget01 # semget02 # semget05