26. File System Implementations 2
Page Cache
당장 필요하지 않은 페이지 프레임에 당장 필요한 내용을 메모리에 올려두고, 필요하지 않은 건 쫓아내는 것
페이징 시스템에서 사용하는 페이지 프레임들을 Page Cache라고 부른다.
Buffer Cache
버퍼 캐시는 운영체제가 디스크에서 읽어온 내용을 자신의 버퍼 캐시 영역에 저장해두고
사용자의 프로그램에 카피해서 넘겨주기 때문에 다음 번에 동일 데이터에 read write 시스템 콜이 오면 버퍼 캐시 영역에 있는
데이터를 가져다 주는 것이다.
페이지 캐시는 swap area에 있는가 page cache에 올라와 있는가
버퍼 캐시는 파일 시스템 스토리지에 저장되어 있는가, 버퍼 캐시에 올라와 있는가
단위
페이지 캐시의 단위는 4kb라는 페이지 단위이다.
버퍼 캐시는 어떤 파일의 블록을 읽어오는 것이기에, 섹터 단위 512 바이트이기 때문에 4kb보다 다소 작은 단위.
최근에는 리눅스의 경우 통합이 되면서 버퍼 캐시에서 사용하는 단위도, 작은 크기의 블록이 아닌 똑같은 페이지 단위의 크기를 쓰게 됐다.
리눅스의 경우, 별도의 공간 구분을 하지 않고 똑같이 페이지 단위로 사용하면서 필요 시에 페이지 캐시를 할당해서 버퍼 캐시로 사용하는 방식이다. 필요할 때 그때 그때 할당해서 사용하는 방식으로 쓴다.
이게 바로 이전 구분짓던 때와 다른 점이다.
memory-mapped I/O
프로세스의 주소 공간 중의 일부를 파일에 일부 매핑해두고,
매핑된 이후에는 메모리 접근하는 연산을 이용해서 파일 입출력을 하는 방식이다.
<Unified Buffer Cache를 이용하지 않는 File I/O>
1. 파일을 open하고 read write 시스템 콜을 하는 방식 (by OS) :
운영체제가 해당 하는 파일의 내용이 버퍼 캐시에 있으면 바로 전달하고,
없으면 디스크 파일 시스템에서 불러와서 사용자 파일 시스템에 전달해준다. 사용자 프로그램은 자신의 페이지에 카피해서 사용하게 된다.
2. memory-mapped I/O 방식 :
'나는 memory-mapped I/O를 쓰겠다'는 시스템 콜을 운영체제에게 보내고, 디스크에 있는 파일을 읽어오고, 읽어온 내용을 페이지 캐시에 카피를 한다. 그러면 그 내용이 파일에 매핑된 내용이 된다. 그러면 그 후부터는 사용자 프로그램이 자신의 페이지 캐시의 메모리 영역에서 read write하는 방식이다. (그 후부터는 운영체제의 간섭없이 접근이 가능한 것임.)
둘의 차이는
첫 번째 방식은 버퍼 캐시에 있든 없든, 항상 운영체제에게 요청을 해서 받아와야 하는 것이고
두 번째 방식은 페이지 캐시에 올라온 내용은 운영체제의 도움을 받지 않고, 자신의 주소공간에 매핑되어 있는 것이니까 메모리 접근 방식처럼 read write하면 된다. 이미 메모리에 올라온 내용에 대해서는 운영체제 커널의 도움을 받지 않아도 된다.
근데 어쨌든, 둘의 공통점은 파일 입출력을 위해서는 버퍼 캐시를 통과해야 한다. 운영체제가 할당해둔 공간이기 때문에.
버퍼 캐시에 있는 내용을 자신의 페이지 캐시에 복제해야 하는 오버헤드가 있다.
<Unified Buffer Cache를 이용한 File I/O>
" 리눅스의 경우, 별도의 공간 구분을 하지 않고 똑같이 페이지 단위로 사용하면서 필요 시에 페이지 캐시를 할당해서 버퍼 캐시로 사용하는 방식이다. 필요할 때 그때 그때 할당해서 사용하는 방식으로 쓴다. "
-> 경로가 더 단순해짐
1. read write 시스템 콜의 경우 :
디스크 파일 시스템이나 버퍼 캐시한테 올라와 있든 상관없이 무조건 운영체제한테 CPU 제어권이 넘어가서 시스템 콜을 해야 한다.
운영체제는 이미 메모리에 올라와 있는 내용은 사용자 프로그램의 주소 영역에 카피를 해주고,
메모리에 올라와 있지 않은 내용은 디스크 파일 시스템에서 읽어와서 사용자 프로그램에게 카피해준다.
2. memory-mapped I/O 방식 :
파일에게 매핑하는 단계를 거친 후부터는 사용자 프로그램의 주소영역에 페이지 캐시가 매핑이 된다.
기존처럼 버퍼 캐시의 내용을 한 번 카피해서 올라가는 게 아니라 페이지 캐시 자체가 사용자 프로그램의 논리적 주소영역에 매핑이 되어서 별도로 존재하는 것이 아닌 페이지 캐시 자체에 버퍼 캐시를 쉐어해서 사용하는 방식이 된다.
Unified가 아닌 것과의 차이는
첫 번째 방식에서 버퍼 캐시를 거치는 것이 아니라 바로 운영체제에게 시스템콜을 하는 것이다. (맞냐..?)
두 번째 방식에서 메모리 주소와 파일 매핑 이후에는 버퍼 캐시 == 페이지 캐시 바이브가 된다는 것이다.
각 실행 파일 A, B는 파일시스템에 저장되어있다가 실행 시에 프로세스가 되고,
프로세스만의 독자적인 주소공간인 가상 메모리(code-data-stack)가 생성된다.
주소 변환을 해주는 하드웨어에 의해서, 당장 필요한 부분은 물리적 메모리(Physical memory)에 올라가게 되고,
물리적 메모리의 공간이 한정되어서 쫓겨난 부분은 디스크의 swap area로 넘어가게 된다.
code 부분은 메모리에 올라간 후, 쫓겨날 때 swap area로 넘어가지 않는다.
왜냐하면 read-only이기 때문이다. 실행될 때, 애시당초 파일 시스템의 실행 파일 형태로 존재하기 때문이다.
프로세스의 주소 공간에 파일 시스템의 실행 파일과 그대로 매핑된다. 즉, code 부분이 memory-mapped I/O의 대표적인 예시다.
code 부분은 swap area를 따로 가지고 있지 않음, 주소 공간에 그대로 매핑되어 있고, 메모리에 안올라와 있으면 실행파일에서 가져와야 한다. (나 사실 여기 잘 이해안감..;)
실행 파일과 데이터 파일도 파일 시스템에 저장되어 있다.
파일의 내용을 읽어오라는 read 시스템 콜이 있을 수 있거나, memory-mapped I/O 형태로도 쓸 수 있다.
memory-mapped I/O 형태로 쓰고 싶을 경우에는, 해당 프로그램이 운영체제에게 그 데이터 파일의 일부를 자신의 주소 공간의 일부에다 매핑해달라고 시스템 콜을 하는 것이다.
그래서 그 프로그램이 실행되면서 메모리 위치로 접근 시에 그 내용이 메모리에 안올라와 있으면 페이지 폴트가 일어나고, CPU가 운영체제에게 넘어가서 페이지 폴트난 페이지를 물리적 메모리에 올려놓을 것이다. 그 가상 메모리의 주소공간의 페이지가 물리적 메모리의 해당 페이지로 매핑이 된다. 그래서 그 프로세스B가 추후 해당 데이터 파일에 접근하려면 운영체제의 도움을 받지 않고 자신의 주소공간의 일부이기 때문에 읽고 쓸 수 있는 것이다. 근데 메모리에서 쫓겨날 때는 memory-mapped 파일이기 때문에 파일에다가 수정하고 쫓겨내야 한다.
마지막으로 정리하자면, 파일에 접근하는 방법은 2개가 있고, Unified Buffer Cache를 기준으로 정리하면,
1. read write 시스템 콜은 카피해서 전달
- 복제본을 가지고 있는 것이고 운영체제가 중재를 하기 때문에 기에 일관성 문제는 발생하지 않는다.
2. memory mapped I/O는 파일을 매핑해서 사용하는 것
- 가상메모리의 주소공간의 논리적 페이지가 물리적 메모리의 페이지 프레임에 올라와 있는 것이다.
- 시스템 콜을 쓰지 않고, 직접 접근하는 거라 빠른 장점이며, 자신의 주소공간으로 카피하는 것이 아니라 그대로 매핑하는 것이다.
- 주의할 점은 페이지 캐시를 매핑하는 것이기 때문에 쉐어해서 쓸 경우에 일관성 문제 바꾼 내용이 반영되는가가 주의해야 할 점이다.
https://core.ewha.ac.kr/publicview/C0101020140523142954456205?vmode=f
'⭐️ Computer Science > 운영체제' 카테고리의 다른 글
[운영체제] 2. 메모리계층, 가상메모리, 스와핑, 페이지폴트, 스레싱 (0) | 2022.08.21 |
---|---|
[운영체제] 1. 운영체제와 컴퓨터, 인터럽트, 시스템콜과 modebit (0) | 2022.08.21 |
[운영체제] 28. Disk Management & Scheduling 2 (0) | 2022.08.14 |
[운영체제] 27. Disk Management & Scheduling 1 (0) | 2022.08.14 |
[운영체제] 25. File System Implementations 1 (0) | 2022.08.07 |