diff --git a/kernel/src/process/process/mod.rs b/kernel/src/process/process/mod.rs index af0852c79..43847d95d 100644 --- a/kernel/src/process/process/mod.rs +++ b/kernel/src/process/process/mod.rs @@ -82,7 +82,7 @@ pub struct Process { /// Process group pub(super) process_group: Mutex>, /// resource limits - resource_limits: Mutex, + resource_limits: ResourceLimits, /// Scheduling priority nice value /// According to POSIX.1, the nice value is a per-process attribute, /// the threads in a process should share a nice value. @@ -217,7 +217,7 @@ impl Process { sig_dispositions, parent_death_signal: AtomicSigNum::new_empty(), exit_signal: AtomicSigNum::new_empty(), - resource_limits: Mutex::new(resource_limits), + resource_limits, nice: AtomicNice::new(nice), timer_manager: PosixTimerManager::new(&prof_clock, process_ref), prof_clock, @@ -320,7 +320,7 @@ impl Process { *self.executable_path.write() = executable_path; } - pub fn resource_limits(&self) -> &Mutex { + pub fn resource_limits(&self) -> &ResourceLimits { &self.resource_limits } diff --git a/kernel/src/process/rlimit.rs b/kernel/src/process/rlimit.rs index 9dac343a4..a2312d7a5 100644 --- a/kernel/src/process/rlimit.rs +++ b/kernel/src/process/rlimit.rs @@ -3,6 +3,11 @@ #![expect(non_camel_case_types)] +use core::{ + array, + sync::atomic::{AtomicU64, Ordering}, +}; + use super::process_vm::{INIT_STACK_SIZE, USER_HEAP_SIZE_LIMIT}; use crate::prelude::*; @@ -30,43 +35,44 @@ impl ResourceLimits { pub fn get_rlimit(&self, resource: ResourceType) -> &RLimit64 { &self.rlimits[resource as usize] } - - // Get a mutable reference to a specific resource limit - pub fn get_rlimit_mut(&mut self, resource: ResourceType) -> &mut RLimit64 { - &mut self.rlimits[resource as usize] - } } impl Default for ResourceLimits { fn default() -> Self { - let mut rlimits = [RLimit64::default(); RLIMIT_COUNT]; + let mut rlimits: [RLimit64; RLIMIT_COUNT] = array::from_fn(|_| RLimit64::default()); // Setting the resource limits with predefined values - rlimits[ResourceType::RLIMIT_CPU as usize] = RLimit64::new(RLIM_INFINITY, RLIM_INFINITY); - rlimits[ResourceType::RLIMIT_FSIZE as usize] = RLimit64::new(RLIM_INFINITY, RLIM_INFINITY); + rlimits[ResourceType::RLIMIT_CPU as usize] = + RLimit64::new(RLIM_INFINITY, RLIM_INFINITY).unwrap(); + rlimits[ResourceType::RLIMIT_FSIZE as usize] = + RLimit64::new(RLIM_INFINITY, RLIM_INFINITY).unwrap(); rlimits[ResourceType::RLIMIT_DATA as usize] = - RLimit64::new(USER_HEAP_SIZE_LIMIT as u64, RLIM_INFINITY); + RLimit64::new(USER_HEAP_SIZE_LIMIT as u64, RLIM_INFINITY).unwrap(); rlimits[ResourceType::RLIMIT_STACK as usize] = - RLimit64::new(INIT_STACK_SIZE as u64, RLIM_INFINITY); - rlimits[ResourceType::RLIMIT_CORE as usize] = RLimit64::new(0, RLIM_INFINITY); - rlimits[ResourceType::RLIMIT_RSS as usize] = RLimit64::new(RLIM_INFINITY, RLIM_INFINITY); + RLimit64::new(INIT_STACK_SIZE as u64, RLIM_INFINITY).unwrap(); + rlimits[ResourceType::RLIMIT_CORE as usize] = RLimit64::new(0, RLIM_INFINITY).unwrap(); + rlimits[ResourceType::RLIMIT_RSS as usize] = + RLimit64::new(RLIM_INFINITY, RLIM_INFINITY).unwrap(); rlimits[ResourceType::RLIMIT_NPROC as usize] = - RLimit64::new(INIT_RLIMIT_NPROC, INIT_RLIMIT_NPROC); + RLimit64::new(INIT_RLIMIT_NPROC, INIT_RLIMIT_NPROC).unwrap(); rlimits[ResourceType::RLIMIT_NOFILE as usize] = - RLimit64::new(INIT_RLIMIT_NOFILE_CUR, INIT_RLIMIT_NOFILE_MAX); + RLimit64::new(INIT_RLIMIT_NOFILE_CUR, INIT_RLIMIT_NOFILE_MAX).unwrap(); rlimits[ResourceType::RLIMIT_MEMLOCK as usize] = - RLimit64::new(INIT_RLIMIT_MEMLOCK, INIT_RLIMIT_MEMLOCK); - rlimits[ResourceType::RLIMIT_AS as usize] = RLimit64::new(RLIM_INFINITY, RLIM_INFINITY); - rlimits[ResourceType::RLIMIT_LOCKS as usize] = RLimit64::new(RLIM_INFINITY, RLIM_INFINITY); + RLimit64::new(INIT_RLIMIT_MEMLOCK, INIT_RLIMIT_MEMLOCK).unwrap(); + rlimits[ResourceType::RLIMIT_AS as usize] = + RLimit64::new(RLIM_INFINITY, RLIM_INFINITY).unwrap(); + rlimits[ResourceType::RLIMIT_LOCKS as usize] = + RLimit64::new(RLIM_INFINITY, RLIM_INFINITY).unwrap(); rlimits[ResourceType::RLIMIT_SIGPENDING as usize] = - RLimit64::new(INIT_RLIMIT_SIGPENDING, INIT_RLIMIT_SIGPENDING); + RLimit64::new(INIT_RLIMIT_SIGPENDING, INIT_RLIMIT_SIGPENDING).unwrap(); rlimits[ResourceType::RLIMIT_MSGQUEUE as usize] = - RLimit64::new(INIT_RLIMIT_MSGQUEUE, INIT_RLIMIT_MSGQUEUE); + RLimit64::new(INIT_RLIMIT_MSGQUEUE, INIT_RLIMIT_MSGQUEUE).unwrap(); rlimits[ResourceType::RLIMIT_NICE as usize] = - RLimit64::new(INIT_RLIMIT_NICE, INIT_RLIMIT_NICE); + RLimit64::new(INIT_RLIMIT_NICE, INIT_RLIMIT_NICE).unwrap(); rlimits[ResourceType::RLIMIT_RTPRIO as usize] = - RLimit64::new(INIT_RLIMIT_RTPRIO, INIT_RLIMIT_RTPRIO); - rlimits[ResourceType::RLIMIT_RTTIME as usize] = RLimit64::new(RLIM_INFINITY, RLIM_INFINITY); + RLimit64::new(INIT_RLIMIT_RTPRIO, INIT_RLIMIT_RTPRIO).unwrap(); + rlimits[ResourceType::RLIMIT_RTTIME as usize] = + RLimit64::new(RLIM_INFINITY, RLIM_INFINITY).unwrap(); ResourceLimits { rlimits } } @@ -97,34 +103,69 @@ pub const RLIMIT_COUNT: usize = 16; #[derive(Debug, Clone, Copy, Pod)] #[repr(C)] +pub struct RawRLimit64 { + pub cur: u64, + pub max: u64, +} + +#[derive(Debug)] +#[repr(C)] pub struct RLimit64 { - cur: u64, - max: u64, + cur: AtomicU64, + max: AtomicU64, + lock: SpinLock<()>, } impl RLimit64 { - pub fn new(cur: u64, max: u64) -> Self { - Self { cur, max } + pub fn new(cur_: u64, max_: u64) -> Result { + if cur_ > max_ { + return_errno_with_message!(Errno::EINVAL, "invalid rlimit"); + } + Ok(Self { + cur: AtomicU64::new(cur_), + max: AtomicU64::new(max_), + lock: SpinLock::new(()), + }) } + /// Gets the current rlimit without synchronization. pub fn get_cur(&self) -> u64 { - self.cur + self.cur.load(Ordering::Relaxed) } + /// Gets the max rlimit without synchronization. pub fn get_max(&self) -> u64 { - self.max + self.max.load(Ordering::Relaxed) } - pub fn is_valid(&self) -> bool { - self.cur <= self.max + /// Gets the rlimit with synchronization. + /// + /// Only called when handling the `getrlimit` or `prlimit` syscall. + pub fn get_cur_and_max(&self) -> (u64, u64) { + let _guard = self.lock.lock(); + (self.get_cur(), self.get_max()) + } + + /// Sets the rlimit with synchronization. + /// + /// Only called when handling the `setrlimit` or `prlimit` syscall. + pub fn set_cur_and_max(&self, new_cur: u64, new_max: u64) -> Result<()> { + if new_cur > new_max { + return_errno_with_message!(Errno::EINVAL, "invalid rlimit"); + } + let _guard = self.lock.lock(); + self.cur.store(new_cur, Ordering::Relaxed); + self.max.store(new_max, Ordering::Relaxed); + Ok(()) } } impl Default for RLimit64 { fn default() -> Self { Self { - cur: RLIM_INFINITY, - max: RLIM_INFINITY, + cur: AtomicU64::new(RLIM_INFINITY), + max: AtomicU64::new(RLIM_INFINITY), + lock: SpinLock::new(()), } } } diff --git a/kernel/src/syscall/dup.rs b/kernel/src/syscall/dup.rs index 7749fae03..a821cc31e 100644 --- a/kernel/src/syscall/dup.rs +++ b/kernel/src/syscall/dup.rs @@ -60,7 +60,6 @@ fn do_dup3( >= ctx .process .resource_limits() - .lock() .get_rlimit(ResourceType::RLIMIT_NOFILE) .get_cur() as FileDesc { diff --git a/kernel/src/syscall/fallocate.rs b/kernel/src/syscall/fallocate.rs index dcb5fa553..71d87e661 100644 --- a/kernel/src/syscall/fallocate.rs +++ b/kernel/src/syscall/fallocate.rs @@ -48,7 +48,7 @@ fn check_offset_and_len(offset: i64, len: i64, ctx: &Context) -> Result<()> { } let max_file_size = { - let resource_limits = ctx.process.resource_limits().lock(); + let resource_limits = ctx.process.resource_limits(); resource_limits .get_rlimit(ResourceType::RLIMIT_FSIZE) .get_cur() as usize diff --git a/kernel/src/syscall/prlimit64.rs b/kernel/src/syscall/prlimit64.rs index 51ca0038c..409d61e4b 100644 --- a/kernel/src/syscall/prlimit64.rs +++ b/kernel/src/syscall/prlimit64.rs @@ -3,15 +3,17 @@ use super::SyscallReturn; use crate::{ prelude::*, - process::{rlimit::RLimit64, Pid, ResourceType}, + process::{rlimit::RawRLimit64, Pid, ResourceType}, }; pub fn sys_getrlimit(resource: u32, rlim_addr: Vaddr, ctx: &Context) -> Result { let resource = ResourceType::try_from(resource)?; debug!("resource = {:?}, rlim_addr = 0x{:x}", resource, rlim_addr); - let resource_limits = ctx.process.resource_limits().lock(); + let resource_limits = ctx.process.resource_limits(); let rlimit = resource_limits.get_rlimit(resource); - ctx.user_space().write_val(rlim_addr, rlimit)?; + let (cur, max) = rlimit.get_cur_and_max(); + let rlimit_raw = RawRLimit64 { cur, max }; + ctx.user_space().write_val(rlim_addr, &rlimit_raw)?; Ok(SyscallReturn::Return(0)) } @@ -21,12 +23,11 @@ pub fn sys_setrlimit(resource: u32, new_rlim_addr: Vaddr, ctx: &Context) -> Resu "resource = {:?}, new_rlim_addr = 0x{:x}", resource, new_rlim_addr ); - let new_rlimit: RLimit64 = ctx.user_space().read_val(new_rlim_addr)?; - if !new_rlimit.is_valid() { - return_errno_with_message!(Errno::EINVAL, "invalid rlimit"); - } - let mut resource_limits = ctx.process.resource_limits().lock(); - *resource_limits.get_rlimit_mut(resource) = new_rlimit; + let new_raw: RawRLimit64 = ctx.user_space().read_val(new_rlim_addr)?; + let resource_limits = ctx.process.resource_limits(); + resource_limits + .get_rlimit(resource) + .set_cur_and_max(new_raw.cur, new_raw.max)?; Ok(SyscallReturn::Return(0)) } @@ -42,18 +43,19 @@ pub fn sys_prlimit64( "pid = {}, resource = {:?}, new_rlim_addr = 0x{:x}, old_rlim_addr = 0x{:x}", pid, resource, new_rlim_addr, old_rlim_addr ); - let mut resource_limits = ctx.process.resource_limits().lock(); + let resource_limits = ctx.process.resource_limits(); if old_rlim_addr != 0 { let rlimit = resource_limits.get_rlimit(resource); - ctx.user_space().write_val(old_rlim_addr, rlimit)?; + let (cur, max) = rlimit.get_cur_and_max(); + let rlimit_raw = RawRLimit64 { cur, max }; + ctx.user_space().write_val(old_rlim_addr, &rlimit_raw)?; } if new_rlim_addr != 0 { - let new_rlimit: RLimit64 = ctx.user_space().read_val(new_rlim_addr)?; - debug!("new_rlimit = {:?}", new_rlimit); - if !new_rlimit.is_valid() { - return_errno_with_message!(Errno::EINVAL, "invalid rlimit"); - } - *resource_limits.get_rlimit_mut(resource) = new_rlimit; + let new_raw: RawRLimit64 = ctx.user_space().read_val(new_rlim_addr)?; + debug!("new_rlimit = {:?}", new_raw); + resource_limits + .get_rlimit(resource) + .set_cur_and_max(new_raw.cur, new_raw.max)?; } Ok(SyscallReturn::Return(0)) } diff --git a/kernel/src/syscall/truncate.rs b/kernel/src/syscall/truncate.rs index d6982b434..a8e856d50 100644 --- a/kernel/src/syscall/truncate.rs +++ b/kernel/src/syscall/truncate.rs @@ -47,7 +47,7 @@ fn check_length(len: isize, ctx: &Context) -> Result<()> { } let max_file_size = { - let resource_limits = ctx.process.resource_limits().lock(); + let resource_limits = ctx.process.resource_limits(); resource_limits .get_rlimit(ResourceType::RLIMIT_FSIZE) .get_cur() as usize