5.3 Real world: Copy-On-Write (COW) fork
Many kernels (though not xv6) use page faults to implement copy-on-write (COW) fork. The fork system call promises that the child sees memory whose initial content is the same as the parent’s memory at the time of the fork. One way to implement this is to copy the entire memory of the parent to newly allocated physical memory for the child; this is what xv6 does. Copying can be slow, and it would be more efficient if the child could share the parent’s physical memory. A straightforward implementation of this would not work, however, since it would cause the parent and child to disrupt each other’s execution with their writes to the shared stack and heap.
Copy-on-write fork causes parent and child to safely share physical
memory by appropriate use of page-table permissions and page faults.
The basic plan is for the parent and child to initially share all
physical pages, but for each to map them read-only (with the
PTE_W flag clear). Parent and child can then read from the
shared physical memory. If either writes a shared page, the RISC-V CPU
raises a page-fault exception. A kernel supporting COW would respond
by allocating a new page of physical memory and copying the shared
page into that new page. Then kernel would change the relevant PTE in
the faulting process’s page table to point to the copy and to allow
writes as well as reads, and then resume the faulting process at the
instruction that caused the fault. Because the PTE now allows writes,
the re-executed store instruction will execute without a fault, and
will modify a private copy of the page rather than the shared page.
Copy-on-write requires book-keeping to help decide when physical pages can be freed, since each page can be referenced by a varying number of page tables depending on the history of forks, page faults, execs, and exits. This book-keeping allows an important optimization: if a process incurs a store page fault and the physical page is only referred to from that process’s page table, no copy is needed.
Copy-on-write makes fork faster, since fork
need not copy memory. Some of the memory will have to be copied
later, when written, but it’s often the case that most of the
memory never has to be copied.
A common example is
fork followed by exec:
a few pages may be written after the fork,
but then the child’s exec releases
the bulk of the memory inherited from the parent.
Copy-on-write fork eliminates the need to
ever copy this memory.
Furthermore, COW fork is transparent:
no modifications to applications are necessary for
them to benefit.