Module fork

Module fork 

Source
Expand description

§Fork with Copy-On-Write optimization.

fork is a system call that creates a new process by duplicating the calling process. The new child process is almost identical to the parent, inheriting the same memory layout, open file descriptors, and register state. The child receives a copy of the parent’s process state, including FileStruct and MmStruct. Two processes can communicate via opened pipes after the forking. The only difference is the return value of the syscall: the parent receives the child’s PID, while the child receives 0.

§Copy-On-Write

In modern operating system, fork utilizes copy-on-write (COW) optimization to efficiently share memory between parent and child. Instead of copying all memory pages immediately, the parent and child initially share all pages marked as read-only. If either process writes to one of these shared pages, a page fault triggers the kernel to create a private copy for that process. Note that modern CPUs include a Translation Lookaside Buffer (TLB), a hardware cache that stores recent virtual-to-physical address translations. This leads to case where even after you modify the permission of the address, the change is not immediately visible to the CPU if the TLB still holds a cached, now-stale mapping. Therefore, you must maintain the consistency with the TLB. To maintain memory protection correctness:

  • The kernel must shut down TLB for all pages made read-only by write-protection since they were previously writable.
  • The kernel must invalidate a TLB entry after a new private page is installed , replacing a previously shared page.

Without these TLB flushes, processes may continue using stale or incorrect mappings, bypassing copy-on-write or causing data corruption. In KeOS, copy-on-write works as follow:

  1. When a process invokes a fork system call, the kernel makes copy of FileStruct.
  2. The kernel write-protected ptes by calling LazyPager::write_protect_ptes to make copy of MmStruct. This marks all writable pages as read-only when the child is created. This ensures any future writes will trigger a page fault.
  3. After write-protecting pages, the kernel shuts down the TLB entries for those pages to remove stale writable translations from the CPU’s cache. This is done via tlb_shutdown.
  4. Execute a new process for child with the copy of states.
  5. Resume the execution of both parent and child.

After resuming the execution, process might confront a page fault from the write-protect. The page fault handler determines whether the fault is copy-on-write fault with PageFaultReason::is_cow_fault and handle it with LazyPager::do_copy_on_write. This function finds the pte with PageTable::walk_mut, allocates and installs a new private copy of a page. After mapping the new page, the kernel invalidates the old TLB entry with the StaleTLBEntry::invalidate.

§Implementation Requirements

You need to implement the followings:

This ends the project 3.

Functions§

fork
Creates a new process by duplicating the current process using copy-on-write.