파일은 크기가 균일하지 않음
그래서 파일을 동일한 크기 단위인 sector로 나누어 저장
디스크에 파일을 저장하는 방법은 아래의 3가지가 있음.
(메모리 관리 기법 중 페이징 기법과 유사함)
하나의 파일이 디스크 상에 연속해서 저장되는 방식으로,
나누어진 각 블록들이 연속된 번호를 부여 받아 저장된다.

sector들이 각각 node가 되어 Linked List 구조를 취하면서 파일을 저장한다.

파일이 어디에 나눠져 있는지 인덱스를 적어 두는 블록 하나 =
인덱스 블록을 활용

실제로 시스템은 어떻게 구현되는가..!

부팅에 필요한 정보를 담고 있는 블록
모든 파일 시스템에 존재하는 블록
파일 시스템에 관한 총체적인 정보를 담고 있는 블록
어느 부분이 비어 있는 블록인지, 어느 부분이 사용 중인 블록인지, 어디부터가 Inode 블록인지 Data 블록인지 등을 알려 주는 정보를 가짐
파일 이름을 제외한 파일의 모든 메타 데이터를 따로 저장
파일 하나 당 Inode가 하나씩 할당됨
해당 Inode는 그 파일의 메타 데이터를 갖고 있음.
이때 파일의 이름은 디렉토리가 가지고 있는데, 디렉토리는 파일의 이름과 Inode 번호를 저장하고 있다.
direct blocks는 파일이 존재하는 인덱스를 저장하는 인덱스 블록
파일의 크기가 크지 않다면 이 블록을 이용하여 파일을 접근할 수 있다.
direct blocks으로 커버할 수 있는 크기보다 저장 용량이 큰 파일은 single indirect를 통해서 하나의 level을 두어서 저장하는 방식을 취하고, 그보다 더 큰 파일은 double indirect, 더 큰 파일은 triple indirect 방식을 취한다.
파일의 실제 내용을 보관하는 블록
이 중 디렉토리 파일은 자신의 디렉토리에 속한 파일들의 이름과 Inode 번호를 가지고 있음.

sector가 할당되고 나서 발생하는 hole을 어떻게 관리할 것인가?
모든 free 블록을 링크로 연결 (free list)
Linked list의 변형
첫 번째 free 블록이 n 개의 포인터를 갖음
하나의 free 블록에 나머지 free 블록에 대한 위치 정보를 저장하는 방식
프로그램들이 종종 여러 개의 연속적인 블록을 할당하고 반납한다는 성질에 착안
0이면 비어 있는 값이고, 1이면 sector 저장된 공간이다.
<file name, file의 메타 데이터>의 리스트
- 구현이 간단
- 디렉토리 내에 파일이 있는지 찾기 위해서는 선형 탐색이 필요하다. (O(N))
선형 리스트 + 해싱
해시 테이블은 file name을 이 파일의 선형 리스트의 위치로 바꾸어 준다.
Inode, FAT 서로 다른 다양한 파일 시스템에 대해 동일한 시스템 콜 인터페이스(API)를 통해 접근할 수 있게 해 주는 OS의 레이어
분산 시스템에서는 네트워크를 통해 파일이 공유될 수 있다.
NFS는 분산 환경에서 대표적인 파일 공유 방법
‼️ 어떤 파일 시스템을 쓰든 상관 없이 VFS 인터페이스를 사용한다.
분산 시스템에서는 네트워크를 통해 파일을 공유하기 위해 NFS 클라이언트와 NFS 서버가 이용됨
운영체제가 file입출력을 할 때 사용자 프로그램의 요청을 받아서 disk에서 읽어온 내용을 그냥 전달하는 게 아니라 자신의 buffer cache 영역에 읽어놓고, 그 내용을 copy로 넘겨주기 때문에 다음번에 동일한 file data에 대한 read, write system call이 오면, disk까지 가지않고 buffer cache에서 처리한다.
예전에는 sector단위는 512byte였다. 최근에는 buffer cache가 page cache와 통합이 되면서 buffer cache에서 사용하는 단위도 4KB를 사용한다(unified buffer cache).
가상 메모리의 페이징 시스템에서 사용하는 페이지 프레임을 캐싱의 관점에서 설명하는 용어
Memory-Mapped I/O를 쓰는 경우 파일의 I/O에서도 페이지 캐시를 사용한다.
파일의 일부를 가상 메모리에 매핑한다.
매핑한 영역에 대한 메모리 접근 연산은 파일의 입출력을 수행하게 한다.
파일 시스템을 통한 I/O 연산은 메모리의 특정 영역인 버퍼 캐시를 사용한다.
파일 사용의 지역성 활용
한 번 읽어 온 블록에 대한 후속 요청 시, 버퍼 캐시에서 즉시 전달
모든 프로세스가 공용으로 사용
교체 알고리즘 필요 (LRU, LFU 등)
최근의 OS에서는 기존의 버퍼 캐시가 페이지 캐시에 통합됨.

read, write system call을 쓸 때는 그 내용이 buffer cache에 있든 없든 항상 운영체제에게 요청해서 받아와야 함.
mmap을 쓰게 되면 page cache에 올라온 내용은 운영체제의 도움을 받지 않고 사용자 프로세스가 직접 메모리접근을 통해 I/O를 한다(인터페이스의 차이)
mmap을 사용하는 이유
mmap을 사용하면 이미 메모리에 올라온 내용에 대해서는 kernel의 도움을 받지 않고 (운영체제를 호출하지 않고) 자신이 직접 자신의 메모리에 접근하듯이

unified buffer cache를 사용하면 기존처럼 buffer cache를 따로 두지 않고, 필요에 따라 page cache에서 공간을 할당해서 쓰는 방식을 사용
read, write system call을 하는 경우 해당 내용이 buffer cache에 올라와 있든 아니든 상관없이 운영체제에게 CPU 제어권이 넘어감
CPU는 이미 올라와 있는 data는 사용자 프로그램에 copy해주고 메모리에 없다면 disk에서 읽어와서 사용자프로그램에 copy해서 전달한다.
mmap인 경우, 자신의 주소영역중에 일부를 file에 mapping하는 단계를 거치고 나면 사용자 프로그램의 주소영역에 page cache가 mapping된다.
이전처럼 buffer cache의 내용을 copy하는 것이 아니라 그냥 page cache 자체가 사용자 프로세스의 논리적 주소영역에 mapping되어 사용됨(page cache에 직접 읽고 쓴다)