Skip to content

feat(fadvise64): 实现fadvise64系统调用和页面缓存管理功能#1439

Merged
fslongjin merged 9 commits intoDragonOS-Community:masterfrom
xboHodx:feat/fadvise64
Dec 9, 2025
Merged

feat(fadvise64): 实现fadvise64系统调用和页面缓存管理功能#1439
fslongjin merged 9 commits intoDragonOS-Community:masterfrom
xboHodx:feat/fadvise64

Conversation

@xboHodx
Copy link
Contributor

@xboHodx xboHodx commented Dec 5, 2025

  • 新增fadvise64系统调用实现
  • 添加页面缓存范围写回和驱逐功能
  • 改进预读机制,支持随机访问模式
  • 扩展文件访问模式标志管理

- 新增fadvise64系统调用实现
- 添加页面缓存范围写回和驱逐功能
- 改进预读机制,支持随机访问模式
- 扩展文件访问模式标志管理
@fslongjin
Copy link
Member

@claude review this pr in Chinese

@dragonos-community-ai-pr-reviewer
Copy link

dragonos-community-ai-pr-reviewer bot commented Dec 5, 2025

Claude finished @fslongjin's task —— View job


代码审查:feat(fadvise64) 系统调用实现

待办事项清单:

  • 分析PR变更范围和实现目标
  • 审查新增的 sys_fadvise64.rs 文件
  • 审查 page_cache.rs 的修改
  • 审查 readahead.rs 的修改
  • 审查 VFS 相关文件的修改
  • 检查系统调用注册和集成
  • 提供整体代码审查反馈
  • 总结审查结果和建议

代码审查反馈

总体评价

这是一个设计良好的PR,实现了fadvise64系统调用和相关的页面缓存管理功能。代码结构清晰,功能完整。以下是详细审查反馈:

主要问题

1. sys_fadvise64.rs 中的问题

a) 错误的文件注释 (第1行)

//! System call handler for the brk system call.

应该改为 fadvise64 系统调用。

b) 边界检查逻辑需要澄清 (第107-109行)

if len < 0 || inode.page_cache().is_none() {
    return Err(SystemError::EINVAL);
}

根据POSIX规范,len == 0 表示从 offset 到文件结尾。当前代码允许 len == 0 通过,这是正确的,但建议添加注释说明。

c) endbyte 计算可能有问题 (第118-121行)

let mut endbyte = offset as u64 + len as u64;
if len == 0 || endbyte < len as u64 {
    endbyte = i64::MAX as u64;
}
  • len == 0 时,endbyte = offset as u64,然后被设置为 i64::MAX as u64
  • endbyte < len as u64 检查可能意图防止溢出,但表达式有误。建议重写为:
let mut endbyte = offset.checked_add(len).ok_or(SystemError::EINVAL)? as u64;
if len == 0 {
    endbyte = u64::MAX; // 或文件大小
}

d) 未使用的导入 (第3行)
导入了 PAGE_SHIFT 但未使用,而代码中使用 MMArch::PAGE_SHIFT

e) DontNeed 处理的页索引计算 (第153行)
使用 MMArch::PAGE_SIZE 进行位移操作,而不是 MMArch::PAGE_SHIFT,导致代码冗长:

let start_index = (offset as usize + MMArch::PAGE_SIZE - 1) >> MMArch::PAGE_SHIFT;

可以简化为:

let start_index = page_align_up(offset as usize) >> MMArch::PAGE_SHIFT;

2. page_cache.rs 中的问题

a) 魔法数字需要解释 (第359行)

if Arc::strong_count(page) <= 3 {

为什么是3?需要添加注释说明每个引用的来源(例如:1个page_cache引用,1个当前guard引用等)。

b) 缺少参数验证
writeback_rangeinvalidate_range 方法应检查 start_index <= end_index,否则返回错误或交换参数。

3. 代码风格和可读性

a) 复杂的条件表达式 (sys_fadvise64.rs 第156-163行)

if (endbyte as usize & !(MMArch::PAGE_SIZE - 1)) != !(MMArch::PAGE_SIZE - 1)
    && endbyte != inode.metadata()?.size as u64 - 1
{
    // ...
}

建议提取为辅助函数或添加详细注释。

b) 日志和调试代码
部分注释掉的调试代码(如 log::debug!)可以删除或通过条件编译控制。

建议的改进

  1. 添加更多注释:特别是在复杂算法和边界条件处。
  2. 提取辅助函数:将复杂的计算逻辑(如页索引计算)提取为函数。
  3. 增加参数验证:在公共方法中添加参数范围检查。
  4. 统一错误处理:确保所有错误路径都返回适当的错误码。
  5. 性能考虑writeback_rangeinvalidate_range 在循环中频繁获取锁,考虑批量操作。

测试建议

  1. 单元测试:为 PosixFadviseFlag::from_i32 和页索引计算添加测试。
  2. 边界测试:测试 len == 0offset 接近文件末尾等边界情况。
  3. 并发测试:测试多线程下的 fadvise 调用和页面缓存操作。

总结

这个PR实现了核心功能,代码质量良好。建议在合并前修复上述问题,特别是:

  1. 修正错误的文件注释
  2. 澄清边界检查逻辑
  3. 解释魔法数字
  4. 添加参数验证

这些改进将提高代码的可维护性和健壮性。


审查完成

- 在FileDescriptorVec中新增get_file_by_fd_not_raw方法
- 修改sys_fadvise64使用新方法进行权限检查
@fslongjin
Copy link
Member

@claude review this pr in Chinese

@dragonos-community-ai-pr-reviewer
Copy link

dragonos-community-ai-pr-reviewer bot commented Dec 8, 2025

Claude finished @fslongjin's task —— View job


Claude正在处理 @fslongjin 的任务

待办事项清单

  • 分析PR变更范围和实现目标
  • 审查新增的 sys_fadvise64.rs 文件
  • 审查 page_cache.rs 的修改
  • 审查 readahead.rs 的修改
  • 审查 VFS 相关文件的修改
  • 检查系统调用注册和集成
  • 提供整体代码审查反馈
  • 总结审查结果和建议

代码审查反馈

总体评价

这是一个设计良好的PR,成功实现了fadvise64系统调用和相关的页面缓存管理功能。代码结构清晰,功能完整,涵盖了POSIX fadvise的主要标志。整体实现质量较高,但存在一些需要改进的地方。

主要问题

1. sys_fadvise64.rs 中的问题

a) 复杂条件表达式需要注释 (第154-162行)

if (endbyte & !(MMArch::PAGE_SIZE - 1)) != !(MMArch::PAGE_SIZE - 1)
    && endbyte != inode.metadata()?.size as usize - 1
{
    if end_index == 0 {
        return Ok(0);
    }
    end_index -= 1;
}

这个条件判断逻辑复杂,意图是"如果要驱逐的最后一页不是整页,则需要保留"。建议提取为辅助函数或添加详细注释说明。

b) 边界情况处理需要澄清 (第105-107行)

if len < 0 || inode.page_cache().is_none() {
    return Err(SystemError::EINVAL);
}

根据POSIX规范,len == 0表示从offset到文件结尾,当前代码允许len == 0通过,这是正确的。但建议添加注释说明。

2. page_cache.rs 中的问题

a) 缺少参数验证
writeback_range (第327-342行) 和 invalidate_range (第344-372行) 方法应检查 start_index <= end_index,否则返回错误或自动交换参数。当前实现中,如果 start_index > end_index,循环 for idx in start_index..=end_index 不会执行任何迭代,这可能 silently 跳过操作,最好显式处理。

b) 锁粒度过细
这两个方法在循环中频繁获取和释放页面锁,考虑批量操作以提高性能。

3. 系统调用集成问题

a) 遗留的存根实现 (kernel/src/syscall/mod.rs 第340-344行)

SYS_FADVISE64 => {
    // todo: 这个系统调用还没有实现
    Err(SystemError::ENOSYS)
}

这个存根实现仍然存在,虽然系统调用表宏可能覆盖它,但为了代码清晰性,应该移除或更新这个存根。

4. 代码风格和可读性

a) 日志和调试代码
部分注释掉的调试代码(如 log::debug!)可以删除或通过条件编译控制。

b) 错误处理一致性
确保所有错误路径都返回适当的错误码。当前实现中大部分错误处理良好。

建议的改进

  1. 添加更多注释:特别是在复杂算法和边界条件处,如 sys_fadvise64.rs 中的页索引计算逻辑。
  2. 提取辅助函数:将复杂的计算逻辑(如页索引计算、边界检查)提取为函数,提高可读性。
  3. 增加参数验证:在公共方法中添加参数范围检查,特别是 start_index <= end_index
  4. 性能优化:考虑批量操作减少锁竞争,特别是在 writeback_rangeinvalidate_range 中。
  5. 清理遗留代码:移除 syscall/mod.rs 中的旧存根实现。

测试建议

  1. 单元测试:为 PosixFadviseFlag::from_i32 和页索引计算添加测试。
  2. 边界测试:测试 len == 0offset 接近文件末尾、start_index > end_index 等边界情况。
  3. 并发测试:测试多线程下的 fadvise 调用和页面缓存操作。
  4. 功能测试:验证各个标志(NORMAL, RANDOM, SEQUENTIAL, WILLNEED, DONTNEED, NOREUSE)的实际效果。

总结

这个PR实现了核心功能,代码质量良好。主要改进点在于:

  1. 为复杂逻辑添加注释
  2. 添加参数验证
  3. 清理遗留存根代码
  4. 考虑性能优化

建议在合并前修复上述问题,特别是参数验证和遗留存根清理,这些改进将提高代码的健壮性和可维护性。


审查完成

@fslongjin
Copy link
Member

if (endbyte & !(MMArch::PAGE_SIZE - 1)) != !(MMArch::PAGE_SIZE - 1)

这个地方应当用 check_aligned这个函数

Comment on lines +143 to +145
let mut ra_state = file.ra_state.lock().clone();
force_page_cache_readahead(&page_cache, &inode, &mut ra_state, start_page, page_num)?;
*file.ra_state.lock() = ra_state;
Copy link
Member

@fslongjin fslongjin Dec 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果仅仅是为了这个需求,那么ra_state不应该pub,而是应该封装成函数来操作。
并且如果并发的对同一file结构体进行了这个操作。那么ra_state可能就是不正确的。

PosixFadviseFlag::Sequential => {
file.set_ra_pages(MAX_READAHEAD * 2);
file.remove_mode_flags(FileMode::FMODE_RANDOM);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这两个操作不是原子的,中间会有个并发窗口,这样是否会造成问题?或许可以考虑封装成函数来处理set_ra_flag + remove_mode_flags 这一套操作。

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fadvise64这个系统调用没必要保证原子性,因为它只是建议,这里发生并发冲突可能会导致效率不高,但不会产生损害。linux中也没有保证原子性

@xboHodx
Copy link
Contributor Author

xboHodx commented Dec 8, 2025

if (endbyte & !(MMArch::PAGE_SIZE - 1)) != !(MMArch::PAGE_SIZE - 1)

这个地方应当用 check_aligned这个函数

这个我写错了,应该写if (endbyte & MMArch::PAGE_OFFSET_MASK) != MMArch::PAGE_OFFSET_MASK才对。不是想检测对齐,而是想判断endbyte不是页的最后一个字节

- 将File结构体的ra_state字段改为私有并提供get/set方法
- 在sys_fadvise64中使用新的访问方法
- 修复fadvise64中页边界检查逻辑
- 移除syscall模块中未实现的fadvise64 stub
@fslongjin fslongjin merged commit fd5cc66 into DragonOS-Community:master Dec 9, 2025
12 of 13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants