Skip to content

Commit c0ef399

Browse files
committed
feat(fs): implement RLIMIT_FSIZE limit checking
- Add file size limit checking before write operations - Send SIGXFSZ signal when exceeding file size limit - Handle partial writes when approaching the limit - Add check for O_PATH file descriptors in writeable method - Update test configurations for write limit tests Signed-off-by: longjin <longjin@DragonOS.org>
1 parent 84a5869 commit c0ef399

4 files changed

Lines changed: 57 additions & 7 deletions

File tree

kernel/src/filesystem/vfs/file.rs

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ use crate::{
1515
procfs::ProcfsFilePrivateData,
1616
vfs::FilldirContext,
1717
},
18-
ipc::pipe::PipeFsPrivateData,
18+
ipc::{kill::kill_process, pipe::PipeFsPrivateData},
1919
libs::{rwlock::RwLock, spinlock::SpinLock},
20-
process::{cred::Cred, ProcessManager},
20+
process::{cred::Cred, resource::RLimitID, ProcessManager},
2121
};
2222

2323
/// 文件私有信息的枚举类型
@@ -272,20 +272,50 @@ impl File {
272272
return Err(SystemError::ENOBUFS);
273273
}
274274

275+
// 检查RLIMIT_FSIZE限制
276+
let current_pcb = ProcessManager::current_pcb();
277+
let fsize_limit = current_pcb.get_rlimit(RLimitID::Fsize);
278+
279+
// 计算实际可写入的长度
280+
let actual_len = if fsize_limit.rlim_cur != u64::MAX {
281+
let limit = fsize_limit.rlim_cur as usize;
282+
283+
// 如果当前文件大小已经达到或超过限制,不允许写入
284+
if offset >= limit {
285+
// 发送SIGXFSZ信号
286+
let _ = kill_process(
287+
current_pcb.raw_pid(),
288+
crate::arch::ipc::signal::Signal::SIGXFSZ,
289+
);
290+
return Err(SystemError::EFBIG);
291+
}
292+
293+
// 计算可写入的最大长度(不超过限制)
294+
let max_writable = limit.saturating_sub(offset);
295+
if len > max_writable {
296+
// 部分写入:只写到限制位置,不发送信号
297+
max_writable
298+
} else {
299+
len
300+
}
301+
} else {
302+
len
303+
};
304+
275305
// 如果文件指针已经超过了文件大小,则需要扩展文件大小
276306
if offset > self.inode.metadata()?.size as usize {
277307
self.inode.resize(offset)?;
278308
}
279-
let len = self
309+
let written_len = self
280310
.inode
281-
.write_at(offset, len, buf, self.private_data.lock())?;
311+
.write_at(offset, actual_len, buf, self.private_data.lock())?;
282312

283313
if update_offset {
284314
self.offset
285-
.fetch_add(len, core::sync::atomic::Ordering::SeqCst);
315+
.fetch_add(written_len, core::sync::atomic::Ordering::SeqCst);
286316
}
287317

288-
Ok(len)
318+
Ok(written_len)
289319
}
290320

291321
/// @brief 获取文件的元数据
@@ -345,8 +375,15 @@ impl File {
345375
/// @brief 判断当前文件是否可写
346376
#[inline]
347377
pub fn writeable(&self) -> Result<(), SystemError> {
378+
let mode = *self.mode.read();
379+
380+
// 检查是否是O_PATH文件描述符
381+
if mode.contains(FileMode::O_PATH) {
382+
return Err(SystemError::EBADF);
383+
}
384+
348385
// 暂时认为只要不是read only, 就可写
349-
if *self.mode.read() == FileMode::O_RDONLY {
386+
if mode == FileMode::O_RDONLY {
350387
return Err(SystemError::EPERM);
351388
}
352389

kernel/src/process/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,12 @@ impl ProcessControlBlock {
963963
};
964964
arr[RLimitID::Rss as usize] = arr[RLimitID::As as usize];
965965

966+
// 设置文件大小限制的默认值 (Linux默认通常是unlimited)
967+
arr[RLimitID::Fsize as usize] = RLimit64 {
968+
rlim_cur: u64::MAX,
969+
rlim_max: u64::MAX,
970+
};
971+
966972
arr
967973
}
968974

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# 由于缺少SYS_RT_SIGTIMEDWAIT而失败
2+
WriteTest.WriteExceedsRLimit
3+
# 缺少pwritev而失败
4+
WriteTest.PartialWriteSIGSEGV
5+
# 缺少pwritev而失败
6+
WriteTest.PartialWriteSIGBUS

user/apps/tests/syscall/gvisor/whitelist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ uname_test
1010

1111
# 文件系统相关测试
1212
dup_test
13+
write_test
1314
#stat_test
1415
#chmod_test
1516
#chown_test

0 commit comments

Comments
 (0)