xv6, line by line
lab 16
Lab 1616 Swapping to disk

Lab 16 · reveal · 20 steps · 11 commits

Swapping to disk: the reference solution

In this tree a process can use only as much memory as there are free pages. When kalloc finds its free list empty, sbrk fails and a lazy page fault kills the process. In this lab you make the kernel take a page that some process has not used for a while, write it to a reserved area at the end of the disk, and give its physical page to whoever needs it. When the owner touches that page again, it takes a page fault, and the kernel reads the page back in. The test program writes and checks 36,000 pages on a machine with 32,768 pages of RAM.

Swapping touches more of the kernel than any lab before it, because it moves pages out from under processes that are not expecting it. Where on the disk do the pages go, and through which layer? How does a PTE say “this page is on disk, in slot 2128”? Which page do you pick, and how do you get from a physical page to the PTE that maps it? The page you pick may belong to a process that is running on another hart at that very moment: what does that hart’s TLB (translation lookaside buffer) still believe? Eviction needs the disk, and the disk sleeps: from which of kalloc's many callers is that allowed? The kernel copies into user memory while holding spinlocks: what if the page it copies to is on disk? The think section asks these questions in the order a designer meets them.

The reference solution is twelve commits. It passes usertests -q on three harts, and during that run it writes about 49,000 pages to swap without anyone noticing.

Each step shows one change on the branch ext/16-swap, the code around it, and the state of the machine when that code runs.

The route
  1. 1A swap area the file system never sees mkfs/mkfs.c
  2. 2One request for a whole page kernel/virtio_disk.c
  3. 3Slots, with a count of their users kernel/swap.c
  4. 4The frame table, a map from pages back to PTEs kernel/swap.c
  5. 5Every fresh user page is recorded kernel/vm.c
  6. 6What a page in swap looks like kernel/riscv.h
  7. 7uvmunmap gives slots back kernel/vm.c
  8. 8fork shares the slot kernel/vm.c
  9. 9vmfault: a third kind of missing page kernel/vm.c
  10. 10swapin kernel/swap.c
  11. 11usertrap keeps its fault registers kernel/trap.c
  12. 12copyout keeps its page by staying on its hart kernel/vm.c
  13. 13copyin under pi->lock kernel/vm.c
  14. 14Pinning a buffer kernel/vm.c
  15. 15read, write and wait pin, then unpin kernel/sysfile.c
  16. 16The clock hand, and the lock dance kernel/swap.c
  17. 17Second chance, or victim kernel/swap.c
  18. 18evict writes, then frees kernel/swap.c
  19. 19ualloc, and the reserve kalloc lives on kernel/swap.c
  20. 20The test that the original kernel cannot run user/swaptest.c

Keys: ← → step · Home start