메모리 스와핑은 물리 메모리의 활용을 극대화하기 위한 메모리 회수기법입니다.
메인 메모리의 프레임들이 모두 할당된다면, 시스템은 유저프로그램이 요청하는 메모리 할당 요청을 더 이상 처리할 수 없습니다.
이에 대한 한 가지 해결 방법은 현재 사용되지 않고 있는 메모리 프레임들을 디스크로 스왑 아웃 하는 것입니다.
이는 일부 메모리 자원들을 해제 시켜서 다른 어플리케이션들이 이 자원들을 사용할 수 있게 해 줍니다.
모든 스와핑 연산은 명시적으로 호출되는 것이 아니라 함수 포인터로 호출됩니다.
이 연산들은 struct page_operations file_ops의 멤버변수로서 각 페이지의 initializer에 대한 operation으로 등록되어있습니다.
이를 위해서 우리는 anon.c file을 수정할 것
이 기능에서는 스왑 디스크를 설정. 또한 스왑 디스크에서 사용 가능한 영역과 사용된 영역을 관리하기 위한 데이터 구조가 필요. 스왑 영역도 PGSIZE(4096바이트) 단위로 관리
const size_t SECTORS_PER_PAGE = PGSIZE / DISK_SECTOR_SIZE; // 256KB/512B -> 512
/* Initialize the data for anonymous pages */
// anonymous page를 위한 data를 초기화함
void
vm_anon_init (void) {
/* TODO: Set up the swap_disk. */
swap_disk = disk_get(1,1); // swap disk를 받아줌
size_t swap_size = disk_size(swap_disk) / SECTORS_PER_PAGE; // 할당된 swap_disk의 사이즈를 512로 나눔
swap_table = bitmap_create(swap_size); // swap_size에 맞는 bitmap을 만들어서 swap_table로 반환함
}
swap을 지원하기 위해서 anon_page에 정보를 추가해줘야함
/* Initialize the file mapping */
bool
anon_initializer (struct page *page, enum vm_type type, void *kva) {
/* Set up the handler */
page->operations = &anon_ops; // page->operation 에 anonymous type을 넣어줌
struct anon_page *anon_page = &page->anon; // page->anon 의 주소를 anon_page로 연결
}
disk 에서 memory로 anonymous_page를 swap해줌
/* Swap in the page by read contents from the swap disk. */
static bool
anon_swap_in (struct page *page, void *kva) {
struct anon_page *anon_page = &page->anon; // anon_page에 page->anon 주소를 연결하고
int page_no = anon_page->swap_index; // swap_index - 몇번째 swap data랑 바꿀것인지
if(bitmap_test(swap_table, page_no) == false) // swap_talbe(전역변수) 에서 page_no를 bit로 찾을건데 없으면 false 있으면 해당 index를 return함
return false;
for ( int i = 0; i < SECTORS_PER_PAGE; i++){
disk_read(swap_disk, page_no*SECTORS_PER_PAGE+ i, kva + DISK_SECTOR_SIZE* i);
//swap dist에서 page_no*SECOTRS_PER_PAGE+ i sec를 kva+DISK_SECTOR_SIZE* i 만큼 읽음
}
bitmap_set(swap_table, page_no, false);
// page_no을 index로 swap_table 안에 설정함
return true;
}
content를 swap disk에 기록 후 page를 swap out 함
/* Swap out the page by writing contents to the swap disk. */
static bool
anon_swap_out (struct page *page) {
struct anon_page *anon_page = &page->anon;
/* for project 3 - start */
int page_no = bitmap_scan(swap_table, 0, 1, false); // swap_table에 value로 설정된 애들중 첫번째 index를 반환
if(page_no == BITMAP_ERROR)
return false;
for (int i = 0; i < SECTORS_PER_PAGE; i++){
disk_write(swap_disk, page_no*SECTORS_PER_PAGE+ i, page->va + DISK_SECTOR_SIZE* i);
//swap disk로 page_no*SECOTRS_PER_PAGE+ i sec를 kva+DISK_SECTOR_SIZE* i 만큼 씀
}
bitmap_set (swap_table, page_no, true);
pml4_clear_page(thread_current() -> pml4, page->va);
anon_page->swap_index = page_no;
return true;
/* for project 3 - end */
}
file-backed 페이지의 내용은 파일에서 가져오므로 mmap된 파일을 백업 저장소로 사용해야 합니다. 즉, file-backed 페이지를 evict하면 해당 페이지가 매핑된 파일에 다시 기록됩니다.
static bool
file_backed_swap_in (struct page *page, void *kva) {
struct file_page *file_page UNUSED = &page->file;
if (page == NULL)
return false;
struct container *aux = (struct container *)page->uninit.aux;
struct file *file = aux->file;
off_t offset = aux->offset;
size_t read_byte = aux->read_byte;
file_seek(file, offset);
if(file_read(file, kva, read_byte) != (int)read_byte)
return false;
memset(kva + read_byte, 0, PGSIZE - read_byte);
return true;
}
static bool
file_backed_swap_out (struct page *page) {
struct file_page *file_page UNUSED = &page->file;
if (page == NULL)
return false;
struct container *aux = (struct container *)page->uninit.aux;
if(pml4_is_dirty(thread_current()->pml4, page->va)){
file_write_at(aux->file, page->va, aux->read_byte, aux->offset);
pml4_set_dirty(thread_current()->pml4, page->va, 0);
}
pml4_clear_page(thread_current()->pml4, page->va);
}