Lab 4 Lazy
Allocate user memory lazily
Introduction
One of the many neat tricks an O/S can play with page table hardware is lazy allocation of user-space heap memory. Xv6 applications ask the kernel for heap memory using the sbrk() system call. In the kernel we’ve given you, sbrk() allocates physical memory and maps it into the process’s virtual address space. However, there are programs that use sbrk() to ask for large amounts of memory but never use most of it, for example to implement large sparse arrays.
To optimize for this case, sophisticated kernels allocate user memory lazily. That is, sbrk() doesn’t allocate physical memory, but just remembers which addresses are allocated. When the process first tries to use any given page of memory, the CPU generates a page fault, which the kernel handles by allocating physical memory, zeroing it, and mapping it.
Your Task
Add this lazy allocation feature to xv6
Task 1: Print page table
Requirements
Implement a function that prints the contents of a page table. Define the function in kernel/vm.c; it has the following prototype: void vmprint(pagetable_t)
. Insert a call to vmprint in exec.c to print the page table for the first user process.
The output of vmprint for the first user-level process should be as follows:
The first line prints the address of the argument of
vmprint
.Each PTE line shows the PTE index in its page directory, the pte, the physical address for the PTE.
The output should also indicate the level of the page directory: the top-level entries are preceded by “..”, the next level down with another “..”, and so on.
You should not print entries that are not mapped.
In the above example, the top-level page directory has mappings for entry 0 and 255. The next level down for entry 0 has only index 0 mapped, and the bottom-level for that index 0 has entries 0, 1, and 2 mapped.
Solution
Task 2: Eliminate allocation from sbrk()
Requirement
Your new sbrk(n) should just increment the process’s size (myproc()->sz) by n and return the old size. It should not allocate memory
Solution
Task 3: Lazy allocation
Requirement
Modify the code in trap.c to respond to a page fault from user space by mapping a newly-allocated page of physical memory at the faulting address, and then returning back to user space to let the process continue executing.
Check whether a fault is a page fault by seeing if r_scause()
is 13 or 15 in usertrap()
.
Look at the arguments to the printf() in usertrap()
that reports the page fault, in order to see how to find the virtual address that caused the page fault.
Use PGROUNDDOWN(va)
to round the faulting virtual address down to a page boundary.
Solution
In trap.c: usertrap
Now trap handler will allocate a new physical memory and install to user page table once passed safety checks.
p->ustack
is new added to Process struct, indicate the bottom of user stack. User stack is established in exec.c
when loading file image to execute. See below code for references:
Reference: User Process Address Space
If accessing guard page, we should fail!
Fix a couple of place in vm.c
so no panic
vm.c
so no panicIn uvmunmap
, if a PTE does not exist, continue the loop instead of panic. If an PA in PTE not mapped, continue the loop instead of panic. Same fix in uvmcopy
Fix Copy in/out between kernel and user space
Requirement
Handle the case in which a process passes a valid address from sbrk() to a system call such as read or write, but the memory for that address has not yet been allocated.
Solution
copyout
: Copy from kernel to user. copying
: Copy from user to kernel. They originally will error out if physical address (PA) does not exist. We should fix it, so allow to continue looping if such PA does not exist. Since the virtual address could be valid, so trap handler will allocate new pages later. We should allow the copy to continue.
Change from:
Change to:
Result
心得
中断是操作系统的核心,利用中断来做Lazy allocation也是精妙的思想。最终要解决的问题是不要过多分配完全不使用的内存给用户。用多少拿多少。
Last updated