Linux – How to two identical virtual addresses point to different physical addresses

forkhardwarelinuxmemory

Following a fork() call in Linux, two processes (one being a child of the other) will share allocated heap memory. These allocated pages are marked COW (copy-on-write) and will remain shared until either process modifies them. At this point, they are copied, but the virtual address pointers referencing them remain the same. How can the MMU (memory management unit) distinguish between the two? Consider the following:

  1. Process A is started
  2. Process A is allocated a memory page, pointed to by the virtual address 0x1234
  3. Process A fork()s, spawning process B
  4. Process A and B now share virtual address 0x1234, pointing to the same physical memory location
  5. Process B modifies its 0x1234 memory page
  6. This memory page is copied and then modified
  7. Process A and B both have virtual address 0x1234, but this points to different physical memory addresses

How can this be distinguished?

Best Answer

One of the things the kernel does during a context switch between processes is to modify the MMU tables to remove entries that describe the previous process's address space and add entries that describe the next process's address space. Depending on the processor architecture, the kernel and possibly the configuration, this may be done by changing a processor register or by manipulating the page tables in memory.

Immediately after the fork operation, due to copy-on-write, the MMU tables for both processes have the same physical address for the virtual address 0x1234. Once again, these are two separate table, that happen to have identical entries for this particular virtual address.

The descriptor for this page has the read-only attribute. If a process tries to write (it doesn't matter whether it's A or B), this triggers a processor fault due to the permission violation. The kernel's page fault handler runs, analyzes the situation and decides to allocate a new physical page, copies the content of the read-only page to this new page, changes the calling process's MMU configuration so that 0x1234 now points to this freshly-allocated physical page with read-write attributes, and restarts the calling process on the instruction that caused the fault. This time the page is writable so the instruction will not trap.

Note that the page descriptor in the other process is not affected by this operation. In fact, it might be, because the kernel performs one more action: if the page is now only mapped in a single process, it's switched back to read-write, to avoid having to copy it later.

See also What happens after a page fault?

Related Question