๐Ÿ‘จโ€๐Ÿ’ป Seungineer's GitHub Contribution

๐Ÿงญ KAIST JUNGLE/Pintos

[PintOS] Virtual Memory - Mid Check (Project 3, WIL)

seungineer = seungwoo + engineer 2024. 5. 21. 06:06

2024.05.19 - [๐Ÿงญ KAIST JUNGLE/โญ Pintos] - [PintOS] Virtual Memory - ๋“ค์–ด๊ฐ€๊ธฐ(Project 3, TIL)

 

[PintOS] Virtual Memory - ๋“ค์–ด๊ฐ€๊ธฐ(Project 3, TIL)

Virtual Memory๋Š” ์™œ ํ•„์š”ํ• ๊นŒ?๊ฐ€์ƒ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ๋ฅผ ์ƒ์ƒํ•ด ๋ณด์ž. ์Œ์•… ์žฌ์ƒ ํ”Œ๋ ˆ์ด์–ด์™€ ๊ฒŒ์ž„ ํ”„๋กœ์„ธ์Šค์—์„œ ๊ฐ™์€ ๋ฌผ๋ฆฌ์  ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ์— ๊ฐ๊ฐ ์žฌ์ƒ ์‹œ๊ฐ„๊ณผ ์บ๋ฆญํ„ฐ์˜ ์ฒด๋ ฅ ์ •๋ณด๊ฐ€ ๋‹ด๊ธฐ๋ฉด ์–ด๋–ป๊ฒŒ

seungineer.tistory.com


์ง„ํ–‰ ์ƒํ™ฉ

โœ… Memory Management

โœ… Anonymous Page

โœ… Stack Growth

โŽ Memory Mapped Files

โŽ Swap In/Out

 

Project3์˜ Virtual Memory๋ฅผ ๋ชจ๋‘ ๊ตฌํ˜„ํ•œ ํ›„์˜ ๋™์ž‘ mechanism

Reference to ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น(์ขŒ), Pintos์—์„œ reference๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ณผ์ •(์šฐ)

Project2๊นŒ์ง€ ๊ตฌํ˜„๋œ ํ˜„์žฌ Pintos์˜ ๋ชจ์Šต์€ ์–ด๋–จ๊นŒ?

๊ตฌํ˜„ ์ „, ํ›„ ์ด๋ฏธ์ง€๋ฅผ ๋น„๊ตํ•ด ๋ดค์„ ๋•Œ ๊ตฌํ˜„ํ•ด์•ผ ํ•  ๊ฒƒ์ด ์ง์ ‘์ ์œผ๋กœ ๋ณด์ธ๋‹ค. Page table์˜ ํ™•์žฅ๊ณผ hash, bucket์˜ ์ถ”๊ฐ€์ด๋‹ค.

Implement Supplemental Page Table

๊ตฌํ˜„

ํ˜„์žฌ Pintos์—์„œ VA๋ฅผ PA๋กœ ๋งคํ•‘ํ•˜๋Š” ๊ฒƒ์„ ๊ด€๋ฆฌํ•˜๋Š” pml4๋กœ๋Š” ๋ถ€์กฑํ•˜๋‹ค. Page fault๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์ฒ˜๋ฆฌํ•  page์— ๋Œ€ํ•œ ๋ณด์ถฉ์ ์ธ ์„ค๋ช…์ด ํ•„์š”ํ•˜๊ธฐ์— Supplemental Page Table(SPT)์„ ์ถ”๊ฐ€ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. Pintos Instruction์„ ์ฐธ๊ณ ํ•˜๋ฉด, SPT ์„ค๊ณ„ ํ›„ ์ด๋ฅผ ํ† ๋Œ€๋กœ ํ•จ์ˆ˜ ์„ธ ๊ฐœ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค.

void supplemental_page_table_init (struct supplemental_page_table *spt);
struct page *spt_find_page (struct supplemental_page_table *spt, void *va);
bool spt_insert_page (struct supplemental_page_table *spt, struct page *page);
  • supplemental_page_table_init : spt ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ํ•จ์ˆ˜๋กœ initd(), __do_fork() ํ•จ์ˆ˜์—์„œ ํ˜ธ์ถœ๋จ
  • *spt_find_page : ์ธ์ž์˜ spt์—์„œ va์— ๋Œ€์‘๋˜๋Š” 'page ๊ตฌ์กฐ์ฒด'๋ฅผ ์ฐพ์•„์„œ ๋ฐ˜ํ™˜ํ•จ
  • spt_insert_page : ์ธ์ž๋กœ์˜ spt์— page ๊ตฌ์กฐ์ฒด๋ฅผ ์‚ฝ์ž…ํ•จ
/* Initialize new supplemental page table */
void supplemental_page_table_init(struct supplemental_page_table *spt UNUSED) {
    hash_init(spt, page_hash, page_less, NULL);
}
struct page 
*spt_find_page(struct supplemental_page_table *spt UNUSED, void *va UNUSED) {
    struct page *page = NULL;
    page = malloc(sizeof(struct page));
    struct hash_elem *hash_element;
    page->va = pg_round_down(va);  // ํŽ˜์ด์ง€๋ฅผ ์ฐพ์„๋•Œ๋Š” rounddown  -> up์€ ํ• ๋‹นํฌ๊ธฐ ๋งž์ถœ๋•Œ
    hash_element = hash_find(spt, &page->hash_elem);
    free(page);  // ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ
    if (hash_element) {
        return hash_entry(hash_element, struct page, hash_elem);  // hash_entry๋กœ hash_elem์„ page๋กœ ๋ณ€ํ™˜
    }
    return NULL;
}
/* Insert PAGE into spt with validation. */
bool spt_insert_page(struct supplemental_page_table *spt UNUSED,
                     struct page *page UNUSED) {
    int succ = false;
    // REVIEW INSERT_PAGE
    if (hash_insert(&spt->hash_page, &page->hash_elem) == NULL) {  // ์ž˜ ์ถ”๊ฐ€๋˜์—ˆ์œผ๋ฉด NULL๋ฐ˜ํ™˜
        succ = true;
    }
    return succ;
}

ํ•จ์ˆ˜ ๋‚ด์˜ hash๊ฐ€ ๋œฌ๊ธˆ์—†์–ด ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ์œ„์˜ ๊ตฌํ˜„ ํ›„ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ์„ค๋ช… ์ด๋ฏธ์ง€๋ฅผ ์ž์„ธํžˆ ๋ณด๋ฉด hash๋ฅผ ํ†ตํ•ด์„œ vm_entry๊นŒ์ง€ ๊ด€๋ฆฌ๋˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ๋”๋ถˆ์–ด Pintos์—์„œ๋Š” chaining hash table์„ ์ œ๊ณตํ•œ๋‹ค(lib/kernel/hash.* ์ฐธ๊ณ ). ์—ฌ๋‹ด์œผ๋กœ ๋ฆฌ๋ˆ…์Šค์—์„œ๋Š” Red-Black tree ๊ตฌ์กฐ๋กœ vm_entry๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค.

Frame Management

์ด์ œ Physical Memory์—๋„ Frame์ด๋ผ๋Š” ๋‹จ์œ„๋กœ ๊ตฌ๋ถ„๋˜์–ด ๊ด€๋ฆฌ๋œ๋‹ค. frame ์ ์šฉ์„ ์œ„ํ•ด struct frame์— kva(Kernel Virtual Address), page ๊ตฌ์กฐ์ฒด๋ฅผ ๋‹ด์„ ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ•œ๋‹ค. Instruction์—๋Š” ์—†์ง€๋งŒ frame๋„ page์™€ ๋งˆ์ฐฌ๊ฐ€์ง€ ๊ตฌ์กฐ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด frame_elem๋„ ์ถ”๊ฐ€ํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

/* The representation of "frame" */
struct frame {
    void *kva;
    struct page *page;
    struct list_elem *frame_elem;
};

frame ๊ด€๋ จํ•œ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š” ํ•จ์ˆ˜

static struct frame *vm_get_frame (void);
bool vm_do_claim_page (struct page *page);
bool vm_claim_page (void *va);

์œ„ ์„ธ ํ•จ์ˆ˜(์‚ฌ์‹ค ๋‘ ๊ฐœ์— ๊ฐ€๊น๋‹ค ใ…Ž)๋ฅผ ๊ตฌํ˜„ํ•  ๋•Œ ์šฐ๋ฆฌ ์กฐ๋Š” vm_do_claim_page()์—์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.

static bool
vm_do_claim_page(struct page *page) {  // va ํŽ˜์ด์ง€๋ฅผ๋งŒ๋“ค๊ณ  ํ”„๋ ˆ์ž„์— ํ• ๋‹นํ•œ ํŽ˜์ด์ง€
    struct frame *frame = vm_get_frame();

    /* Set links */
    frame->page = page;
    page->frame = frame;

    struct thread *current = thread_current();
    // bool writable = is_writable(current->pml4); <- ๊ธฐ์กด
    // pml4_set_page(current->pml4, page->va, frame->kva, writable); <- ๊ธฐ์กด, ์•„๋ž˜๊ฐ€ ์ˆ˜์ •
    pml4_set_page(current->pml4, page->va, frame->kva, page->writable);

    return swap_in(page, frame->kva);
}

์ฃผ์„ ์ฒ˜๋ฆฌ๋œ ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด, is_writable() ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ˜„์žฌ thread์˜ pml4๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” PA์˜ writable ์œ ๋ฌด๋ฅผ ํ™•์ธํ•ด ์ค€๋‹ค. ์–ผํ• ๋ณด๋ฉด ํ•ฉ๋‹นํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ์ด๋Š” ๋ง๋„ ์•ˆ ๋˜๋Š” ๊ฒƒ์ด๋‹ค(ใ…œใ…œ). ํ•จ์ˆ˜๋ช…๋Œ€๋กœ '์š”์ฒญํ•œ ํŽ˜์ด์ง€'์˜ write ์—ฌ๋ถ€๋ฅผ ๋ด์•ผ ํ•˜๋Š”๋ฐ ํ˜„์žฌ thread ์ •๋ณด๋ฅผ ๋ณด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ง€๊ธˆ ์ƒ๊ฐํ•ด ๋ณด๋ฉด ๋งค์šฐ ์‰ฌ์šด ์˜ค๋‹ต์ธ๋ฐ, ์—๋Ÿฌ๋ฅผ ์œ ๋ฐœํ•œ ์ฝ”๋“œ์—์„œ ๋งค์šฐ ๋ฉ€๋ฆฌ ๋–จ์–ด์ง„ ๋ฐ์„œ KERNEL PANIC์ด ๋ฐœ์ƒํ–ˆ๊ธฐ์— ๋””๋ฒ„๊น…์— ์–ด๋ ค์›€์ด ์ปธ๋‹ค.

์ˆ˜์ •ํ•œ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ํ• ๋‹นํ•˜๊ณ ์ž ํ•˜๋Š” page์˜ writable field๋กœ write ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•œ๋‹ค. ํ•จ์ˆ˜๋ช…๊ณผ๋„ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

์ˆ˜์ • ์ „, ํ›„ writable ์—ฌ๋ถ€(1 or 0) ๋น„๊ต

์ ˆ๋Œ€ ์˜์‹ฌํ•ด, race condition ๐Ÿ˜ˆ

make check ํ›„ ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ๋•Œ๋งˆ๋‹ค PASS/FAIL์ด ์˜ค๋ฝ๊ฐ€๋ฝํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ์žˆ์—ˆ๋‹ค(์šฐ๋ฆฌ ํŒ€์˜ ๊ฒฝ์šฐ syn-read....). ์˜ค๋ฝ๊ฐ€๋ฝํ•  ๋•Œ ๊ฐ€์žฅ ์‰ฝ๊ฒŒ ์˜์‹ฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒŒ race condition์ด๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ์™€ ๊ฐ™์ด file_write(file ,..., size) ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋  ๋•Œ, ๋‘ ๊ฐœ์˜ thread์—์„œ ๋™์‹œ์— ๊ฐ™์€ ํŒŒ์ผ์— write๋ฅผ ์‹œ๋„ํ•  ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•ด filesys_lock์„ ์‚ฌ์šฉํ•œ๋‹ค.

์ด๋ ‡๊ฒŒ lock์„ ๊ฑด๋‹ค๊ณ  ํ•œ๋“ค lock์„ ๊ฑธ๊ธฐ ์ „ ๋‹ค๋ฅธ ์ฝ”๋“œ์—์„œ write ๋ถ€๋ถ„์„ ์ž˜๋ชป ์ˆ˜์ •ํ•œ๋‹ค๋ฉด, ์ด๋ ‡๊ฒŒ lock์„ ๊ฑธ์–ด์ค˜๋„ ์˜๋ฏธ๊ฐ€ ์—†๋‹ค(!..). ๊ทธ๋ž˜์„œ race condition ์žก๊ธฐ๊ฐ€ ์—„์ฒญ ์–ด๋ ค์› ๋‹ค.

int write(int fd, const void *buffer, unsigned size)
{
	check_address(buffer);
	int bytes_write = 0;
	if (fd == STDOUT_FILENO)
	{
		putbuf(buffer, size);
		bytes_write = size;
	}
	else
	{
		if (fd < 2)
			return -1;
		struct file *file = process_get_file(fd);
		if (file == NULL)
			return -1;
		lock_acquire(&filesys_lock); // race condition ๋ฐฉ์ง€
		bytes_write = file_write(file, buffer, size);
		lock_release(&filesys_lock); // race condition ๋ฐฉ์ง€
	}
	return bytes_write;
}

์ด ์™ธ์—๋„ ๋ฌด์ˆ˜ํžˆ ๋งŽ์€ race condition ๋ฐœ์ƒ ๊ฐ€๋Šฅ ์œ„์น˜์— lock_acquire(), lock_release()๋ฅผ ํ•ด์ฃผ์—ˆ๋‹ค.

Pintos demand paging ์ผ๋ถ€ ๊ตฌํ˜„ ๊ณผ์ •

Pintos ์ƒ์˜ ํ•จ์ˆ˜ ํ๋ฆ„์€ ์•„๋ž˜์˜ Proj3 ์ค‘๊ฐ„๋ฐœํ‘œ(WIL) ์ž๋ฃŒ๋ฅผ ํ†ตํ•ด ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.