This question tests whether you know what fork copies. The interviewer wants the page table mechanics — not "it makes a copy of the process."
The mental model: fork creates a new process that is a near-exact duplicate of the parent. But duplicating the entire physical working set would make fork O(memory) and useless. The trick: fork copies the mappings — page tables and metadata — and marks every page read-only. Physical pages are shared until someone writes.
Walk through the mechanism. fork allocates a new task_struct and a new mm_struct, copies the page table hierarchy (all four levels on x86-64), and for every PTE it clears the write bit and sets the COW flag, incrementing the refcount of the underlying physical page. Physical memory isn't touched. The child returns 0 from the syscall; the parent gets the child's PID. Both continue at the same instruction — the difference is only in the return value.
The write. The moment either process writes to a shared page, the CPU raises a protection fault: PTE is present but write-protected. The kernel's fault handler sees the COW flag, allocates a fresh physical page, copies the old contents over, points the faulting process's PTE at the new page with the write bit restored, and decrements the old page's refcount. From the process's view, the write was atomic and instant — it never knows. Each process ends up with a private copy of exactly the pages it modified. That's why fork's cost is proportional to the number of page table entries, not the memory size: microseconds even for a multi-GB address space.
Then comes the real punchline: fork is almost always followed by exec, which tears down the whole duplicated address space and builds a fresh one. The COW machinery is precisely why fork + exec is the cheap standard: the duplicate is never materialized at all.
Tradeoffs and edge cases worth naming:
- vfork shares the address space without COW and blocks the parent until exec — a historical optimization, now mostly redundant.
- fork in a multithreaded process duplicates only the calling thread; other threads vanish, and held locks in the child stay held by threads that no longer exist.
- A fork bomb is just fork in a loop without exec — COW makes each fork cheap enough to exhaust PIDs and memory.
- Overcommit matters: the kernel must be confident the shared pages can be duplicated later, which is why
vm.overcommit_memoryexists.
A strong closing line: fork copies mappings, not memory; COW is a deferred copy triggered by protection faults, and it exists to make the fork-then-exec pattern nearly free.