Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 29 additions & 8 deletions kernel/src/mm/syscall/sys_madvise.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
//! System call handler for the madvise system call.

use crate::arch::{interrupt::TrapFrame, syscall::nr::SYS_MADVISE, MMArch};
use crate::libs::align::page_align_up;
use crate::mm::{
syscall::{check_aligned, MadvFlags, PageFrameCount},
syscall::{MadvFlags, PageFrameCount},
ucontext::AddressSpace,
MemoryManagementArch, VirtPageFrame, {verify_area, VirtAddr},
};
Expand All @@ -23,31 +24,51 @@ impl Syscall for SysMadviseHandle {
/// ## madvise系统调用
///
/// ## 参数
/// - `start_vaddr`:起始地址(已经对齐到页)
/// - `len`:长度(已经对齐到页)
/// - `start_vaddr`:起始地址(必须页对齐)
/// - `len`:长度(不需要页对齐,会自动向上舍入到页边界)
/// - `madv_flags`:建议标志
fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result<usize, SystemError> {
let start_vaddr = VirtAddr::new(Self::start_vaddr(args));
let len = Self::len(args);
let madv_flags =
MadvFlags::from_bits(Self::madv_flags(args) as u64).ok_or(SystemError::EINVAL)?;
if Self::start_vaddr(args) & (MMArch::PAGE_SIZE - 1) != 0 {

// 长度为 0 时直接返回成功
if len == 0 {
return Ok(0);
}

// 起始地址必须页对齐
if !start_vaddr.check_aligned(MMArch::PAGE_SIZE) {
return Err(SystemError::EINVAL);
}

if !start_vaddr.check_aligned(MMArch::PAGE_SIZE) || !check_aligned(len, MMArch::PAGE_SIZE) {
// 检查向上舍入到页边界后是否会溢出
// page_align_up 的计算方式是 (addr + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)
// 我们需要确保 len + PAGE_SIZE - 1 不会溢出
let page_size = MMArch::PAGE_SIZE;
if len > usize::MAX - (page_size - 1) {
// 向上舍入会导致溢出
return Err(SystemError::EINVAL);
}
if verify_area(start_vaddr, len).is_err() {

// 将长度向上舍入到页边界
let aligned_len = page_align_up(len);

// 检查地址范围是否会溢出
// 检查 start + aligned_len 是否溢出
if start_vaddr.data().checked_add(aligned_len).is_none() {
return Err(SystemError::EINVAL);
}
if len == 0 {

// 验证地址范围的有效性
if verify_area(start_vaddr, aligned_len).is_err() {
return Err(SystemError::EINVAL);
}

let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
let start_frame = VirtPageFrame::new(start_vaddr);
let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
let page_count = PageFrameCount::new(aligned_len / MMArch::PAGE_SIZE);

current_address_space
.write()
Expand Down
69 changes: 36 additions & 33 deletions kernel/src/mm/syscall/sys_msync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,30 +70,40 @@ impl Syscall for SysMsyncHandle {
.find_nearest(VirtAddr::new(start));
loop {
if let Some(vma) = next_vma.clone() {
let guard = vma.lock_irqsave();
let vm_start = guard.region().start().data();
let vm_end = guard.region().end().data();
if start < vm_start {
if flags == MsFlags::MS_ASYNC {
break;
// 读取VMA信息,确保在调用find_nearest前释放锁
let (vm_start, vm_end, vm_flags, file, file_pgoff);
{
let guard = vma.lock_irqsave();
vm_start = guard.region().start().data();
vm_end = guard.region().end().data();
vm_flags = *guard.vm_flags();
file = guard.vm_file();
file_pgoff = guard.file_page_offset();

if start < vm_start {
if flags == MsFlags::MS_ASYNC {
break;
}
start = vm_start;
if start >= vm_end {
break;
}
unmapped_error = Err(SystemError::ENOMEM);
}
start = vm_start;
if start >= vm_end {

if flags.contains(MsFlags::MS_INVALIDATE)
&& vm_flags.contains(VmFlags::VM_LOCKED)
{
err = Err(SystemError::EBUSY);
break;
}
unmapped_error = Err(SystemError::ENOMEM);
}
let vm_flags = *guard.vm_flags();
if flags.contains(MsFlags::MS_INVALIDATE) && vm_flags.contains(VmFlags::VM_LOCKED) {
err = Err(SystemError::EBUSY);
break;
}
let file = guard.vm_file();
let fstart = (start - vm_start)
+ (guard.file_page_offset().unwrap_or(0) << MMArch::PAGE_SHIFT);

let fstart = (start - vm_start) + (file_pgoff.unwrap_or(0) << MMArch::PAGE_SHIFT);
let fend = fstart + (core::cmp::min(end, vm_end) - start) - 1;
let old_start = start;
start = vm_end;

if flags.contains(MsFlags::MS_SYNC) && vm_flags.contains(VmFlags::VM_SHARED) {
if let Some(file) = file {
let old_pos = file.lseek(SeekFrom::SeekCurrent(0)).unwrap();
Expand All @@ -104,25 +114,18 @@ impl Syscall for SysMsyncHandle {
file.lseek(SeekFrom::SeekSet(old_pos as i64)).unwrap();
if err.is_err() {
break;
} else if start >= end {
err = unmapped_error;
break;
}
next_vma = current_address_space
.read()
.mappings
.find_nearest(VirtAddr::new(start));
}
} else {
if start >= end {
err = unmapped_error;
break;
}
next_vma = current_address_space
.read()
.mappings
.find_nearest(VirtAddr::new(vm_end));
}

if start >= end {
err = unmapped_error;
break;
}
next_vma = current_address_space
.read()
.mappings
.find_nearest(VirtAddr::new(start));
} else {
return Err(SystemError::ENOMEM);
}
Expand Down
6 changes: 3 additions & 3 deletions kernel/src/mm/ucontext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1033,10 +1033,10 @@ impl UserMappings {
if guard.region.contains(vaddr) {
return Some(v.clone());
}
// 选择起始地址不大于 vaddr 的 VMA 中,起始地址最大的一个
if guard.region.start <= vaddr
// 向下寻找:选择起始地址大于 vaddr 的 VMA 中,起始地址最小的一个(最近的下一个VMA)
if guard.region.start > vaddr
&& if let Some(ref current) = nearest {
guard.region.start > current.lock_irqsave().region.start
guard.region.start < current.lock_irqsave().region.start
} else {
true
}
Expand Down
4 changes: 4 additions & 0 deletions user/apps/tests/syscall/gvisor/blocklists/fork_test
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 这个测例,pipe读到的是正确的,但是很奇怪,用户程序glibc会报错:
# Fatal glibc error: allocatestack.c:192 (advise_stack_range): assertion failed: freesize < size
# 接着内核panic,然后才会看到错误,说不结果匹配。感觉是哪里写坏内存了,或者对cow/dirty page的处理不对。
# 已经排除了child进程退出的影响。
ForkTest.COWSegment
ForkTest.SigAltStack
ForkTest.Affinity
2 changes: 2 additions & 0 deletions user/apps/tests/syscall/gvisor/blocklists/madvise_test
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
MadviseDontforkTest.DontforkShared
MadviseDontforkTest.DontforkAnonPrivate
1 change: 1 addition & 0 deletions user/apps/tests/syscall/gvisor/whitelist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ futex_test
#mmap_test
brk_test
mincore_test
madvise_test

# 网络相关测试
#bind_test
Expand Down