When a process is created via fork, it starts out with a page directory
and a page or so of the executable. So the page fault handler is the
source of most of a processes' memory.
The page fault handler <#2101#> do_page_fault()<#2101#> retrieves the faulting address
from the register cr2. The error code (retrieved in sys_call.S)
differentiates user/supervisor access and the reason for the fault~---
write protection or a missing page. The former is handled by <#2102#>
do_wp_page()<#2102#>
and the latter by <#2103#> do_no_page()<#2103#>.
If the faulting address is greater than TASK_SIZE the process receives a
SIGKILL. <#2104#> [Why this check? This can only happen in kernel mode because
of segment level protection.]<#2104#>
These routines have some subtleties as they can get called from an
interrupt. You can't assume that it is the `current' task that is executing.
<#2105#> do_no_page()<#2105#> handles three possible situations:
- The page is swapped.
- The page belongs to the executable or a shared library.
- The page is missing~--- a data page that has not been allocated.
In all cases <#2108#> get_empty_pgtable()<#2108#> is called first to ensure the
existence of a page table that covers the faulting address. In case 3
<#2109#> get_empty_page()<#2109#> is called to provide a page at the required
address and in case of the swapped page, <#2110#> swap_in()<#2110#> is called.
In case 2, the handler calls <#2111#> share_page()<#2111#> to see if the page is
shareable with some other process. If that fails it reads in the page
from the executable or library (It repeats the call to <#2112#>
share_page()<#2112#> in case another process did the same meanwhile). Any
portion of the page beyond the brk value is zeroed.
A page read in from the disk is counted as a major fault (<#2113#>
maj_flt<#2113#>). This happens with a <#2114#> swap_in()<#2114#> or when it is read
from the executable or a library. Other cases are deemed minor faults
(<#2115#> min_flt<#2115#>).
When a shareable page is found, it is write-protected. A process that
writes to a shared page will then have to go through <#2116#>
do_wp_page()<#2116#> which does the copy-on-write.
<#2117#> do_wp_page()<#2117#> does the following:
- send SIGSEGV if any user process is writing to current <#2119#> code_space<#2119#>.
- If the old page is not shared then just unprotect it.
Else <#2120#> get_free_page()<#2120#> and <#2121#> copy_page()<#2121#>. The page
acquires the dirty flag from the old page. Decrement the map
count of the old page.