본문 바로가기

Information Technology/OS

[운영체제] File System Implementations

이 글은 개인의 학습을 목적으로 정리한 글입니다. 이점 참고하고 읽어주세요;)


테이프: 순차 접근만 가능. 건너뛰기 불가능

하드 디스크, 플래시 메모리: 건너뛰기 가능. 직접 접근 가능한 매체


1) Continguous Allocation

start: 시작 위치

length: 길이

mail의 start가 19이고 length가  6 => 19번 ~ 24번까지(6개)가 mail의 파일 데이터

디렉터리: 디렉터리 밑에 있는 존재하는 파일들의 메타 데이터 정보. 

 

- 단점:

   1) 파일들의 길이가 균일하지 않기 때문에 중간의 free block으로 인한 외부 조각 발생

   2) 파일 생성 이후에 연속 할당이 가능하지 않은 크기로의 확장 제약 -> 이를 위해 미리 메모리상에서 빈 공간을 확보하는 방법 -> 당장 사용하지 않는 공간으로 인한 공간 낭비(중간에 홀이 생김)

- 장점:

  1) 빠른 I/O 가능. 하드 디스크의 파일 I/O => 헤드의 이동. 어떤 파일을 전부 읽고 싶다면 한 번의 seek으로 시작 주소까지 찾아가면 더 이상 seek가 필요 없이 전부 읽어올 수 있음(물론 같은 트랙 상에 존재할 때) -> 때문에 파일 저장이 아닌, 프로세스의 주소 공간 일부를 물리적 메모리에서 쫓아내고 가져오는 Swap  area로 사용. 또는 데드라인이 있고 빠른 처리가 중요한 real time file용

 2) 파일이 시작 위치로부터 연속적으로 위치하기 때문에, 파일의 특정 위치만 궁금하다면 굳이 시작위치부터 볼 필요 없이 시작 위치 + 해당 위치로 접근해서 데이터 확인 가능(직접 접근 가능)


2. Linked Allocation

메모리상 임의의 빈 공간에 파일 데이터를 분산 저장.

디렉토리에는 파일의 시작 주소만 저장해놓고, 해당 주소에 가보면 다음 주소가 저장되어 있음

 

- 단점:

    1) 해당 주소에 가야만 다음 주소를 알 수 있기 때문에 파일에서 특정 위치(중간에 위치한)의 데이터가 궁금하다면 그 시작 주소부터 하나하나 순차적으로 확인해야 함. 즉, 데이터에 직접 접근 불가능. 건너뛰는 게 불가능. 다음 위치로 이동하는 데 발생하는 헤드의 seek가 많이 발생

   2) 하나의 섹터에서 고장이 발생해 pointer가 유실되면 다음 데이터들의 주소 역시 망가지기 때문에 파일의 많은 부분을 유실할 수 있음

   3) 크기가 512Byte인 하나의 섹터에서 다음 주소의 포인터를 위해 할당해주는 크기가 4Byte. 여기서 메모리 낭비가 발생할 수 있음.

- 장점: 메모리 공간에서 external fragmentation이 발생하지 않음. 즉, 각기 다른 크기의 파일로 인한 메모리 낭비가 없음

 

* File Allocation Table(FAT): 이러한 Linked allocation의 문제를 해결한 파일 시스템


3) Indexed Allocation

하나의 파일을 구성하는 블록들의 주소를 index block에 저장. 디렉토리에는 하나의 파일당 하나의 index block을 마치 주소록처럼 가지고 있어서, 특정 파일에 접근하고 싶다면 그 파일의 index block을 먼저 확인해야 함. 그리고 index block에서 필요한 블록의 위치를 확인해서 직접 접근 가능.

 

- 단점:

1) 아무리 작은 크기의 파일이라도 최소 두 개의 블록 필요(실제 메모리상의 블록과, 블록에서 index block). 

2) 굉장히 큰 파일의 경우 하나의 index block으로 모든 주소를 표시하기 어려움.

 * 해결방안 1) linked scheme: 하나의 index block으로 파일의 모든 주소를 표시할 수 없을 때, index block의 마지막 주소는 메모리상 파일의 데이터 주소가 아니라 또 다른 index block의 주소로 연결. 

 * 해결방안 2) multi level index: 하나의 index block의 주소들이 메모리상 파일의 데이터 주소를 나타내는 게 아니라, 또 다른 index block을 가리키게 함. 

-> 모두 index block을 위한 공간 낭비가 존재함.


- Boot block: 부팅에 필요한 정보. 어떤 파일시스템이든 boot block이 가장 먼저 위치함(0번 블록에 위치).

- Super block: 파일시스템에 대한 총체적인 정보. 어떤 부분이 비어있는 블록이고, 어디에 파일이 저장된(사용 중인) 블록인지.

- Inode list: 디렉토리가디렉터리가 파일의 모든 메타 데이터를 가지고 있는 건 아님. 실제 파일의 메타 데이터를 별도로 저장하고 관리하는 공간이 Inode(Index node) list. 파일 하나당 inode가 하나씩 할당. inode에 메타 데이터를 저장하고 있는 구조. 하지만 파일의 이름은 inode가 아닌 디렉터리가 관리함. 디렉터리에서 파일의 이름과 inode를 저장하고 있어서, 파일의 이름을 찾은 다음 inode 주소를 확인하고 찾아가서 여러 메타 데이터를 이용.

UNIX 파일 시스템 -> 거의 indexed allocation. 가급적 작은 index block을 가지고 크기가 큰 파일을 표시해야하기 때문에, direct blocks, single indirect, double indirect, triple indirect 이렇게 4개의 block을 사용해서 표시. 크기가 작은 파일은 direct block으로만 표현 가능. 크기가 큰 파일은 index block의 층을 나타내는 single, double, triple indirect를 사용해서 표현.


- boot block: 어떤 파일 시스템이든 0번 위치. 부팅에 관한 데이터(커널의 위치 등등)

- FAT: 파일의 메타 데이터 중 일부를 저장. 하지만 굉장히 일부(오직 위치정보만 관리). 나머지 메타 데이터는 파일의 디렉토리가 관리(접근 권한, 소유주, 첫 번째 위치 등등..)

* 기존 Linked allocation의 문제 -> 하나의 블록에서 유실이 생기면 다음 데이터로 이어지는 주소 역시 유실되기 때문에 그 블록 이후의 데이터들이 모두 유실될 위험. 이를 해결하기 위해 FAT라는 별도의 배열을 만들어서 파일의 주소들만 관리하는 것이 FAT 파일 시스템. 디스크의 헤드가 순차적으로 모든 데이터 블록들을 확인해야만 특정 위치를 파악할 수 있는 것이 아니라, FAT을 참조함으로써 다음 위치를 확인 가능(FAT은 이미 메모리에 올라와있기 때문에 테이블을 파악하는 건 많은 오버헤드 없이 곧바로 위치 파악 가능). 이를 통해 직접 접근이 가능함. 섹터 하나가 베드 섹터가 나더라도 포인터에 대한 유실 우려가 없음. FAT는 중요한 정보이기 때문에 디스크에 최소 두 개 이상의 복사본을 만들어 놓음.


비어있는 블록(free space)을 관리하는 방법

1. Bit map

각 블록별로 번호가 매핑. Unix의 경우 Super block에서 0과 1을 통해 파일들의 상태를 표시. 

-> 연속적인 n개의 free block을 찾는데 효과적.

 

2. Linked list

비어있는 블록들을 연결. 어차피 비어있기 때문에 포인터를 통해 비어있는 다음 위치를 저장하는 게 가능. bit map에 비해 추가적인 공간낭비가 없음. 하지만 연속적인 빈 공간을 찾기 어려움. 

 

3. Grouping

하나의 비어있는 블록이 index block 역할.

 

4. Counting

연속적인 빈 블록을 찾기 위해 빈 블록의 위치를 가리키고 몇 개의 블록이 비어있는지도 저장해서 관리.


디렉토리: 디렉터리 밑에 존재하는 파일들의 메타 데이터를 관리하는 파일

 

1) Linear list: 파일의 이름과 다른 메타 데이터를 순차적으로 저장. 메타 데이터의 크기는 고정. 파일의 이름은 ~byte, 주소는 ~byte 이런 식으로 정해져 있음. -> 순차적으로 파일의 이름을 찾아야 하기 때문에 비효율적

 

2) Hash Table: 파일의 이름을 해시함수를 적용해서 저장. 파일의 해시값 결과에 해당하는 엔트리에 메타 데이터를 저장. 특정 파일을 찾을 때, 순차적으로 파일들을 찾을 필요 없이 해시 엔트리만 확인하면 되기 때문에 효율적. 하지만 hash를 사용하기 때문에 collision 발생 가능.

 

파일의 메타데이터는 저장 공간이 유한함(엔트리가 고정되어 있음). 그런데 파일 이름의 경우 너무 길어져서 할당 길이를 넘어가면, 포인터를 둬서 디렉토리의 맨 마지막부터 거꾸로 파일의 이름이 저장되도록 설정.


VFS: 파일 시스템의 종류는 굉장히 다양함. 사용자가 파일 시스템에 접근할 땐 syscall을 해야하는데, 파일 시스템별로 syscall 형식이 다르면 불편하기 때문에 개별 파일 시스템 위 계층에 VFS라는 인터페이스를 통해 syscall 호출. 사용자 입장에서는 동일한 API를 사용해서 syscall을 가능하게 해주는 게 VFS.

 

NFS: 원격에 저장된 파일 시스템을 불러올 때 사용. 클라이언트서버가 네트워크로 연결되어 있을 때, 클라이언트가 자신의 로컬에 저장된 파일 시스템과 원격에 저장된 파일 시스템에도 접근이 가능하게 만들어줌. NFS를 통해 RPC(Remote PC)에 연결한 뒤 역시 VFS를 통해서 syscall 사용. 클라이언트와 서버 모두 NFS 모듈을 설치해야 함


Page Cache: 가상 메모리 측면. 메모리에 올라간 page에 대해서는 하드웨어적인 주소전환만 이뤄지기 때문에 운영체제가 가지고 있는 정보가 제한적. 때문에 clock 알고리즘을 사용.

 

Buffer Cache: 파일 시스템 측면. 파일 접근에는 무조건 syscall이 필요하기 때문에 운영체제가 모든 정보를 관리. 때문에 LRU, LFU 등등이 사용 가능. 

 

Memory-Mapped I/O: 기존의 파일 사용은 파일은 OPEN()한 다음 write syscall, read syscall 등등을 통해 사용. 하지만 memory-mapped는 파일의 일정 부분을 메모리 영역에 맵핑한 뒤 사용. 한 번 맵핑을 해놓으면 파일을 호출해서 저장하는 게 아니라 메모리 영역에 write/read 가능. 

 

사용자 영역: 페이지 단위로 관리

커널 영역에 버퍼 캐시 존재. 디스크에서 버퍼 캐시에 저장 뒤 사용자 영역에 전달. 

최근에는 이 버퍼 캐시와 페이지 캐시를 통합하는 추세.