Jungle

[TIL] pintos : VM 시행착오 error 모음집

손가든 2023. 12. 20. 23:17

이번주부터 메모리 가상화를 구현하여 paging swap을 직접 수행하고 처리하는 작업을 시작했다.

 

코드를 진행하면서 이론을 3일정도 공부했다.

 

확실히 VM은 가상화가 너무 많아 이론을 머리속에 정리하기 어려웠다.

 

 

지금은 어떻게 해야할지 갈피를 잡았고 프로그램이 실행되는 프로세스에서 어떤 작업들을 해주어야 하는지 차근차근 생각하며

 

코드를 구현하고 있다.

 

 

이번 포스팅에서는 잘못 알고 있었던 것들과 사소한 잘못된 습관들 때문에 발생한 에러들을 하나씩 적으며 코딩하겠다.

 


 

 

1. 가상화했다고 struct 구조체까지 가상화해버림

 

메모리를 가상화해서 컴퓨터를 속여야 되는데 내 자신마저 속여서 코드까지 속였다.

 

 

메모리를 가상화한다는 것은

 

DRAM에 올라와있지 않은 메모리를 마치 올려놓은 것 처럼 속여놓고

 

실제로 그 DRAM을 읽으려고 page-table을 찾아봤을 때 없으면 그때 DRAM에 올리는 방식으로

 

수많은 페이지들이 DRAM에 올라와있다고 착각하게 만드는 것을 말한다.

 

 

pintos는 메모리를 반으로 자른 유저 pool에서 유저 프로세스가 메모리를 사용하고 있다.

 

따라서 유저 프로세스는 실행될 때, 유저 pool에 본인이 실행해야되는 프로그램 전부가 올라가있다고 착각한다.

 

하지만 이제 load해줄 때 load해준게 아니라 page struct를 생성해서 spt 이라는 테이블에 저장한 뒤

 

load한 척만 해야 한다.

 

 

근데 문제는 page struct 구조체는 가상의 페이지에 대한 메타 데이터 (이후 필요할 때 로딩하게 될 상태 등)가 들어있는데

 

이 구조체 멤버에 대한 정보를 담을 메모리도 할당 안해버린 것.

 

아래 함수는 잘못된 코드이다.

 

이 함수는 load해줄 때, 실제 데이터를 할당하지 않고 page struct만 load한척 spt에 넣는 함수이다.

 

if문 안에를 보면 new_page로 page를 생성한다.

 

근데 이 page에 대한 정보를 담을 메모리는 할당해주지 않았다..

 

따라서 다음과 같이 struct page에 멤버 데이터를 저장하기 위해 다음과 같이 malloc을 사용해야 한다.

 

 

이때 pintos 내에서 사용하지 않고 있는 malloc을 사용해서 다른 page의 메모리와 곂치지 않게 했다.

 

 


 

2. uninit 유형의 페이지 생성하며 writable 정보 사라짐

 

실시간으로 포스팅 중에 바로 위의 코드 사진에서 문제가 발생했다.

 

 

문제 상황은 프로그램을 실행시키기 위해 exec() 함수를 수행하며

 

spt 테이블 안에 새로운 페이지를 생성해주기 위해 uninit_new로 페이지를 초기화해주면서 발생했다.

 

 

이 함수는 load_segment() 함수에서 호출하는데,

 

어떤 페이지를 생성하고, 페이지 폴트가 발생했을 시 어떤 대처를 해줘야 하는지에 대한 정보를 전달해주어 uninit page에 담아둔다.

 

 

이때 전달하는 정보 중 writable이 있다.

 

이 파일이 읽을 수 있는지 없는지에 대한 정보이다.

 

이 값은 매우 중요한데, pml4 테이블에 그 정보를 비트로 표시해두고 만약 writable이 false인 파일을 누군가 접근하여 write를 하려고하면 deny 시켜야 하기 때문이다.

 

 

그래서 아래 사진에 표시된 대로 writable을 페이지 구조체의 멤버로 새로 추가한 뒤 값을 기록해두었다.

 

근데 밑에 uninit_new 함수를 보면

 

 

uninit에 원하는 값의 페이지로 복제하는 이 함수가 원래 넣어뒀던 writable 값을 삭제해버린 것이다.

 

이 사실을 매우 뒤늦게 깨닫는 바람에 하루종일 골머리를 써야했다.

 

하지만 디버깅과 팀원의 페어 프로그래밍을 통해 한코드 한코드 분석해보며 원인을 파악할 수 있었고,

 

덕분에 writable 값을 이 new함수를 수행한 뒤 저장해 주는 것으로 바꾸어 pass할 수 있었다!