크래프톤 정글

Pintos Project3 - Virture Memory Test case 트러블 슈팅 (read-boundary)

Jerry_K 2024. 12. 5. 10:38

Anonymous Page까지 구현을 하고,

make check를 돌려보았지만, read-boundary의 테스트 케이스가 통과하지를 못했다. 

디버깅을 돌려보니 check_address 함수 내에 pml4_get_page 부분이 자꾸 터지는 것을 보았다.

 

이 부분에 대해 나와 비슷한 문제를 겪는 사람들이 있어서 이 부분에 대해서 포스팅을 해본다 ! 

먼저 테스트 파일들을 확인해보자.

 

Test Case : read-boundary.c 파일

buffer = get_boundary_area () - sizeof sample / 2;
byte_cnt = read (handle, buffer, sizeof sample - 1);
  • get_boundary_area 함수는 페이지의 경계 값을 가져옴
  • sample.txt 파일 전체 크기를 반으로 나누어 경계값에 빼줌
    • ex) Page1과 Page2의 경계가 있다면, sample.txt 반을 각각의 Page에 들어가도록 
    • 아래와 같은 느낌
주소        :  0x1000   0x1FD1   ...  0x1FFF |   0x2000   ...  0x2032 ... 0x2FFF
페이지      : [ 페이지 A (0x1000 ~ 0x1FFF) ]  |  [ 페이지 B (0x2000 ~ 0x2FFF)   ]
데이터 흐름 : [ 빈 공간  buffer → 데이터 → ]  |  [ → 데이터 계속 저장 → 빈 공간 ]

 

 

이번에는 오류가 발생하는 함수 부분을 살펴보자. 

check_address  함수 (syscall.c)

#ifndef VM
void check_address(void *addr) {
    if (is_kernel_vaddr(addr) || addr == NULL || pml4_get_page(thread_current()->pml4, addr) == NULL)
        exit(-1);
}
#endif

#ifdef VM
void check_address(void *addr) {
    if (is_kernel_vaddr(addr) || addr == NULL )
        exit(-1);
    spt_find_page(&thread_current()->spt,addr);
}
#endif
  • VM 부분과 이외 프로젝트로 나눠짐 (이외 프로젝트 부분은 다루지 않음)
  • VM 부분에서 check_address 부분에 pml4_get_page 부분이 사라지고, spt_find_page 함수가 추가해야 함
    • VM에 Lazy Loading 때문에 pml4로 가면 안되고 spt에서 찾아야함 

 

read 함수 (syscall.c)

int read(int fd, void *buffer, unsigned length) {
    thread_t *curr = thread_current();
    check_address(buffer);

    . . .
    
    return bytes;
}

 

 

궁금증❗

단순히 spt에서 page를 찾는 spt_find_page 함수인데, check_address에 쓰는게 의미가 있나 ? 
(check_address 부분에 spt_find_page를 쓰지 않으면 read-boundary 테스트 케이스 fail이 됨)

 

 

load_segment는 프로그램 실행 시 초기화 과정에서 실행 파일의 필요한 부분을 SPT에 등록한다.

이때 모든 페이지가 load_segment에서 SPT에 등록되지 않는다.

보통 첫 번째 페이지는 SPT에 등록되지만 두번째 페이지는 Lazy Loading 때문에 SPT에 등록되지 않을 수 있다.

실행 도중 접근 가능성이 낮은 페이지나 동적으로 확장되는 영역(예: 스택, 힙, 추가 데이터)은 초기화 단계에서 등록되지 않을 수도 있다. 

 

read-boundary 테스트 케이스 같은 경우는 두 개 이상의 페이지에 걸쳐 데이터를 복사해서 spt_find_page 없이는 fail이 뜨게 되는 것이다.  

 

그러면 spt_find_page의 역할을 뭘까 ?

간단히 말하자면, 페이지 폴트를 발생시켜 해당 주소에 대한 정보를 SPT에 추가해준다. 

즉, SPT에 등록되지 않은 페이지를 Page Fault를 통해서 데이터를 로드한다. 

 

만일 단일 페이지 내에서 작업이라면 굳이 spt_find_page 함수가 필요 없다. 

SPT에 등록된 페이지만 접근하므로 경계 조건에 대한 특별한 처리가 필요 없기때문이다. 

 

이해를 위한 예시

  • 첫 번째 페이지: 초기화된 데이터(.data)를 포함.
  • 두 번째 페이지: 경계 이후의 확장 영역이거나 아직 접근되지 않은 부분.
+----------+----------+
|  Page 1  |  Page 2  |
|  등록됨  |  미등록   |
+----------+----------+
 ^ 경계를 넘어 Page 2 접근 시:
   - SPT에서 Page 2 정보를 찾지 못함 -> 페이지 폴트 발생.
   - 페이지 폴트 핸들러에서 Page 2를 처리 후 등록.

 

 

이렇게하면 왜 spt_find_page를 써야하는지를 알 수 있다.