PintOS| 가상메모리 VM_FILE이 없다고?

맹쥐·2025년 6월 5일

kaist - PintOS

목록 보기
10/10
post-thumbnail

VM_FILE인 줄 알았는데, 갑자기 VM_ANON이라고?

process_exec() 부터 코드를 차근차근 따라가다 보면..
뭔가 이상한 걸 발견했을 것이다.

static bool
load_segment (struct file *file, off_t ofs, uint8_t *upage,
		uint32_t read_bytes, uint32_t zero_bytes, bool writable) {
	ASSERT ((read_bytes + zero_bytes) % PGSIZE == 0);
	ASSERT (pg_ofs (upage) == 0);
	ASSERT (ofs % PGSIZE == 0);
	// read_bytes : 마지막 페이지 읽어야할 크기 / zero_bytes: 페이지 - read_bytes
	// 페이지 단위로 나눠서 반복문 돌림.
	// page_read_bytes : 페이지 크기 만큼 읽는다. * 마지막 페이지일 때? -> read_bytes
	// page_zero_bytes : 0 * 마지막 페이지일 때? -> zero_bytes

	while (read_bytes > 0 || zero_bytes > 0) {
		/* Do calculate how to fill this page.
		 * We will read PAGE_READ_BYTES bytes from FILE
		 * and zero the final PAGE_ZERO_BYTES bytes. */
		size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE;
		size_t page_zero_bytes = PGSIZE - page_read_bytes;

		struct file_info *aux = malloc(sizeof(struct file_info));
		if (aux == NULL) return false;	
		aux->file = file;
		aux->page_read = page_read_bytes;
		aux->page_zero = page_zero_bytes;
		aux->offset = ofs;
		
        // ‼️ 이 곳 ‼️ //
		if (!vm_alloc_page_with_initializer (VM_ANON, upage,
					writable, lazy_load_segment, aux))
			return false;

		/* Advance. */
		read_bytes -= page_read_bytes;
		zero_bytes -= page_zero_bytes;
		upage += PGSIZE;
		ofs += page_read_bytes;
	}
   
	return true;
}

여기서 갑자기 VM_ANON 으로 타입을 설정해버린다.
당황스럽다.


PintOS 과제에서는 "VM_FILE 없는 셈 치기"

가상메모리 구조를 열심히 공부했을 것이다.
VM_ANON/ VM_FILE에 대해서 실컷 공부했는데 ..
놀랍게도, 우리의 편의를 위해 우선 VM_FILE을 없는 셈 친다.

FILE은 extra에서 다룰 것이다.
VM_ANON이든, VM_FILE이든 모두 VM_ANON로 가정하고 구현해야할 것이다.
( 이걸 몰라서 한참을 헤맸다. 😢 )


그림 오른쪽 위에, uninit_page를 보면
vm_type 이라는 멤버가 있다.
이곳에, UNINIT page의 최종 목표인 VM_ANON/VM_FILE이 저장되어 있다.

하지만, 앞서 말했듯이 UNINIT은 모두 최종 목표가 VM_ANON으로 설정되어 있을 것이다.
(추후 과제를 수행하려면 수정해야함)


  • process_exec() 에서 프로세스가 실행이 되고,

  • load() 에서 프로세스에 해당하는 데이터를 모두 page 구조체로 만들어 둔다.
    이전 글에서 설명

  • 그다음 load_segment()

  • vm_alloc_page_with_initializer() 에서,
    VM_ANONlazy_load_segment를 인자로 넘겨준다.

  • 여기서 uninit_new()를 호출하여, UNINIT 페이지 구조체를 완성한다 !

    정리하면, UNINIT 페이지 구조체는

    • 최종 목표가 (type) = ANON
    • init = lazy_load_segment
    • initializer = anon_initialzer

후에, UNINIT 페이지에 접근했을 때 어떤 동작을 취할 지 예약하는 과정이다.


UNINIT 페이지에 접근한다면 ? = 이제 데이터를 로드해야될 차례

  • .swap_in함수가 실행된다.
  • 즉, uninit_initialize가 실행된다.
static bool
uninit_initialize (struct page *page, void *kva) {
	struct uninit_page *uninit = &page->uninit;

	/* Fetch first, page_initialize may overwrite the values */
	vm_initializer *init = uninit->init;
	void *aux = uninit->aux;

	/* TODO: You may need to fix this function. */
	/* 목표 initializer 실행 & 현재 init 함수 실행 ! */
	return uninit->page_initializer (page, uninit->type, kva) &&
		(init ? init (page, aux) : true);
}
  • 내부에서 page_initializerinit 함수가 실행된다.

이때, anon_initializerlazy_load_segment가 실행되는 것 !

  • anon_initializer
    여기서 init 타입을 ANON으로 바꾼다.
  • lazy_load_segment
    여기서 데이터를 로드한다.

최종적으로 VM_ANON 타입의,
frame과 연결된 = 데이터가 로드된
page가 완성이 됐다.

profile
이유민

4개의 댓글

comment-user-thumbnail
2025년 6월 7일

mmap에서 쓴다고 하네요 ^^;

1개의 답글