[pintOS] 3주차 VM: 진행 과정 기록

Johnny·2021년 10월 21일
0

개발일지 (정글)

목록 보기
5/7

CHECK POINT 1

  • 상태
    • 기존에 통과하던 테스트케이스들이 실패
    • 문제가 되는 테스트케이스 예시 :pintos -v -k -T 60 -m 20 --fs-disk=10 -p tests/userprog/args-none:args-none --swap-disk=4 -- -q -f run args-none
  • 개선 요구 사항: Implement Supplemental Page Table
    • process 를 새로 생성하거나 fork할 때 실행되는 supplemental page table과 관련된 기능들이 구현되어야 함 (supplemental_page_table_init() 등)
  • 진행 과정
    • ((vm.h)) supplemental_page_table 생성 및 초기화
      • spt의 자료구조를 선택해 반영 (해시 테이블로 선택)
      • spt인 hash의 초기 설정은 딱히 안해주어도 되려나?
    • ((vm.c)) supplemental_page_table_init() 구현
      • 입력값으로 들어온 thread의 spt를 initiate
      • page_hash(), page_less() 구현 필요
      • hash_init() 활용
      • hash_init()은 malloc을 사용해 bucket에 메모리를 할당하는데, 실패한 경우 처리는 어떻게?
    • ((vm.h)) struct page에 hash table을 위한 hash_elem 추가
      • struct hash_elem h_elem
    • ((vm.c)) page_hash(), page_less() 구현
      • hash_entry 등을 활용
    • ((vm.c)) spt_find_page() 구현
      • spt에서 va를 가진 page를 찾기 위해, 동일한 va를 가진 dummy page를 생성해서 hash_find의 인자로 넘겨줌
      • dummy page를 spt_find_page 내에서 지역변수로 정의해도 되겠지?
      • hash_find() 활용
    • ((vm.c)) spt_insert_page() 구현
      • spt에 page를 추가하며, 추가하기 전에 spt에 동일한 va(virtual address)가 이미 존재하는지 체크해주어야 함
      • hash_insert() 활용
    • ((vm.c)) spt_remove_page() 업데이트? 일단 보류
      • hash table을 정리하는 역할을 이 함수에서 수행해야 할까?
      • hash table에서 추가된 page를 제거하는 타이밍이 언제일까?
        • 개별적으로? process가 종료될 때 한 번에?

CHECK POINT 2

  • 상태
    • check point 1과 동일
    • (git book의 가이드에 따라 Frame Management 파트로 분리해 진행)
  • 개선 요구 사항: Frame Management
    • palloc으로 user 영역에서 page를 할당 받아, frame 구조체의 kva (kernel virtual address)에 연결
      • 즉, frame은 물리메모리의 user 영역 내 page를 하나씩 들고 있음
      • 이 때, frame 구조체는 malloc으로 kernel 영역에 할당 받음
    • 만약 user 영역에 추가 page 할당이 불가능할 경우, 기존의 frame을 재활용
      • frame에 연결된 기존 page를 swap out 한 뒤, 해당 frame에 다른 page를 연결
      • 그렇기 때문에 malloc으로 할당 받은 frame의 영역을 바로 free하지 않음
    • 결과적으로 frame도 필요할 때마다 추가되는 방식임
      • (책에서 설명하듯) 물리메모리의 가능한 user 영역들에 frame을 모두 할당해 놓는 것이 아니라, frame과 그 frame에 연결된 page를 만드는 방식임
  • 진행 과정
    • ((vm.c)) frame_table 생성 및 초기화
      • Allows efficient implementation of eviction policy of physical frames
      • 생성된 frame들을 보관하는 곳
        • 자료형은 일단 list로 결정
        • 전역 변수? 정적 변수? (아니면 gitbook 가이드대로 malloc?) vm.c에서만 접근한다면 정적 변수로 설정
      • 주로 swap_in, swap_out할 때 victim을 정할 때 활용됨
      • vm_init()에서 list_init()으로 초기화해주어야 함
    • ((vm.h)) struct frame 업데이트
      • frame table의 자료형에 맞게 frame 구조체 수정
      • struct list_elem elem;
    • ((vm.c)) vm_get_frame () 구현
      • palloc_get_page으로 user 영역에서 page 한 개 할당 받기
      • palloc에 성공했을 때
        • malloc으로 frame 생성 및 할당 받은 page 연결
        • frame table에 추가
          • 일단 push_back으로 처리하되, 추후 victim 정하는 정책에 맞게 수정
      • palloc에 실패했을 때
        • PANIC("TODO") 처리
    • ((vm.h)) struct page 업데이트
      • page의 상태 정보 중 writable 추가
        • vm_do_claim_page ()에서 pml4_set_page()로 pte를 추가할 때 넣어주기 위함
        • bool writable;
    • ((vm.c)) vm_do_claim_page () 구현
      • page table(pml4)에 page table entry 추가 (page의 va, frame의 kva 활용)
      • swap_in()을 통해 실제 물리 메모리에 올림
      • pml4_set_page() 활용
      • project 2 코드 중 install_page() 참고
    • ((vm.c)) vm_claim_page () 구현
      • spt에서 매개변수 va에 해당하는 page를 찾아 page table에 pte 추가
      • spt_find_page(), vm_do_claim_page () 활용

CHECK POINT 3

  • 상태
    • check point 1,2와 동일
    • (git book의 가이드에 따라 Frame Management 파트로 분리해 진행)
  • 개선 요구 사항: Page Initialization with Lazy Loading
    • 하나의 executable이 새로운 process에 load될 때, load할 대상(?)을 load_segment 함수를 통해 순차적으로 load하게 됨
    • project 2까지의 코드에서는 모든 것들을 한꺼번에 physical memory에 load했었지만, 이제는 lazy_load가 되도록 수정해주어야 함
  • 진행 과정
    • ((vm.c))vm_alloc_page_with_initializer() 구현
      • 이 함수는 앞서 이야기한 load_segment()에서 실행되며, 해당 process(thread)의 supplemental page table을 활용해, 각 page가 필요한 시점에 물리메모리에 load 될 수 있도록 (즉 lazy_load)될 수 있도록 처리해주어야 함
      • malloc() 활용해 page 생성
        • 나중에 vm_dealloc_page()을 통해 free 하게 됨
      • uninit_new() 활용해 UNINIT 타입으로 page를 초기화
        • lazy load 시점에 변경될 타입을 확인 및 전달 시 VM_TYPE macro 활용
          • macro 사용 이유? 나중에 VM_MARKER_0 (stack을 의미) 등으로 vm_type에 추가적인 마커를 표시하기도 하기 때문
        • 해당 TYPE에 맞게 lazy load 시점에 사용할 initializer 함수도 uninit_new()에 전달
      • spt_insert_page() 활용해 현재 thread의 spt에 새로 생성 및 초기화된 page를 추가
    • ((uninit.c)) uninit_initialize() 체크
      • vm_do_claim_page()을 통해 swap_in 될 때, page가 uninit 상태였다면 실행되는 함수
      • 인자로 전달된 page를 실제 type으로 다시 초기화하여 kva가 가리키는 물리메모리에 올려놓는 역할 수행
      • 이 함수가 실행될 때 page는 이미 thread의 page table(pml4)에 올라간 상태임
    • ((exception.c)) page_fault()에서 임시 코드 제거
      • project 2에서 추가되었던, page_fault 발생 시 프로세스를 종료하는 코드 제거
    • ((anon.c)) vm_anon_init() 체크
      • swap 관련된 부분은 나중에 구현
    • ((anon.c)) anon_initializer() 체크
      • page의 operations 함수들을 anon_ops로 교체
    • ((process.c)) project2에서의 load_segment() 체크
      • load_segment()와 lazy_load_segment() 구현을 위해 project2 때 load_segment에서 수행하던 작업들을 참고
      • project2 때는 수행했지만 project3에서는 하지 않고 있는 작업들이 lazy_load_segment에게 이관됨
        • file_seek(file, ofs)로 파일에서 읽기 시작할 position을 수정
        • file_read(file, kpage, page_read_bytes)로 file에서 page_read_bytes만큼의 데이터를 읽어 kpage(물리메모리)에 저장
        • file_read() 실패 시 palloc_free_page()
        • memset() 으로 page의 남은 영역 0으로 변경
        • install_page() 로 pte를 page table(pml4)에 등록
      • lazy_load_segment()에 인자로 전달할 값 묶음
        • file: process가 종료되기 전까지는 file이 계속 열려있으니 주소값만 전달해도 되겠지?
        • ofs, page_read_bytes, page_zero_bytes
    • ((process.c)) load_segment() 업데이트
      • lazy_load_segment()에서 필요한 정보들을 aux에 담아 vm_alloc_page_with_initializer()의 마지막 인자로 전달
      • malloc을 활용해 load_info 형식으로 aux를 구성
      • 주의!! lazy_load에서 file_seek으로 ofs를 매번 다시 설정해주어야 하며, 이를 위해 ofs를 업데이트 해주어야 함
        • ofs += page_read_bytes;
    • ((process.c)) lazy_load_segment() 구현
      • 위에서 체크했던 내용들을 상황에 맞게 실행
        • file_seek(file, ofs)
        • file_read(file, page->frame->kva, page_read_bytes)
        • file_read() 실패 시 이번에는 vm_dealloc_page 사용
        • memset()
        • lazy load 되는 시점에는 page가 이미 page table에 등록된 상태
      • aux의 역할이 끝났으므로 malloc으로 할당되었던 메모리 free
    • ((process.c)) setup_stack() 구현
      • project2에서 하던 작업들
        • kpage = palloc_get_page (PAL_USER | PAL_ZERO);로 stack을 위한 영역 할당
        • 영역 할당에 성공 시 install_page (((uint8_t *) USER_STACK) - PGSIZE, kpage, true);로 page table(pml4)에 pte 추가
          • 이 때, 가상 주소를 stack의 위치로 설정
        • if_->rsp = USER_STACK;로 stack pointer의 위치 수정
      • project3에 적용
        • vm_alloc_page()로 페이지 할당
          • 이 때, type에 marker 표시
          • 이 때, upage에 stack의 위치 전달
        • vm_claim_page()로 즉시 물리메모리에 배치
          • TODO 실패 시 page를 찾아 dealloc 해주어야 함
        • if_->rsp = USER_STACK;로 stack pointer의 위치 수정
    • ((vm.c)) vm_try_handle_fault() 업데이트
      • page fault가 kernel 영역에서 발생한 경우 return false
      • spt_find_page() 활용해 fault를 일으킨 주소값이 supplemental page table에 있는 주소인지 확인
      • spt에 있는 경우 vm_do_claim_page(page)로 물리메모리에 로드
      • return 값이 true일 경우 page_fault()함수가 종료되며, page fault가 해결된 상태(즉 lazy load된 상태)로 다시 user program이 실행됨

CHECK POINT 4

  • 상태
    • exec 관련 testcase 실패
    • fork 관련 testcase 실패
    • wait 관련 testcase 실패
    • 등등
  • 개선 요구 사항: revisit the supplemental page table interface to support copy and clean up operations
    • process fork 시 parent의 spt를 child의 spt로 복제하는 함수 생성
    • process exit 시 spt를 제거하는 함수 생성 (메모리 초기화 필수)
  • 진행 과정
    • ((process.c)) process_exec()에서 spt를 다시 초기화
      • process_cleanup() 과정에서 기존의 spt는 supplemental_page_table_kill()에 의해 삭제되었으므로, 다시 프로그램을 load하고 실행하기 위해서는 spt를 초기화해주어야 함
      • `supplemental_page_table_init(&thread_current()->spt);
    • ((vm.c)) supplemental_page_table_copy() 구현
      • process가 fork되면서 __do_fork_ 내에서 실행됨
        • 이 때 child process의 spt는 supplemental_page_table_init()로 초기화된 상태
      • hash_iterator, hash_first, hash_next, hash_cur 등을 조합해 parent process의 spt 내 page들을 하나씩 복제
        • writable 이 false인 경우 공유할 수도 있으려나?? 일단 모두 복제
      • 복제 시 page의 type에 맞게 처리
        • VM_UNINIT 인 경우
          • parent process에서 vm_alloc_page_with_initializer()로 만들어져 lazy load가 되기를 기다리는 중 (아직 물리메모리에 올라가지 못하고 대기하고 있는 상태)
            • parent의 값들을 어떻게 가져오지?
          • child process에서도 vm_alloc_page_with_initializer() 사용하면 되겠다
            • type, upage, writable 그대로
            • init (lazy_load_segment) 그대로
            • aux는 새로 생성해서 넣어주어야 함
        • VM_ANON 인 경우
          • 이미 uninit 상태를 지나 물리메모리에 올라가 본 page
            • setup_stack 비슷하게 처리하면 될 듯
            • vm_alloc_page(type 그대로, upage 그대로, writable 그대로) 사용해 child process의 spt에 새로운 page를 넣음
            • spt_find_page()로 새로운 spt에서의 page를 찾고
            • vm_do_claim_page()로 해당 page를 물리메모리에 올려버린 뒤
            • memcpy()로 동일한 내용이 되도록 복사
              • 만약 parent page가 disk로 swap 되어 있었다면 어떻게 하지?
                - memcpy 전에 parent page도 물리메모리에 올려놓도록 조치를 해야할까?
          • VM_MARKER_0 인 경우 즉, 스택인 경우를 구분할 필요가 있을까?
            • setupstack은 page를 할당하고, if->rsp 를 초기화해주는 역할
            • 하지만 stack에 해당하는 page도 memcpy를 통해 복사해주면 되고, rsp는 오히려 초기화하면 안됨
            • 스택을 별도로 구분하지 않기로 결정
        • VM_FILE 인 경우
          • 이미 uninit 상태를 지나 물리메모리에 올라가 본 page
            • VM_ANON 일반 상황과 동일하게 처리 가능할 것
            • 일단 아무것도 하지 않는 것으로 처리
    • ((anon.c)) page type으로 스택을 식별할 수 있도록 anon page 수정
      • struct page_operations stack_ops 추가
      • anon_initializer()에서 type 인자를 활용해 구분
    • ((vm.c)) page_destroy() 구현
      • hash_destroy()에 두 번째 인자로 전달할 함수
      • hash_elem로 page를 찾아 page를 destroy
    • ((vm.c)) supplemental_page_table_kill 구현
      • 메모리가 할당되었던 부분
        • hash_init()에서 hash->bucket에 malloc
        • vm_alloc_page_with_initializer()로 생성된 각 page들
      • hash_destroy()를 사용해 page_table 내 page들을 모두 free
        • 두 번째 인자 desctructor을 통해서 page_table에 포함된 page들에 접근
        • free(page) 대신 가이드에 따라 destroy(page)로 처리 (구현해주어야 함)
        • hash_destroy 실행 중에 접근 못하도록 lock을 걸어야 하나? 일단 패스
    • ((uninit.c)) uninit_destroy() 구현
      • page가 들고 있는 load_info를 free 시켜주어야 함
    • ((anon.c)) anon_destroy() 구현
      • frame에 할당된 메모리를 해제해주는 것이 맞을까?
      • frame에 할당된 메모리를 해제한다면, frame이 들고 있는 물리메모리의 페이지도 함께 free 해주어야 함 (palloc_free_page)
      • 그 대신, 나중에 vm_get_frame에서 놀고 있는 frame을 찾도록 할 수도 있을 것 같은데?
      • 그렇다면 일단 page를 frame을 지우지 말고, frame 구조체가 가리키는 page를 NULL로 만들어, 죽은 process의 page가 담겨 있던 frame임을 표시해두자.

CHECK POINT 5

  • 상태

    • project2까지의 testcase 중 read/write 관련된 부분 제외하고 통과
    • 본래는 project2까지의 testcase는 모두 통과해야 한다고 하지만, 일단 넘어가자!
  • 개선 요구 사항: Stack Growth

    • Now, if the stack grows past its current size, we allocate additional pages as necessary.
    • 스택에 공간이 부족한 경우에 page fault가 발생하게 되므로, 스택을 키우는 작업을 vm_try_handle_fault()에서 처리할 수 있음
    • 이 때, vm_try_handle_fault()에서는 fault난 상황이 스택이 부족했던 것인지, 아니면 정말 엄한 장소에 접근하려 한 것인지 체크를 해야 함
    • Allocate additional pages only if they "appear" to be stack accesses. Devise a heuristic that attempts to distinguish stack accesses from other accesses.
    • 이를 위해서 page fault 직전의 user stack pointer의 위치를 기억해야 함
      • 저장하는 이유?
        • page fault를 유발한 주소와 user stack pointer의 위치를 비교하여 page fault가 stack 영역이 부족해 발생한 것인지 판단해주어야 함
          • 이 때, if->rsp가 꼭 유저 영역이 아닐 수도 있음. 즉 커널 모드일 때 page fault가 발생했을 수도 있음
          • 그런데 if->rsp는 유저 모드에서 커널 모드로 전환될 때만 업데이트되므로, 커널 모드에서 작업이 진행되던 중 page fault가 났을 때는 이미 rsp가 커널 모드에서 변경된 상태일 것
          • 그러므로 유저 모드에서 커널 모드로 전환될 때 user stack pointer를 저장해두어야 함
          • 구체적으로 보아 저장하는 타이밍은 user program에서 system call 혹은 page fault가 발생했을 때임
          • Within a system call or a page fault generated by a user program, you can retrieve it from the rsp member of the struct intr_frame passed to syscall_handler() or page_fault(), respectively.
        • 더불어, 스택 영역이 부족한 상황은 메모리에 write하려는 상황일 것임 (단순히 읽는 것이라면 fault도 나지 않았음)
        • 또한, 스택 영역이 부족한 상황은 not_present인 상황일 것임 (read only page는 아닐 것)
  • 진행 과정

    • ((thread.h)) stack pointer를 임시로 보관하는 멤버 생성
      • uintptr_t user_rsp;
    • ((syscall.c)) syscall_handler() 수정
      • user program에 의해 syscall이 발생했을 때 user stack pointer의 위치를 저장해 둠
    • ((exception.c)) page_fault() 수정
      • user program에 의해 page fault가 발생했을 때 user stack pointer의 위치를 저장해 둠
    • ((vm.c)) vm_try_handle_fault() 수정
      • stack growth 가 필요한 상황인지 판단해 처리
        • 접근하려는 주소는 user 영역이어야 함
        • 스택이 부족한 상황이므로 write을 위한 접근
        • 스택이 부족한 상황이므로 not_present (read only가 아님)
        • 접근하려는 주소가 스택 범위 내에 속해야 함
        • stack size는 가이드에 따라 1MB로 제한
    • ((vm.c)) vm_stack_growth() 구현
      • setup_stack() 참고
      • 스택은 한 번에 여러 page가 커져야 할 수도 있음
        • testcase: pt-big-stk-obj

CHECK POINT 6

  • 상태
    • 포인터 관련 testcase에서 read, write 관련된 것 빼고 통과
      • tests/vm/pt-write-code2
  • 개선 요구 사항: Memory Mapped Files
    • 진행 과정으로 대체
  • 진행 과정
    • ((syscall.c)) syscall에 mmap, munmap 양식 추가
      • mmap은 인자 5개를 받아 주소값 리턴
      • munmap은 인자 1개를 받고 리턴값 없음
    • ((file.c)) mmap된 영역을 누적 관리하는 자료 구조 구현
      • mmap된 영역을 munmap 하려면 연이어 할당된 크기 (페이지의 크기)를 알아야 함
      • 그냥 간단히 list로 구현
        • vm_file_init()에서 초기화
      • mmap_list에서 mmap 단위로 관리할 정보를 묶어놓기 위해 mmap_info 구조체 추가
        • file.h에서 추가
    • ((syscall.c)) syscall mmap 구현
      • 입력값 유효성 체크
        • It must fail if addr is not page-aligned or if the range of pages mapped overlaps any existing set of mapped pages, including the stack or pages mapped at executable load time.
        • 첫 번째 인자, 즉 가상주소 공간에서 저장할 주소값이 user 영역이어야 함
        • 가상주소 공간의 주소값과 offset이 page 단위로 나누어 떨어져야 함
        • length가 양의 정수여야 함
        • 가상주소 공간에서 mmap할 영역이 비어 있어야 함 (다른 목적으로 이미 차지된 상태여서는 안됨)
      • file descriptor table에서 fd로 파일 주소값 가져오기
      • file을 reopen해야 할까?
        • testcase: mmap-close 처리를 위해 필요!!!
        • mmap이 lazy load 방식으로 구현되었기 때문에, mmap이 lazy하게 load되기 전에 file이 close되었을 경우 file을 load하지 못하는 상황이 생김
        • 이를 처리하기 위해 새로 연 파일을 넘겨주어야 함
        • (load_segment 에서도 동일한 처리가 필요할까??)
      • do_mmap 실행
    • ((file.c)) do_mmap 구현
      • load_segment() 참고
      • lazy_load_file() 추가로 구현 (lazy_load_segment 참고)
        • read_byte에서 반드시 PGSIZE로 떨어지지 않는다는 점을 처리하는 데서 오래 걸림!
        • lazy_load_segment 부분도 수정해주어야 맞을까? 일단 munmap 처리하고 진행해보자
    • ((file.c)) do_munmap 구현
      • mmap에서 리턴한 시작 주소값을 받아 할당된 범위 전체를 삭제해야 함
      • 다음 페이지가 mmap으로 연결된 페이지인지 아닌지 어떻게 알 수 있을까?
        • mmap된 페이지들을 관리하는 페이지 필요 --> mmap_list 구현 및 활용
      • 연결된 페이지들을 하나씩 제거
        • addr에서 PGSIZE 씩 더해주며 다음 페이지로 이동하여 처리
        • 이 때 spt에서도 page를 제거해주어야 함 (otherwise 에러 발생!)
          - vm_dealloc_page 대신 spt_remove_page를 사용!
          • spt_remove_page에서는 hash_delete로 spt에서 page 제거 처리
          • (lazy_load_segment에서도 spt_remove_page로 수정함)
      • dirty page에 대한 처리 필요
        • spt_remove_page에서 vm_dealloc_page를 콜하고, vm_dealloc_page에서 destroy(page)를 콜하므로, 관련 기능을 위해 file_backed_destroy을 구현해주어야 함
    • ((file.h)) (뒤늦은 추가) struct file_page 구현
      • munmap 등에서 page가 dirty 상태일 때, 다시 저장해주기 위해 file을 들고 있어야 함
      • 파일에 저장할 위치를 파악하기 위해 offset도 들고 있어야 함
    • ((file.c)) file_backed_destroy 구현
      • 해당 page가 dirty 상태인지 pml4_is_dirty 를 활용해 확인
        • dirty 상태일 경우, file, offset, 읽어왔던 size를 활용해 file_seek & file_write
        • 이 때 궁금증은, write할 때의 size가 요청했던 크기(가령 PGSIZE)인지 아님 실제로 읽어들인 크기인지 여부 (일단은 실제로 읽어들인 크기로 설정)
      • 열려 있던 파일을 여기서! 닫아주어야 함
        • 미리 닫아버리면 안됨

CHECK POINT 7

  • 상황
    • swap testcase를 처리해야 하는 상황
  • 개선 요구 사항
    • When the system detects that it has run out of memory but receives a memory allocation request, it chooses a page to evict out to swap disk. Then, the exact state of the memory frame is copied to the disk. When a process tries to access a swapped out page, OS recovers the page by bringing the exact content back to the memory.
  • 진행 과정
    • ((vm.c)) vm_evict_frame 구현
      • vm_get_victim이 잘 되었다는 전제 하에
      • swap out 처리
        • page type에 맞게 처리됨
        • 이 때 swap disk가 꽉 찼을 수도 있음
      • victim이 된 frame을 비워주어야 함
        • 그렇지 않으면 process 간 침범이 발생할 수 있음
        • memset 활용
  • ((vm.c)) clock_lock 추가
    • clock 알고리즘 실행 시 thread 간 race가 발생할 수 있어 lock으로 통제
  • ((vm.h)) struct frame 업데이트
    • 현재 page가 할당된 경우, 해당 thread를 저장하도록 멤버 추가
    • vm_get_victim에서 접근되었는지 여부를 판단하기 위해, frame에 할당된 thread의 pml4가 필요함
  • ((vm.c)) vm_get_victim 구현
    • clock 알고리즘을 활용해 swap out할 frame을 하나 선택함
  • ((anon.c)) vm_anon_init 업데이트
    • 디스크에서 swap을 위한 영역 받아오기
      • swap_disk = dist_get(1, 1);
    • 스왑 영역에 가용한 페이지 수 계산하기
    • swap table 초기화 하기
      • 특정 slot이 사용중인지 여부를 체크하는데, bitmap table이 유리 - anon.c에서만 접근할 것이므로 static 으로 설정
  • ((anon.h)) anon_page에 swap_idx 멤버 추가
    • swap out 되었을 때 swap table 상에서의 위치를 저장할 멤버 추가
  • ((anon.c))
    • 적다가 일단 개발에 집중..

어느 순간에는 해야하는 것들

  • ((syscall.c)) check_address() 수정
    • syscall에서 요청된 주소값의 유효성을 체크
      • NULL이 아니어야 함: uaddr == NULL
      • user 영역이어야 함: !is_user_vaddr(uaddr)
      • 할당된 영역이어야 함: pml4_get_page(curr->pml4, uaddr) == NULL
    • lazy_load 방식으로 변경되었기 때문에 세 번째 조건 체크 방식을 수정
      • vm_try_handle_fault 부분 참고
        • spt_find_page 사용
      • 그냥 page_fault를 띄워버릴 순 없을까??
        • exception 상황에서 다시 exception을 때릴 순 없을 것
        • 대신 kernel mode에서 접근하려 할 때 page fault가 날 것

마지막 질문들

  • 왜 mmap할 때 file에서 offset이 PGSIZE 단위가 되어야 하지?
    • testcase 중 mmap-bad-off 에서 offset이 0x1234
    • 처음 예상으로는, 파일 크기보다 큰 offset 일 때를 말하는 줄 알았음
      • 읽어온 값이 0일 때 처리되는 상황
      • 즉, lazy_load가 발생한 이후에 처리되는 줄 알았음
    • 그런데 testcase는 요청 시점에 바로 판단을 해버리더라
      • 즉, 인자값만 보고 바로 판단하더라
      • 그래서 고려한 가능성은 offset도 PGSIZE여야 했다는 것
      • 그런데 왜??
profile
개발자 서자헌

0개의 댓글