Page Fault 처리과정
리눅스 커널은 Physical memory를 관리하기 위해 Virtual Address를 사용한다. 각 Virtual Address는 Physical Address와 매핑 되어 Page Table에서 entry
로 Physical Memory의 페이지를 관리한다.
프로세스는 생성되면 4GB 공간의 address space
를 가지게 되며, 이를 VMA(Virtual Memory Address)
라 한다. VMA
는 User 공간과 Kernel 공간으로 나뉘어 관리되며, 프로세스가 진행하는 작업을 관리하기 위한 stack이 각각 user stack
과 kernel stack
으로 존재한다.
Stack은 8KB의 크기로, 4KB의 User space와 3KB의 kernel space, 1KB의 thread info를 가진다. Thread information은 진행 중인 프로세스의 정보를 담고 있으며, page fault를 처리할 때 중요한 역할을 하게 된다.
커널은 페이지를 디스크로부터 들고 오는 비용이 비싸기 때문에, 한 번 가져온 페이지를 캐시에 저장하여 다음에 다시 사용할 때, 메모리에서 바로 들고 오기 위해 페이지 캐시를 사용한다. 그 중에서도 Swap 캐시는 Evict할 페이지를 관리하고 있다. 그 이유는 Evict 할 페이지를 다시 가져오려고 하면 그 비용이 비싸기 때문에 일단 Swap 캐시에서 저장하였다가 LRU 방식으로 Evict 하고 있다.
Swap 캐시는 여러 개의 Swap Area
로 구성되어 있으며, Swap Area
는 각 페이지를 Swap Entry
로 관리한다. Swap entry
는 Evict 될 페이지의 리스트로, 아직 메모리에 존재할 수도 있고 Disk로 Evict 되었을 수도 있다.
프로세스가 작업을 수행하기 위해 페이지에 접근하려 하면, VMA
상의 page를 Page Table을 통해 Physical Page로 변환하여 사용하려 할 것이다. 이 때, page가 존재하지 않거나 데이터가 비어 있을 경우, Page fault가 발생하게 된다.
Page fault가 발생하게 되면, 커널은 do_fault_page
함수를 통해 이를 처리하게 된다.
do_fault_page
는 먼저, 프로세스를 관리하는 stack에서 thread information를 사용하여 현재 수행 중인 프로세스의 영역인 VMA
를 가져온다. 그리고 VMA
안의 fault 페이지에 대해 유효한 physical Memory 범위인 지, Read only page는 아닌지, 커널 영역의 페이지는 아닌 지 여러 유효 검사를 하게 된다.
유효한 영역의 페이지의 데이터가 없는 경우, handle_mm_fault
함수를 통해 페이지를 처리한다. 이 경우에는 VMF(Virtual Memory Fault)
라는 구조체를 사용하여, fault 페이지를 따로 관리하게 되며, 우리가 주로 살펴볼 Swapped out된 경우는 do_swap_page
함수를 호출하여 이를 관리하게 된다.
VMF
자료구조의 중요한 부분은 다음과 같다.
Do_swap_page
는 Page Table Entry
를 Swap Cache
의 Swap Entry
로 바꾸어 진행한다. 그 이유는 앞서 언급하였듯이 evict 될 페이지는 Swap Cache
에서 관리하고 있기 때문이다.
Do_swap_page
가 Page Table Entry
를 Swap Entry
로 바꾸었다면, 해당 Entry에 대하여 페이지가 현재 메모리 상에 존재하는지, 디스크로 evict 됐는지 검사한다. 만약 Memory 상에 남아 있다면, 페이지를 리턴하고 Swap 캐시에서 제거된다.
만약 페이지가 메모리 상에 존재하지 않는다면, 커널은 페이지를 디스크로부터 가져오려 할 것이다. 이때, 앞에서 말한 것처럼 디스크와의 I/O 연산은 비싸기 때문에 커널은 fault page 외에 다른 페이지를 몇 개 더 가져와 I/O 연산을 줄이려 한다. (이를 prefetching
, readahead
라 한다.)
Prefetching은 Swap Area
상에서 연속된 entry
를 여러 개 가져오는 방식으로 동작하는데, 이 때 Swap Entry
를 메모리에 존재할 수도 있다고 했기 때문에 각 Entry에 대해서도 메모리에 존재하는 지 검사하게 된다. 이후 메모리에 존재하지 않는 Entry
들은 새로 페이지를 할당한 후, 디스크로부터 페이지를 가져오고, 그 페이지 데이터를 새로 할당한 페이지에 저장하게 된다.