15. File-System Internals
◆ 요점 정리
1. 파일 시스템 마운팅
파일 시스템이 파티션에 디렉토리 형태로 접근할 수 있도록 연결하는 작업
- 유닉스의 경우 루트 폴더에 자동으로 파일시스템이 마운트 됨
2. VFS
파일 시스템이 다르더라도 유저 프로세스가 항상 동일한 형태의 시스템 콜을 사용할 수 있도록 인터페이스를 제공하는 것
- Inode : 한 파일 시스템 내에서 파일을 식별하기 위함
- vnode : 여러 파일 시스템들 중에서 파일을 식별하기 위함
3. VFS 구현
- 관리해야 할 Object files
- inode object, file object, superblock object, dentry object 등
- 정의해야 할 Operations
- open, close, read, write, mmap 등
4. Remote File System
- NFS
◆ File-System Mounting
OS 는 디바이스 이름과 마운트 포인트(디렉토리) 를 전달받아 해당 디바이스를 주어진 포인트에 마운트함
파일 시스템 사용하려면 우선 mount되어야 한다.
마운트란 파일 시스템이 접근하는 경로를 만들어주는 것
즉, 파일 시스템이 파티션에 디렉토리 형태로 접근할 수 있도록 연결하는 작업을 의미함.
Root partition에 OS가 위치해있고, 서로 다른 파티션에는 다른 OS, 다른 파일 시스템 등이 존재할 수 있다.
자동으로 마운트될 수도 있고, 내가 원하는 마운트 포인트에 마운트 할 수도 있음.
마운트가 될 때, 파일 시스템 무결성(오류 없이 잘 돌아가고 있는지)이 체크된다.
메타데이터를 확인했을 때,
- 만약 메타데이터에 문제가 있으면 그걸 고치고 다시 마운트하려고 함
- 메타데이터가 올바르게 잘 되어있다면 마운트에 추가해서 접근할 수 있게끔 해줌
파일 시스템 마운트 예시를 보자.
(a) 유닉스 시스템 기준으로 마운팅 설명하고 있는 그림이다.
유닉스 같은 경우에는 루트 폴더에 자동으로 파일시스템이 마운트 됨
루트 파티션의 내용들이 자동으로 접근가능한 형태로 되는 것
users 라는 폴더는 루트 파티션 + users 구조이므로 root/users 라는 경로를 갖게 됨
fred의 접근 경로는 root/users/fred 가 된다.
(b) 만약 파일 시스템이 마운트되지 않았다면, 루트에서 폴더들에 접근할 수 있는 방법이 없음
따라서 항상 파일시스템은 마운트가 되어야 함
유닉스에서는 빈 폴더에다가 파일시스템을 마운트시킬 수 있다. (보통 빈 폴더에다 마운트 시킴)
만약 users 폴더 안에 (b)가 들어가면, 맨 오른쪽 그림처럼 될 것이다.
이때 실제 파일 내용이 바뀌는 게 아니라, 접근 경로만 달라지는 거임.
마운트 포인트는 언제든지 달라질 수 있음!!
◆ Virtual File System(VFS) on Unix
파일 시스템 타입이 달라도 유저 프로세스가 항상 동일한 형태의 시스템 콜을 사용할 수 있도록 인터페이스를 제공
Virtual File System은 파일 시스템을 구현하는 객체지향적 방법을 제공한다.
객체지향의 Polymorphism 개념을 활용한 것이다.
※ Polymorphism
: 상위 클래스가 있고 하위 클래스가 있을 때, 실제 구현은 하위 클래스를 구현하고 접근은 상위 클래스로 접근하는 것. 상위 클래스라는 공통의 인터페이스로써 접근할 수 있는 것임
볼륨륨별로 각기 다른 파일 시스템을 사용할 수 있음. NTFS, FAT32, …
그런데 파일 시스템마다 파일을 저장하는 방식이나 메타데이터를 저장하는 방식이 다름!!
따라서 얘네 전체를 VFS라는 인터페이스로 묶고, 그 아래에 각자의 방식으로 실제 파일 시스템을 구현해놓는다면?
→ 유저 프로세스의 입장에서는 항상 똑같은 인터페이스로 접근할 수 있게 됨!
쉽게 말하면 파일 시스템 타입이 달라도 유저 프로세스가 항상 똑같은 시스템 콜 인터페이스를 사용하게 해주는 것~
이 안에서 파일들을 구분할 수 있는 메커니즘이 존재함.
- Inode (Index node): 하나의 파일시스템 속에서 파일을 구분하는 데 사용.
- vnode (virtual node): 특정 파일 시스템에 종속되지 않고, VFS를 통해 여러 개의 파일 시스템 속에서 일관된 방식으로 파일을 구분할 수 있음.
◆ Virtual File System Implementation
VFS를 어떻게 구현할 수 있는지 알아보자.
1. 관리해야 할 Object Types
VFS구현을 위해, 4개의 object type들을 관리하게 된다.
- Inode object: 각각의 파일을 의미함.
- FCB랑 연결되는 개념
- File object: 오픈된 파일(프로세스가 사용중인 파일)의 데이터를 저장하기 위해 쓰는 것.
- 어디 읽고 쓰고 있는지에 대한 포인터 같은 걸 유지함.
- 프로세스는 슈퍼블록, 아이노드, 덴트리를 직접 다루는 것이 아니라, '파일'을 직접 다룬다.
- Superblock object: 전체 파일 시스템에 대한 메타데이터를 저장하는 것
- 슈퍼블록은 각 파일 시스템별로 구현하며, 본질적인 파일 시스템 메타데이터이다.
- Dentry object: Directory Entry의 약자로, 폴더 안에 있는 개별적인 엔트리를 의미함.
- Inode와 파일을 연결시켜주는 역할을 함.
- 캐시를 저장해서 자주 접근하는 경로를 더 빠르게 접근할 수 있도록 도와줌
- 디렉토리와 디렉토리에 있는 파일들의 관계를 유지하기도 함.
- 이게 실제로 디스크에 있는 파일 시스템에 연결되어 있음
- Inode와 파일을 연결시켜주는 역할을 함.
Dentry를 거쳐서 inode까지 가야 실제로 파일에 관련된 정보를 얻을 수 있다.
2. 정의해야 할 Operations
VFS는 상위 레벨 인터페이스이므로, 하위 구조인 각 파일 시스템들이 구현할 수 있는 함수들을 갖고 있어야 함.
모든 object들은 function table로의 포인터를 갖고 있다.
- int open(...): open a file
- int close(...): close an already-open file
- ssize_t read(...): read from a file
- ssize_t write(...): write to a file
- int mmap(...): memory-map a file
◆ Remote File System
네트워크를 통해 파일을 공유하는 방법들에는 여러 가지가 있다.
그중 네트워크를 통해 파일 시스템을 접근하는 경로도 있음. (NFS 등)
- FTP: 서버 address를 통해 파일을 직접 받아오는 프로토콜.
- DFS(분산 파일 시스템): 네트워크 상에 존재하는 여러 Shard File System 들을 클러스터링하여 Virtual File System 형태로 제공하는 것.
- 주로 여러 네트워크로 연결된 파일시스템들이 공유폴더를 구축하고, 이를 DFS 가 Managing 하여 클러스터링하는 형태이다. → 한번에 아무거나 다 접근할 수 있음. 편하게 탐색 가능
- WWW: FTP의 다른 버전. 다운로드/업로드를 위해 웹 브라우저를 사용함.
- NFS: 네트워크 상에 존재하는 파일을 로컬 파일인 것처럼 접근할 수 있도록 해주는 것.
◆ Network File System (NFS)
로컬 파일에 접근하는 것처럼 원격에 있는 파일에 접근(검색, 저장, 수정)할 수 있도록 해주는 시스템.
LAN이나 WAN을 통해 원격 파일에 접근하기 위한 소프트웨어 시스템을 의미함.
- 널리 사용되며, 잘 구현된 클라이언트-서버 네트워크 파일 시스템이다.
- TCP/IP 또는 UDP/IP 프로토콜을 사용하며, 이더넷이나 다른 네트워크를 통해 작동할 수 있다.
USB에 있는 파일을 F라는 디스크로 접근하는 것처럼, 원격 서버의 디스크를 통째로 로컬로 가져오는 것.
(DFS는 여러 개의 디스크를 모아서 한번에 접근할 수 있도록 하는 것이라는 점에서 차이가 있음.)
- 서버의 주소로 마운팅할 수 있음.
- RPC를 통해 원격 디스크에 접근함.
- 네트워크를 통해서 시스템 콜을 호출하고, 이에대한 결과도 네트워크를 통해 받아옴.
이 방식을 사용하면 그냥 로컬 폴더를 이용하는 것처럼 원격에 있는 파일에 접근(transparent manner)할 수 있다.
- 로컬 파일 시스템 디렉토리에 원격 디렉토리가 마운트 되어야 함.
네트워크로 접근 가능한 세 개의 장치 U, S1, S2가 있다 하자
- 왼쪽 그림에서, 만약 U가 '원격에 있는 S1의 shared라는 폴더를 쓰고 싶어! 로컬에 마운팅 하고 싶어!' 하면,
오른쪽 그림의 U에서처럼 마치 내 로컬에 있는 것처럼 사용 가능함.
◆ NFS Mount Protocol
NFS 마운트 프로토콜
- 서버와 클라이언트 간의 초기 논리적 연결을 설정합니다.
- 마운트 작업에는 마운트할 원격 디렉터리의 이름과 해당 디렉터리를 저장하는 서버의 이름이 포함됩니다.
- 마운트 요청은 해당 RPC로 매핑되어 서버에서 실행 중인 마운트 서버로 전달됩니다.
- Export list - 서버가 마운트할 수 있는 로컬 파일 시스템을 지정하며, 이를 마운트할 수 있는 허용된 머신의 이름도 포함됩니다.
- Export list를 준수하는 마운트 요청 이후에는 서버가 파일 핸들을 반환합니다.
이 파일 핸들은 추가 액세스를 위한 키 역할을 합니다. (어떤 클라에게 어떤 폴더를 마운트 허용할건지 결정)- File handle - 파일 시스템 식별자와 익스포트된 파일 시스템 내에서 마운트된 디렉터리를 식별하는 데 사용되는 아이노드 번호가 포함됩니다.
- 마운트 작업은 사용자의 뷰만 변경하고 서버 측에는 영향을 미치지 않습니다.
◆ NFS Protocol
NFS 프로토콜은 원격 파일 작업을 위한 일련의 RPC(원격 프로시저 호출)을 제공합니다:
- 디렉터리 내에서 파일 검색
- 디렉터리 항목 집합 읽기
- 링크 및 디렉터리 조작
- 파일 애트리뷰트에 접근
- 파일 read/write
NFS 프로토콜 특징
- NFS 서버는 상태를 유지하지 않으며(stateless), 각 요청은 독립적인 요청으로 완전한 argument 집합을 제공해야 합니다.
- 변경된 데이터는 결과를 클라이언트에 반환하기 전에 서버의 디스크에 커밋되어야 합니다(캐싱의 이점을 잃게 됩니다).
- NFS 프로토콜은 동시성 제어 메커니즘을 제공하지 않습니다.
◆ NFS Path-Name Translation
NFS에서 파일 경로를 이름으로 변환하는 과정.
- Path를 구성 요소 이름으로 나누고, 각 구성 요소 이름과 디렉터리 vnode 쌍에 대해 별도의 NFS lookup call 을 호출하여 수행됨.
- 예: /usr/local/dir1/file.txt
- 세 개의 구성 요소 (1) usr, (2) local 및 (3) dir1
- 각 구성 요소에 대해 별도의 RPC를 수행합니다.
- 예: /usr/local/dir1/file.txt
- 조회를 빠르게 하기 위해 클라이언트 측에는 원격 디렉터리 이름에 대한 vnode을 보유하는 directory name lookup cache 가 있습니다. → 오버헤드 감소
◆ NFS Remote Operations
- 보통의 UNIX 시스템 콜과 NFS 프로토콜 RPC 간에는 거의 일대일 대응이 있습니다(파일 open, close는 제외).
- 성능을 위해 버퍼링 및 캐싱 기술을 활용합니다.
- File-block cache - 파일을 열 때 커널은 원격 서버에게 캐시된 속성을 가져올지 또는 다시 확인할지 여부를 확인합니다.
- 파일 블록들에 데이터 및 메타데이터들이 저장되어 있을 것임.
해당하는 캐시된 속성이 최신 상태인 경우, 캐시된 파일 블록이 사용됩니다. (안 바뀌었으면 그냥 캐시해둔 거 씀)
- 파일 블록들에 데이터 및 메타데이터들이 저장되어 있을 것임.
- File-attribute cache - 새로운 속성이 서버로부터 도착할 때마다 attribute cache가 업데이트됩니다.
- File-block cache - 파일을 열 때 커널은 원격 서버에게 캐시된 속성을 가져올지 또는 다시 확인할지 여부를 확인합니다.
- 클라이언트는 데이터가 디스크에 기록되었다는 서버 확인을 받을 때까지 delayed-write block을 해제하지 않습니다.