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:
- When a process invokes a fork system call, the kernel makes copy of
FileStruct. - The kernel write-protected ptes by calling
LazyPager::write_protect_ptesto make copy ofMmStruct. This marks all writable pages as read-only when the child is created. This ensures any future writes will trigger a page fault. - 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. - Execute a new process for child with the copy of states.
- 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.