MIT 6.S081 lab6:Lazy alloc | 懒加载

本实验旨在通过修改 xv6 的缺页异常处理机制,实现内存的懒分配(Lazy Allocation)。当用户调用 sbrk() 时不立即分配物理内存,而是延迟到发生 Page Fault 时才按需分配。


1. 实验目标 (Goal)

传统的 sbrk() 系统调用会立即分配物理内存并映射页表。本实验要求: 1. 修改 sys_sbrk(),仅增加进程的 sz 而不实际分配内存。 2. 在 usertrap() 中捕获页错误(Page Fault)。 3. 动态分配物理页并建立映射,使程序恢复运行。


2. 核心实现 (Implementation)

2.1 修改 sys_sbrk

sysproc.c 中,将 growproc 的调用改为简单的指针增加。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// kernel/sysproc.c
uint64
sys_sbrk(void)
{
int n;
uint64 addr;
struct proc *p = myproc();

if(argint(0, &n) < 0)
return -1;
addr = p->sz;

// Lazy allocation: 仅仅移动指针,不调用 growproc(n)
if (n > 0) {
p->sz += n;
} else if (n < 0) {
p->sz = growproc(n);
}
return addr;
}

### 2.2 修改 usertrap 处理缺页
```C
// kernel/trap.c
void
usertrap(void)
{
uint64 cause = r_scause();
if(cause == 13 || cause == 15) {
uint64 va = r_stval(); // 触发错误的虚拟地址

// 边界检查:防止访问超出 p->sz 或在栈以下的非法地址
if(va >= p->sz || va < PGROUNDDOWN(p->trapframe->sp)) {
p->killed = 1;
} else {
if(lazy_alloc(va) != 0) {
p->killed = 1;
}
}
}
// ... 其他逻辑 ...
}

2.3 实现 lazy_alloc 函数

封装一个简单的分配函数,模仿 uvmalloc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// kernel/vm.c
int lazy_alloc(uint64 va) {
char *mem;
uint64 a = PGROUNDDOWN(va);

mem = kalloc();
if(mem == 0) return -1;

memset(mem, 0, PGSIZE);
if(mappages(myproc()->pagetable, a, PGSIZE, (uint64)mem, PTE_W|PTE_U|PTE_R) != 0){
kfree(mem);
return -1;
}
return 0;
}

2.4 处理边缘情况

uvmunmap 中,如果遇到 PTE 不存在或 PTE_V 为0的页,在 Lazy 模式下是正常的,不应该 panic。同理处理 fork 中的逻辑。

1
2
3
4
5
// kernel/vm.c -> uvmunmap
if((pte = walk(pagetable, a, 0)) == 0)
continue; // 原为 panic
if((*pte & PTE_V) == 0)
continue; // 原为 panic


MIT 6.S081 lab6:Lazy alloc | 懒加载
https://acmicpc.top/2024/03/22/MIT-6.S081-lab07/
作者
江欣婷
发布于
2024年3月22日
许可协议