When a page fault occurs for a virtual address for any process how does the linux/unix operating system determine whether that page (of that virtual address) was swapped previously present in memory and swapped out to disk (i.e. that page is currently present in swap space) or that page was never loaded to memory before (i.e. that page is not present in swap space)?
First we need to look at what happens at the hardware level. A page fault happens when the MMU attempts to dereference a virtual address and finds an invalid descriptor for that address. When this happens, the processor executes a trap: it switches to kernel mode, jumps to a predefined address (the trap vector) and fills in some registers to indicate that a page fault happened, and enough information to allow the kernel to determine what the requested address was, what instructions caused the fault, and in what task. I'm giving the general idea here, the concrete details vary between processor architectures.
The trap handler code, which is part of the kernel, examines registers and memory to determine the nature of the fault (the same handler may be invoked for different types of exceptions), the requested address and which process that was previously active. It then consults some data structures that indicate what is supposed to be mapped in that process at that address. Here again the nature of the data structure varies between processor architectures, and also between Unix variants. Some processor architectures have enough bits in an invalid descriptor that aren't interpreted by the MMU to store a swap sector number, in which case the kernel doesn't need to consult any other data structure. If this is not the case, the kernel will consult a data structure that's attached to the process and describes its memory mappings.
The same mechanism may also determine several other things, such as:
- The page needs to be loaded from a file, for memory-mapped files.
- The memory is mapped but the operation was not authorized, e.g. it was an attempt to write to read-only memory. In this case, the kernel arranges to switch control to the process's SIGSEGV signal if it has one, and otherwise the process is terminated.
- An attempt was made to write to a page that is marked as read-only for the CPU, but marked as copy-on-write. In that case the kernel makes a copy of the page.
If the kernel manages to obtain a page in RAM that has the content that the process expects, it updates the process's memory map to reflect that. Then the kernel transfers control back to the process, like on a context switch; but instead of returning control just after the instruction that the process executed, it returns control just before this instruction, so that the faulting instruction is executed again, this time successfully.
Thank you for the answer, but accepting the other one as it more accurately answers my question. Sep 3, 2015 at 18:09
You did not mention the most common case: The MMU detects a reference to an address for which no address translation (Page Table Entry) exists inside the registers of the MMU. This is called a "descriptor fault" or a "minor page fault" (this is the related name in the statistics from
struct rusage) such faults happen at least for those MMUs that do not implement auto-loading of PTEs. MMU management happens in the HAT (Hardware Address Translation) layer driver that is called by segment driver.– schilySep 3, 2015 at 18:17
The low level page fault handler in the OS (that is listed in the trap table from the CPU) get's the fault address from the CPU and uses this fault address to check the entries in process's address space description table. This table contains a list of segment descriptors that each contain a base address and a size. If the address is not in that list. the OS sends a SIGSEGV (segmentati violati).
If the address could be found, the segment table entry that is responsible for the address range that includes the fault address also holds a pointer to the driver functions of the related segment driver.
A segment driver manages the VMEM to background memory actions. If the address is related to swap space, then the name of the responsible driver is
There are many segment drivers, e.g. a segment driver for every filesystem as basically all filesystem data I/O operations are handled via mmap().
by segment table do you mean Global descriptor table and local descriptor table? As I remember it traverses
mmstructto determine if its a SIGSEGV or not. Sep 2, 2015 at 13:56
The global list is in
struct as, see usr/src/uts/common/vm/as.h and each entry is of
struct seg, see usr/src/uts/common/vm/seg.h. I edited my original text, to make it better understandable. The original handler is called "as_fault()"– schilySep 2, 2015 at 14:51