Swap In/Out
→ vm_anon_init()
→ anon_initializer()
→ anon swap out()
→ anon swap in()
page table entry에 있는 비트쌍인 accessed bit와 dirty bit를 이용해서 page 재배치 알고리즘을 구현하고, 내쫓을 frame을 반환한다.
static struct frame *
vm_get_victim(void)
{
/* TODO: 페이지 교체 정책은 여러분이 결정할 수 있습니다. */
struct thread *curr = thread_current();
struct list_elem *e = list_begin(&frame_table);
while(e != list_end(&frame_table)){
struct frame *f = list_entry(e, struct frame, frame_elem);
struct page *page = f->page;
// 만약 frame이 존재하지 않는다면...
if(f == NULL){
PANIC("[vm_get_victim] frame이 존재하지 않습니다...\n");
}
if (VM_ANON != page->operations->type){
e = list_next(e);
continue;
}
if(pml4_is_accessed(curr->pml4, page->va)){
/* accessed bit를 reset()을 사용해서 0으로 만들고 넘어간다.
* 내 생각으로는 이미 한 번 접근한 page는 접근 bit를 1로 만들지만 다시 접근했을 때 0으로 초기화 해주는 이유는
* 기존의 page가 메모리 공간을 차지함으로써 새로운 page가 로드되는 걸 막기 때문이지 않을까?? */
pml4_set_accessed(curr->pml4, page->va, false);
e = list_next(e);
continue;
}
list_remove(e);
return f;
}
PANIC("[vm_get_victim] frame victim이 존재하지 않아요 ㅠㅠ\n");
}
static struct frame *
vm_get_frame(void)
{
struct frame *frame = malloc(sizeof(struct frame));
if (frame == NULL)
{
PANIC("TODO");
}
// NOTE: PAL_USER인 이유는 주석에 user space pages를 본 함수로 할당받아야 한다고 명시되어 있어서 이렇게 함. 악성 프로그램이 고의로 커널풀 메모리 고갈시키는 거 막기 위한 분리.
frame->page = NULL;
ASSERT(frame->page == NULL);
frame->kva = palloc_get_page(PAL_USER);
if (frame->kva == NULL)
{
free(frame); // frame 메타 데이터 자료구조 해제
frame = vm_evict_frame(); // TODO: evict frame 함수가 아직 구현되지 않음.
}
ASSERT(frame->kva != NULL);
// frame lock 걸어줘야 함.
list_push_back(&frame_table, &frame->frame_elem);
return frame;
}
frame은 vm_get_frame()에서 push해준다.
/* 하나의 페이지를 교체하고 해당 프레임을 반환합니다.
* 실패 시 NULL을 반환합니다. */
static struct frame *
vm_evict_frame(void)
{
/* TODO: victim을 스왑 아웃하고 교체된 프레임을 반환하세요. */
struct frame *victim UNUSED = vm_get_victim();
struct thread *curr = thread_current();
struct page *page = victim->page;
struct frame *change_f;
// 퇴거시킬 때 dirty bit를 check해야하는데 dirty bit가 1이면 swap out()을 진행하고, 0이면 그냥 버려도 된다.
if(pml4_is_dirty(curr->pml4, page->va)){
if(!swap_out(page)){
PANIC("[vm_evict_frame]swap out fail!!!\n");
}
}
page->frame = NULL;
victim->page = NULL;
return victim;
}
vm_anon_init()
→ disk를 초기화 한다.
→ disk의 정보를 가져와서
→ disk size를 계산한다.
/* 익명 페이지를 위한 데이터를 초기화합니다 */
void vm_anon_init(void)
{
// TODO: swap 구현 시 아래 내용을 추가해야 함. 사유는 그때 가서 이해하기.
/* swap_disk를 설정하세요. */
disk_init();
swap_disk = disk_get(1, 1); // NOTE: disk_get 인자값 적절성 검토 완료.
size_t swap_size = disk_size(swap_disk); // SECTORS_PER_PAGE;
// swap_table = bitmap_create(swap_size);
}