feat(process): 新增进程资源限制(rlimit)管理功能及相关系统调用 (#1300)
- 为ProcessControlBlock添加rlimits字段,存储进程资源限制,默认初始化典型值(如nofi le软限制1024、硬限制65536) - 实现进程rlimit的获取、设置及继承机制(inherit_rlimits_from) - 在dup2、fcntl等函数中添加RLIMIT_NOFILE检查,确保文件描述符不超过软限制 - 实现sys_prlimit64和sys_setrlimit系统调用,支持查询和设置进程资源限制 - 调整测试用例,添加dup_test到gvisor白名单,忽略未支持的测试 Signed-off-by: longjin <longjin@DragonOS.org>
This commit is contained in:
parent
1e90730d34
commit
afc09a460b
|
|
@ -1,4 +1,4 @@
|
|||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
|
||||
use alloc::{string::String, sync::Arc, vec::Vec};
|
||||
use log::error;
|
||||
|
|
@ -129,6 +129,8 @@ pub struct File {
|
|||
pub private_data: SpinLock<FilePrivateData>,
|
||||
/// 文件的凭证
|
||||
cred: Arc<Cred>,
|
||||
/// 文件描述符标志:是否在execve时关闭
|
||||
close_on_exec: AtomicBool,
|
||||
}
|
||||
|
||||
impl File {
|
||||
|
|
@ -136,7 +138,7 @@ impl File {
|
|||
///
|
||||
/// @param inode 文件对象对应的inode
|
||||
/// @param mode 文件的打开模式
|
||||
pub fn new(inode: Arc<dyn IndexNode>, mode: FileMode) -> Result<Self, SystemError> {
|
||||
pub fn new(inode: Arc<dyn IndexNode>, mut mode: FileMode) -> Result<Self, SystemError> {
|
||||
let mut inode = inode;
|
||||
let file_type = inode.metadata()?.file_type;
|
||||
if file_type == FileType::Pipe {
|
||||
|
|
@ -144,6 +146,8 @@ impl File {
|
|||
inode = pipe_inode;
|
||||
}
|
||||
}
|
||||
let close_on_exec = mode.contains(FileMode::O_CLOEXEC);
|
||||
mode.remove(FileMode::O_CLOEXEC);
|
||||
|
||||
let private_data = SpinLock::new(FilePrivateData::default());
|
||||
inode.open(private_data.lock(), &mode)?;
|
||||
|
|
@ -156,6 +160,7 @@ impl File {
|
|||
readdir_subdirs_name: SpinLock::new(Vec::default()),
|
||||
private_data,
|
||||
cred: ProcessManager::current_pcb().cred(),
|
||||
close_on_exec: AtomicBool::new(close_on_exec),
|
||||
};
|
||||
|
||||
return Ok(f);
|
||||
|
|
@ -409,6 +414,7 @@ impl File {
|
|||
readdir_subdirs_name: SpinLock::new(self.readdir_subdirs_name.lock().clone()),
|
||||
private_data: SpinLock::new(self.private_data.lock().clone()),
|
||||
cred: self.cred.clone(),
|
||||
close_on_exec: AtomicBool::new(self.close_on_exec.load(Ordering::SeqCst)),
|
||||
};
|
||||
// 调用inode的open方法,让inode知道有新的文件打开了这个inode
|
||||
// TODO: reopen is not a good idea for some inodes, need a better design
|
||||
|
|
@ -438,25 +444,27 @@ impl File {
|
|||
/// 获取文件是否在execve时关闭
|
||||
#[inline]
|
||||
pub fn close_on_exec(&self) -> bool {
|
||||
return self.mode().contains(FileMode::O_CLOEXEC);
|
||||
return self.close_on_exec.load(Ordering::SeqCst);
|
||||
}
|
||||
|
||||
/// 设置文件是否在execve时关闭
|
||||
#[inline]
|
||||
pub fn set_close_on_exec(&self, close_on_exec: bool) {
|
||||
let mut mode_guard = self.mode.write();
|
||||
if close_on_exec {
|
||||
mode_guard.insert(FileMode::O_CLOEXEC);
|
||||
} else {
|
||||
mode_guard.remove(FileMode::O_CLOEXEC);
|
||||
}
|
||||
self.close_on_exec.store(close_on_exec, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
pub fn set_mode(&self, mode: FileMode) -> Result<(), SystemError> {
|
||||
pub fn set_mode(&self, mut mode: FileMode) -> Result<(), SystemError> {
|
||||
// todo: 是否需要调用inode的open方法,以更新private data(假如它与mode有关的话)?
|
||||
// 也许需要加个更好的设计,让inode知晓文件的打开模式发生了变化,让它自己决定是否需要更新private data
|
||||
|
||||
// 直接修改文件的打开模式
|
||||
// 提取 O_CLOEXEC 状态并更新 close_on_exec 字段
|
||||
let close_on_exec = mode.contains(FileMode::O_CLOEXEC);
|
||||
self.close_on_exec.store(close_on_exec, Ordering::SeqCst);
|
||||
|
||||
// 从 mode 中移除 O_CLOEXEC 标志,保持与构造函数一致的行为
|
||||
mode.remove(FileMode::O_CLOEXEC);
|
||||
|
||||
// 更新文件的打开模式
|
||||
*self.mode.write() = mode;
|
||||
self.private_data.lock().update_mode(mode);
|
||||
return Ok(());
|
||||
|
|
@ -528,12 +536,15 @@ impl Default for FileDescriptorVec {
|
|||
}
|
||||
}
|
||||
impl FileDescriptorVec {
|
||||
pub const PROCESS_MAX_FD: usize = 1024;
|
||||
/// 文件描述符表的初始容量
|
||||
pub const INITIAL_CAPACITY: usize = 1024;
|
||||
/// 文件描述符表的最大容量限制(防止无限扩容)
|
||||
pub const MAX_CAPACITY: usize = 65536;
|
||||
|
||||
#[inline(never)]
|
||||
pub fn new() -> FileDescriptorVec {
|
||||
let mut data = Vec::with_capacity(FileDescriptorVec::PROCESS_MAX_FD);
|
||||
data.resize(FileDescriptorVec::PROCESS_MAX_FD, None);
|
||||
let mut data = Vec::with_capacity(FileDescriptorVec::INITIAL_CAPACITY);
|
||||
data.resize(FileDescriptorVec::INITIAL_CAPACITY, None);
|
||||
|
||||
// 初始化文件描述符数组结构体
|
||||
return FileDescriptorVec { fds: data };
|
||||
|
|
@ -544,7 +555,10 @@ impl FileDescriptorVec {
|
|||
/// @return FileDescriptorVec 克隆后的文件描述符数组
|
||||
pub fn clone(&self) -> FileDescriptorVec {
|
||||
let mut res = FileDescriptorVec::new();
|
||||
for i in 0..FileDescriptorVec::PROCESS_MAX_FD {
|
||||
// 调整容量以匹配源文件描述符表
|
||||
let _ = res.resize_to_capacity(self.fds.len());
|
||||
|
||||
for i in 0..self.fds.len() {
|
||||
if let Some(file) = &self.fds[i] {
|
||||
if let Some(file) = file.try_clone() {
|
||||
res.fds[i] = Some(Arc::new(file));
|
||||
|
|
@ -554,6 +568,46 @@ impl FileDescriptorVec {
|
|||
return res;
|
||||
}
|
||||
|
||||
/// 返回当前已占用的最高文件描述符索引(若无则为None)
|
||||
#[inline]
|
||||
fn highest_open_index(&self) -> Option<usize> {
|
||||
// 从高到低查找第一个占用的槽位
|
||||
(0..self.fds.len()).rev().find(|&i| self.fds[i].is_some())
|
||||
}
|
||||
|
||||
/// 扩容文件描述符表到指定容量
|
||||
///
|
||||
/// ## 参数
|
||||
/// - `new_capacity`: 新的容量大小
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - `Ok(())`: 扩容成功
|
||||
/// - `Err(SystemError)`: 扩容失败
|
||||
fn resize_to_capacity(&mut self, new_capacity: usize) -> Result<(), SystemError> {
|
||||
if new_capacity > FileDescriptorVec::MAX_CAPACITY {
|
||||
return Err(SystemError::EMFILE);
|
||||
}
|
||||
|
||||
let current_len = self.fds.len();
|
||||
if new_capacity > current_len {
|
||||
// 扩容:扩展向量并填充None
|
||||
// 使用 try_reserve 先检查内存分配是否可能成功
|
||||
if self.fds.try_reserve(new_capacity - current_len).is_err() {
|
||||
return Err(SystemError::ENOMEM);
|
||||
}
|
||||
self.fds.resize(new_capacity, None);
|
||||
} else if new_capacity < current_len {
|
||||
// 缩容:允许,但不能丢弃仍在使用的高位fd。
|
||||
// 若高位fd仍在使用,将缩容目标提升到 (最高已用fd + 1)。
|
||||
let floor = self.highest_open_index().map(|idx| idx + 1).unwrap_or(0);
|
||||
let target = core::cmp::max(new_capacity, floor);
|
||||
if target < current_len {
|
||||
self.fds.truncate(target);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 返回 `已经打开的` 文件描述符的数量
|
||||
pub fn fd_open_count(&self) -> usize {
|
||||
let mut size = 0;
|
||||
|
|
@ -571,8 +625,8 @@ impl FileDescriptorVec {
|
|||
///
|
||||
/// @return false 不合法
|
||||
#[inline]
|
||||
pub fn validate_fd(fd: i32) -> bool {
|
||||
return !(fd < 0 || fd as usize > FileDescriptorVec::PROCESS_MAX_FD);
|
||||
pub fn validate_fd(&self, fd: i32) -> bool {
|
||||
return !(fd < 0 || fd as usize >= self.fds.len());
|
||||
}
|
||||
|
||||
/// 申请文件描述符,并把文件对象存入其中。
|
||||
|
|
@ -587,7 +641,22 @@ impl FileDescriptorVec {
|
|||
/// - `Ok(i32)` 申请成功,返回申请到的文件描述符
|
||||
/// - `Err(SystemError)` 申请失败,返回错误码,并且,file对象将被drop掉
|
||||
pub fn alloc_fd(&mut self, file: File, fd: Option<i32>) -> Result<i32, SystemError> {
|
||||
// 获取RLIMIT_NOFILE限制
|
||||
let nofile_limit = crate::process::ProcessManager::current_pcb()
|
||||
.get_rlimit(crate::process::resource::RLimitID::Nofile)
|
||||
.rlim_cur as usize;
|
||||
|
||||
if let Some(new_fd) = fd {
|
||||
// 检查指定的文件描述符是否在有效范围内
|
||||
if new_fd < 0 || new_fd as usize >= nofile_limit {
|
||||
return Err(SystemError::EMFILE);
|
||||
}
|
||||
|
||||
// 如果指定的fd超出当前容量,需要扩容
|
||||
if new_fd as usize >= self.fds.len() {
|
||||
self.resize_to_capacity(new_fd as usize + 1)?;
|
||||
}
|
||||
|
||||
let x = &mut self.fds[new_fd as usize];
|
||||
if x.is_none() {
|
||||
*x = Some(Arc::new(file));
|
||||
|
|
@ -596,8 +665,9 @@ impl FileDescriptorVec {
|
|||
return Err(SystemError::EBADF);
|
||||
}
|
||||
} else {
|
||||
// 没有指定要申请的文件描述符编号
|
||||
for i in 0..FileDescriptorVec::PROCESS_MAX_FD {
|
||||
// 没有指定要申请的文件描述符编号,在有效范围内查找空位
|
||||
let max_search = core::cmp::min(self.fds.len(), nofile_limit);
|
||||
for i in 0..max_search {
|
||||
if self.fds[i].is_none() {
|
||||
self.fds[i] = Some(Arc::new(file));
|
||||
return Ok(i as i32);
|
||||
|
|
@ -613,12 +683,37 @@ impl FileDescriptorVec {
|
|||
///
|
||||
/// - `fd` 文件描述符序号
|
||||
pub fn get_file_by_fd(&self, fd: i32) -> Option<Arc<File>> {
|
||||
if !FileDescriptorVec::validate_fd(fd) {
|
||||
if !self.validate_fd(fd) {
|
||||
return None;
|
||||
}
|
||||
self.fds[fd as usize].clone()
|
||||
}
|
||||
|
||||
/// 当RLIMIT_NOFILE变化时调整文件描述符表容量
|
||||
///
|
||||
/// ## 参数
|
||||
/// - `new_rlimit_nofile`: 新的RLIMIT_NOFILE值
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - `Ok(())`: 调整成功
|
||||
/// - `Err(SystemError)`: 调整失败
|
||||
pub fn adjust_for_rlimit_change(
|
||||
&mut self,
|
||||
new_rlimit_nofile: usize,
|
||||
) -> Result<(), SystemError> {
|
||||
// 目标容量不超过实现上限
|
||||
let desired = core::cmp::min(new_rlimit_nofile, FileDescriptorVec::MAX_CAPACITY);
|
||||
if desired >= self.fds.len() {
|
||||
// rlimit 变大:扩容到 desired
|
||||
self.resize_to_capacity(desired)
|
||||
} else {
|
||||
// rlimit 变小:按用户建议,缩容到 max(desired, 最高已用fd+1)
|
||||
let floor = self.highest_open_index().map(|idx| idx + 1).unwrap_or(0);
|
||||
let target = core::cmp::max(desired, floor);
|
||||
self.resize_to_capacity(target)
|
||||
}
|
||||
}
|
||||
|
||||
/// 释放文件描述符,同时关闭文件。
|
||||
///
|
||||
/// ## 参数
|
||||
|
|
@ -638,7 +733,7 @@ impl FileDescriptorVec {
|
|||
}
|
||||
|
||||
pub fn close_on_exec(&mut self) {
|
||||
for i in 0..FileDescriptorVec::PROCESS_MAX_FD {
|
||||
for i in 0..self.fds.len() {
|
||||
if let Some(file) = &self.fds[i] {
|
||||
let to_drop = file.close_on_exec();
|
||||
if to_drop {
|
||||
|
|
@ -672,7 +767,7 @@ impl Iterator for FileDescriptorIterator<'_> {
|
|||
type Item = (i32, Arc<File>);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
while self.index < FileDescriptorVec::PROCESS_MAX_FD {
|
||||
while self.index < self.fds.fds.len() {
|
||||
let fd = self.index as i32;
|
||||
self.index += 1;
|
||||
if let Some(file) = self.fds.get_file_by_fd(fd) {
|
||||
|
|
|
|||
|
|
@ -19,8 +19,16 @@ pub fn do_dup3(
|
|||
flags: FileMode,
|
||||
fd_table_guard: &mut RwLockWriteGuard<'_, FileDescriptorVec>,
|
||||
) -> Result<usize, SystemError> {
|
||||
// 检查 RLIMIT_NOFILE:newfd 必须小于软限制
|
||||
let nofile = crate::process::ProcessManager::current_pcb()
|
||||
.get_rlimit(crate::process::resource::RLimitID::Nofile)
|
||||
.rlim_cur;
|
||||
if newfd as u64 >= nofile {
|
||||
return Err(SystemError::EMFILE);
|
||||
}
|
||||
|
||||
// 确认oldfd, newid是否有效
|
||||
if !(FileDescriptorVec::validate_fd(oldfd) && FileDescriptorVec::validate_fd(newfd)) {
|
||||
if !(fd_table_guard.validate_fd(oldfd) && fd_table_guard.validate_fd(newfd)) {
|
||||
return Err(SystemError::EBADF);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use crate::{
|
|||
arch::interrupt::TrapFrame,
|
||||
filesystem::vfs::{
|
||||
fcntl::{FcntlCommand, FD_CLOEXEC},
|
||||
file::{FileDescriptorVec, FileMode},
|
||||
file::FileMode,
|
||||
syscall::dup2::{do_dup2, do_dup3},
|
||||
},
|
||||
process::ProcessManager,
|
||||
|
|
@ -70,13 +70,19 @@ impl SysFcntlHandle {
|
|||
// debug!("fcntl ({cmd:?}) fd: {fd}, arg={arg}");
|
||||
match cmd {
|
||||
FcntlCommand::DupFd | FcntlCommand::DupFdCloexec => {
|
||||
if arg < 0 || arg as usize >= FileDescriptorVec::PROCESS_MAX_FD {
|
||||
// RLIMIT_NOFILE 检查
|
||||
let nofile = ProcessManager::current_pcb()
|
||||
.get_rlimit(crate::process::resource::RLimitID::Nofile)
|
||||
.rlim_cur as usize;
|
||||
if arg < 0 || arg as usize >= nofile {
|
||||
return Err(SystemError::EBADF);
|
||||
}
|
||||
let arg = arg as usize;
|
||||
for i in arg..FileDescriptorVec::PROCESS_MAX_FD {
|
||||
let binding = ProcessManager::current_pcb().fd_table();
|
||||
let mut fd_table_guard = binding.write();
|
||||
let binding = ProcessManager::current_pcb().fd_table();
|
||||
let mut fd_table_guard = binding.write();
|
||||
|
||||
// 在RLIMIT_NOFILE范围内查找可用的文件描述符
|
||||
for i in arg..nofile {
|
||||
if fd_table_guard.get_file_by_fd(i as i32).is_none() {
|
||||
if cmd == FcntlCommand::DupFd {
|
||||
return do_dup2(fd, i as i32, &mut fd_table_guard);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ use system_error::SystemError;
|
|||
|
||||
use crate::arch::interrupt::TrapFrame;
|
||||
use crate::arch::syscall::nr::{SYS_GETDENTS, SYS_GETDENTS64};
|
||||
use crate::filesystem::vfs::file::FileDescriptorVec;
|
||||
use crate::filesystem::vfs::FilldirContext;
|
||||
use crate::mm::{verify_area, VirtAddr};
|
||||
use crate::process::ProcessManager;
|
||||
|
|
@ -48,7 +47,7 @@ impl Syscall for SysGetdentsHandle {
|
|||
let buf: &mut [u8] = unsafe {
|
||||
core::slice::from_raw_parts_mut::<'static, u8>(buf_vaddr as *mut u8, len)
|
||||
};
|
||||
if fd < 0 || fd as usize > FileDescriptorVec::PROCESS_MAX_FD {
|
||||
if fd < 0 {
|
||||
return Err(SystemError::EBADF);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -482,6 +482,9 @@ impl ProcessManager {
|
|||
)
|
||||
});
|
||||
|
||||
// 继承 rlimit
|
||||
pcb.inherit_rlimits_from(current_pcb);
|
||||
|
||||
// log::debug!("fork: clone_flags: {:?}", clone_flags);
|
||||
// 设置线程组id、组长
|
||||
if clone_flags.contains(CloneFlags::CLONE_THREAD) {
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ use crate::{
|
|||
PhysAddr, VirtAddr,
|
||||
},
|
||||
net::socket::Socket,
|
||||
process::resource::{RLimit64, RLimitID},
|
||||
sched::{
|
||||
DequeueFlag, EnqueueFlag, OnRq, SchedMode, WakeupFlags, __schedule, completion::Completion,
|
||||
cpu_rq, fair::FairSchedEntity, prio::MAX_PRIO,
|
||||
|
|
@ -778,6 +779,8 @@ pub struct ProcessControlBlock {
|
|||
|
||||
/// 进程的可执行文件路径
|
||||
executable_path: RwLock<String>,
|
||||
/// 资源限制(rlimit)数组
|
||||
rlimits: RwLock<[RLimit64; RLimitID::Nlimits as usize]>,
|
||||
}
|
||||
|
||||
impl ProcessControlBlock {
|
||||
|
|
@ -896,6 +899,7 @@ impl ProcessControlBlock {
|
|||
self_ref: weak.clone(),
|
||||
restart_block: SpinLock::new(None),
|
||||
executable_path: RwLock::new(name),
|
||||
rlimits: RwLock::new(Self::default_rlimits()),
|
||||
};
|
||||
|
||||
pcb.sig_info.write().set_tty(tty);
|
||||
|
|
@ -929,6 +933,123 @@ impl ProcessControlBlock {
|
|||
return pcb;
|
||||
}
|
||||
|
||||
fn default_rlimits() -> [crate::process::resource::RLimit64; RLimitID::Nlimits as usize] {
|
||||
use crate::mm::ucontext::UserStack;
|
||||
use crate::process::resource::{RLimit64, RLimitID};
|
||||
|
||||
let mut arr = [RLimit64 {
|
||||
rlim_cur: 0,
|
||||
rlim_max: 0,
|
||||
}; RLimitID::Nlimits as usize];
|
||||
|
||||
// Linux 典型默认值:软限制1024,硬限制65536
|
||||
// 文件描述符表会根据RLIMIT_NOFILE自动扩容
|
||||
arr[RLimitID::Nofile as usize] = RLimit64 {
|
||||
rlim_cur: 1024,
|
||||
rlim_max: 65536,
|
||||
};
|
||||
|
||||
arr[RLimitID::Stack as usize] = RLimit64 {
|
||||
rlim_cur: UserStack::DEFAULT_USER_STACK_SIZE as u64,
|
||||
rlim_max: UserStack::DEFAULT_USER_STACK_SIZE as u64,
|
||||
};
|
||||
|
||||
arr[RLimitID::As as usize] = {
|
||||
let end = <crate::arch::MMArch as crate::mm::MemoryManagementArch>::USER_END_VADDR;
|
||||
RLimit64 {
|
||||
rlim_cur: end.data() as u64,
|
||||
rlim_max: end.data() as u64,
|
||||
}
|
||||
};
|
||||
arr[RLimitID::Rss as usize] = arr[RLimitID::As as usize];
|
||||
|
||||
arr
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_rlimit(&self, res: RLimitID) -> crate::process::resource::RLimit64 {
|
||||
self.rlimits.read()[res as usize]
|
||||
}
|
||||
|
||||
pub fn set_rlimit(
|
||||
&self,
|
||||
res: RLimitID,
|
||||
newv: crate::process::resource::RLimit64,
|
||||
) -> Result<(), system_error::SystemError> {
|
||||
use system_error::SystemError;
|
||||
if newv.rlim_cur > newv.rlim_max {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
// 注意:允许RLIMIT_NOFILE设置为0,这是测试用例的预期行为
|
||||
// 当rlim_cur为0时,无法分配新的文件描述符,但现有fd仍可使用
|
||||
|
||||
// 对于RLIMIT_NOFILE,检查是否超过系统实现的最大容量限制
|
||||
if res == RLimitID::Nofile {
|
||||
if newv.rlim_cur > FileDescriptorVec::MAX_CAPACITY as u64 {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
if newv.rlim_max > FileDescriptorVec::MAX_CAPACITY as u64 {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
let cur = self.rlimits.read()[res as usize];
|
||||
if newv.rlim_max > cur.rlim_max {
|
||||
let cred = self.cred();
|
||||
if !cred.has_capability(crate::process::cred::CAPFlags::CAP_SYS_RESOURCE) {
|
||||
return Err(SystemError::EPERM);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新rlimit
|
||||
self.rlimits.write()[res as usize] = newv;
|
||||
|
||||
// 如果是RLIMIT_NOFILE变化,调整文件描述符表
|
||||
if res == RLimitID::Nofile {
|
||||
if let Err(e) = self.adjust_fd_table_for_rlimit_change(newv.rlim_cur as usize) {
|
||||
// 如果调整失败,回滚rlimit设置
|
||||
self.rlimits.write()[res as usize] = cur;
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 继承父进程的全部rlimit
|
||||
pub fn inherit_rlimits_from(&self, parent: &Arc<ProcessControlBlock>) {
|
||||
let src = *parent.rlimits.read();
|
||||
*self.rlimits.write() = src;
|
||||
|
||||
// 继承后调整文件描述符表以匹配新的RLIMIT_NOFILE
|
||||
let nofile_limit = src[RLimitID::Nofile as usize].rlim_cur as usize;
|
||||
if let Err(e) = self.adjust_fd_table_for_rlimit_change(nofile_limit) {
|
||||
// 如果调整失败,记录错误但不影响继承过程
|
||||
error!(
|
||||
"Failed to adjust fd table after inheriting rlimits: {:?}",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 当RLIMIT_NOFILE变化时调整文件描述符表
|
||||
///
|
||||
/// ## 参数
|
||||
/// - `new_rlimit_nofile`: 新的RLIMIT_NOFILE值
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - `Ok(())`: 调整成功
|
||||
/// - `Err(SystemError)`: 调整失败
|
||||
fn adjust_fd_table_for_rlimit_change(
|
||||
&self,
|
||||
new_rlimit_nofile: usize,
|
||||
) -> Result<(), system_error::SystemError> {
|
||||
let fd_table = self.basic.read().try_fd_table().unwrap();
|
||||
let mut fd_table_guard = fd_table.write();
|
||||
fd_table_guard.adjust_for_rlimit_change(new_rlimit_nofile)
|
||||
}
|
||||
|
||||
/// 返回当前进程的锁持有计数
|
||||
#[inline(always)]
|
||||
pub fn preempt_count(&self) -> usize {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ mod sys_getsid;
|
|||
mod sys_gettid;
|
||||
mod sys_getuid;
|
||||
mod sys_groups;
|
||||
mod sys_prlimit64;
|
||||
pub mod sys_prlimit64;
|
||||
mod sys_set_tid_address;
|
||||
mod sys_setdomainname;
|
||||
mod sys_setfsgid;
|
||||
|
|
@ -39,4 +39,6 @@ mod sys_getpgrp;
|
|||
#[cfg(target_arch = "x86_64")]
|
||||
mod sys_getrlimit;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
mod sys_setrlimit;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
mod sys_vfork;
|
||||
|
|
|
|||
|
|
@ -2,14 +2,11 @@ use crate::arch::syscall::nr::SYS_PRLIMIT64;
|
|||
use crate::syscall::table::FormattedSyscallParam;
|
||||
use crate::syscall::table::Syscall;
|
||||
use crate::{
|
||||
arch::MMArch,
|
||||
filesystem::vfs::file::FileDescriptorVec,
|
||||
mm::{ucontext::UserStack, MemoryManagementArch},
|
||||
process::{
|
||||
resource::{RLimit64, RLimitID},
|
||||
RawPid,
|
||||
ProcessManager, RawPid,
|
||||
},
|
||||
syscall::user_access::UserBufferWriter,
|
||||
syscall::user_access::{UserBufferReader, UserBufferWriter},
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use system_error::SystemError;
|
||||
|
|
@ -83,15 +80,14 @@ syscall_table_macros::declare_syscall!(SYS_PRLIMIT64, SysPrlimit64);
|
|||
/// - 成功,0
|
||||
/// - 如果old_limit不为NULL,则返回旧的资源限制到old_limit
|
||||
///
|
||||
pub(super) fn do_prlimit64(
|
||||
_pid: RawPid,
|
||||
pub fn do_prlimit64(
|
||||
pid: RawPid,
|
||||
resource: usize,
|
||||
_new_limit: *const RLimit64,
|
||||
new_limit: *const RLimit64,
|
||||
old_limit: *mut RLimit64,
|
||||
) -> Result<usize, SystemError> {
|
||||
let resource = RLimitID::try_from(resource)?;
|
||||
let mut writer = None;
|
||||
|
||||
if !old_limit.is_null() {
|
||||
writer = Some(UserBufferWriter::new(
|
||||
old_limit,
|
||||
|
|
@ -100,36 +96,29 @@ pub(super) fn do_prlimit64(
|
|||
)?);
|
||||
}
|
||||
|
||||
match resource {
|
||||
RLimitID::Stack => {
|
||||
if let Some(mut writer) = writer {
|
||||
let mut rlimit = writer.buffer::<RLimit64>(0).unwrap()[0];
|
||||
rlimit.rlim_cur = UserStack::DEFAULT_USER_STACK_SIZE as u64;
|
||||
rlimit.rlim_max = UserStack::DEFAULT_USER_STACK_SIZE as u64;
|
||||
}
|
||||
return Ok(0);
|
||||
}
|
||||
// 找到目标进程(仅支持当前命名空间可见)
|
||||
let target = if pid.data() == 0 {
|
||||
ProcessManager::current_pcb()
|
||||
} else {
|
||||
ProcessManager::find_task_by_vpid(pid).ok_or(SystemError::ESRCH)?
|
||||
};
|
||||
|
||||
RLimitID::Nofile => {
|
||||
if let Some(mut writer) = writer {
|
||||
let mut rlimit = writer.buffer::<RLimit64>(0).unwrap()[0];
|
||||
rlimit.rlim_cur = FileDescriptorVec::PROCESS_MAX_FD as u64;
|
||||
rlimit.rlim_max = FileDescriptorVec::PROCESS_MAX_FD as u64;
|
||||
}
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
RLimitID::As | RLimitID::Rss => {
|
||||
if let Some(mut writer) = writer {
|
||||
let mut rlimit = writer.buffer::<RLimit64>(0).unwrap()[0];
|
||||
rlimit.rlim_cur = MMArch::USER_END_VADDR.data() as u64;
|
||||
rlimit.rlim_max = MMArch::USER_END_VADDR.data() as u64;
|
||||
}
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
_ => {
|
||||
return Err(SystemError::ENOSYS);
|
||||
}
|
||||
// 读取旧限制
|
||||
if let Some(mut writer) = writer {
|
||||
let cur = target.get_rlimit(resource);
|
||||
let rlimit = writer.buffer::<RLimit64>(0)?;
|
||||
rlimit[0].rlim_cur = cur.rlim_cur;
|
||||
rlimit[0].rlim_max = cur.rlim_max;
|
||||
}
|
||||
|
||||
// 设置新限制
|
||||
if !new_limit.is_null() {
|
||||
// 从用户拷贝新值
|
||||
let reader = UserBufferReader::new(new_limit, core::mem::size_of::<RLimit64>(), true)?;
|
||||
let newval = *reader.read_one_from_user::<RLimit64>(0)?;
|
||||
// 应用到目标进程
|
||||
target.set_rlimit(resource, newval)?;
|
||||
}
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
use system_error::SystemError;
|
||||
|
||||
use crate::arch::interrupt::TrapFrame;
|
||||
use crate::arch::syscall::nr::SYS_SETRLIMIT;
|
||||
use crate::process::resource::RLimit64;
|
||||
use crate::process::syscall::sys_prlimit64::do_prlimit64;
|
||||
use crate::process::ProcessManager;
|
||||
use crate::syscall::table::FormattedSyscallParam;
|
||||
use crate::syscall::table::Syscall;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
|
||||
pub struct SysSetRlimit;
|
||||
|
||||
impl SysSetRlimit {
|
||||
fn resource(args: &[usize]) -> usize {
|
||||
args[0]
|
||||
}
|
||||
|
||||
fn rlimit(args: &[usize]) -> *const RLimit64 {
|
||||
args[1] as *const RLimit64
|
||||
}
|
||||
}
|
||||
|
||||
impl Syscall for SysSetRlimit {
|
||||
fn num_args(&self) -> usize {
|
||||
2
|
||||
}
|
||||
|
||||
fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result<usize, SystemError> {
|
||||
let resource = Self::resource(args);
|
||||
let rlimit = Self::rlimit(args);
|
||||
|
||||
do_prlimit64(
|
||||
ProcessManager::current_pcb().raw_pid(),
|
||||
resource,
|
||||
rlimit,
|
||||
core::ptr::null_mut::<RLimit64>(),
|
||||
)
|
||||
}
|
||||
|
||||
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
|
||||
vec![
|
||||
FormattedSyscallParam::new("resource", format!("{:#x}", Self::resource(args))),
|
||||
FormattedSyscallParam::new("rlimit", format!("{:#x}", Self::rlimit(args) as usize)),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
syscall_table_macros::declare_syscall!(SYS_SETRLIMIT, SysSetRlimit);
|
||||
|
|
@ -477,8 +477,6 @@ impl Syscall {
|
|||
let flags = args[4] as u32;
|
||||
Self::sys_perf_event_open(attr, pid, cpu, group_fd, flags)
|
||||
}
|
||||
#[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))]
|
||||
SYS_SETRLIMIT => Ok(0),
|
||||
|
||||
SYS_RT_SIGTIMEDWAIT => {
|
||||
log::warn!("SYS_RT_SIGTIMEDWAIT has not yet been implemented");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
# 暂时不支持该测例,因为/proc/sys/fs/nr_open没支持
|
||||
RlimitTest.DupLimitedByNROpenSysctl
|
||||
|
|
@ -9,6 +9,7 @@ bad_test
|
|||
uname_test
|
||||
|
||||
# 文件系统相关测试
|
||||
dup_test
|
||||
#stat_test
|
||||
#chmod_test
|
||||
#chown_test
|
||||
|
|
|
|||
Loading…
Reference in New Issue