콘텐츠로 바로가기

VFS & Filesystem Internals

서로 다른 수많은 파일 시스템을 하나의 표준 방식으로 다룰 수 있게 해주는 가상 파일 시스템(VFS) 계층과, 인덱스 노드(inode) 및 물리적 저장 구조를 다루는 학습 노드입니다.

Article
M

Me

hyunyoun's Blog

operating-systems-system-mechanicsoperating-systemssystem-mechanicsmemory-managementvirtualization-physicsvfsfilesystem-internalsos-storage9 min read

1. Overview

VFS와 파일 시스템 내부(VFS & Filesystem Internals)는 리눅스가 하드디스크, 네트워크 소켓, USB 메모리, procfs 같은 가상 파일 시스템까지 open(), read(), write()라는 공통 인터페이스로 다루게 만드는 추상화 계층입니다.

학습자는 EXT4 파일 시스템이 파일을 메타데이터(Inode)와 데이터 블록(Data Block)으로 나누어 관리하는 방식을 살핍니다. 이어 디렉터리(Directory)가 이름과 Inode 번호를 매핑하는 자료구조라는 점, 디렉터리 엔트리(Dentry) 탐색 흐름, 시스템 크래시 이후 파일 시스템 일관성을 보호하는 저널링(Journaling) 구조를 이해합니다.

2. Scope & Boundaries

In-Scope

  • VFS (가상 파일 시스템): struct file, struct inode, struct dentry, struct super_block. 리눅스의 객체 지향적(Object-Oriented in C) 인터페이스.
  • 파일 시스템 레이아웃 (EXT4/XFS): 아이노드(Inode) 테이블, 데이터 블록(Data Block), 수퍼 블록(Superblock), 비트맵(Bitmap).
  • 디렉토리 역학 (Namespace): 루트(/)부터 시작하는 디렉토리 엔트리 탐색(Path Lookup), 하드 링크(Hard Link)와 심볼릭 링크(Soft Link)의 Inode 포인터 궤적.
  • 내결함성 (Crash Consistency): 저널링(Journaling / WAL - Write Ahead Log), FSCK(File System Check), 트랜잭션 롤백/리플레이.

Out-of-Scope

  • 네트워크 소켓 버퍼 내부망: 소켓(TCP) 패킷이 read()로 얽혀 있긴 하지만 3-Way Handshake 같은 네트워크 스택 자체 \rightarrow 03-02-04. Inter-Process Communication (IPC) 영역.
  • 물리적 배드 섹터와 RAID: 하드디스크 미디어 물리적 파괴나 디스크를 여러 개 묶는 컨트롤러 레이어 \rightarrow 03-04-01. Disk, SSD & Magnetic Physics 영역.

Boundaries

  • VFS vs. EXT4 (Abstract vs Concrete): VFS는 open(), read(), write(), close() 같은 공통 인터페이스와 함수 포인터 구조를 정의합니다. EXT4나 XFS는 이 인터페이스를 구현해 실제 디스크 레이아웃에 맞게 동작합니다. VFS 덕분에 리눅스는 USB(FAT32)와 하드디스크(EXT4)를 같은 시스템 콜 경로로 다룰 수 있습니다.

3. Counterexample

  • 아이노드 고갈의 함정 (The No-Space Illusion): 디스크 여유 공간이 500GB 남아 있어도, 1바이트짜리 텍스트 파일을 매우 많이 생성해 Inode가 모두 소진되면 No space left on device가 발생할 수 있습니다. 데이터 블록 용량은 남아 있어도 파일 메타데이터를 표현할 Inode가 부족하면 새 파일을 만들 수 없습니다.
  • 하드 링크와 삭제 오해 (Hard Link Deletion Trap): 원본 파일(Inode 10)에 하드 링크를 여러 개 만든 뒤 rm 원본을 실행해도, 다른 링크가 같은 Inode를 계속 참조하면 데이터 블록은 회수되지 않습니다. 하드 링크는 원본과 복사본을 구분하지 않고 동일한 Inode를 공유하며, 참조 카운트가 0이 되어야 디스크 공간이 해제됩니다.

4. Prerequisites

  • 페이지 캐시와 블록 I/O (Basic): 램(Page Cache)에 더티 버퍼가 남아있다가 블록 디바이스로 쏟아지는 지연 쓰기 물리 구조를 알아야 파일 시스템 저널링의 필요성을 깨닫습니다. (03-03-02 Page Cache)
  • C 언어 구조체 포인터 (Recommended): VFS가 file_operations라는 구조체 안에 함수 포인터를 박아넣어 다형성(Polymorphism)을 구현하는 궤적을 이해해야 합니다.

5. Learning Map

Sequence Core Cluster Objective & Description Evidence (BoK)
1 VFS: The Grand Illusion 네트워크(Socket), 파이프, 하드디스크를 '파일'이라는 공통 인터페이스로 다루는 VFS 다형성 구조를 이해합니다. P1
2 The Inode Matrix 파일 이름과 실제 메타데이터가 분리되고, struct inode가 소유자·권한·블록 위치를 담는 방식을 이해합니다. P5
3 Namespaces & Dentry 디렉터리가 이름과 Inode 번호를 매핑하는 자료구조이며, /etc/passwd 같은 경로가 어떻게 탐색되는지 살핍니다. Industry
4 Journaling & Crash 파일 저장 도중 전원이 끊겨도 저널(Log)을 통해 파일 시스템 일관성을 복구하는 방식을 이해합니다. Industry

6. Learning Topics

Basic

Core Topic 01: 공통 인터페이스와 가상 파일 시스템 (VFS)

  • Why to Learn: 프로그램이 하드디스크(EXT4), USB 메모리(FAT32), 웹 소켓(TCP)을 읽을 때 서로 다른 구현 세부사항을 몰라도 read() 같은 공통 인터페이스로 다룰 수 있는 이유를 이해하기 위해서입니다.
  • What to Learn:
    • Concepts: VFS(Virtual File System), 4대 핵심 객체(Superblock, Inode, Dentry, File).
    • Skills: 파일 디스크립터 테이블(File Descriptor Table), file_operations 함수 포인터 맵핑.
    • Tools: 리눅스 커널 소스 fs/read_write.c.
    • Trade-offs: VFS 계층을 두면 여러 장치를 파일처럼 다루는 통일성(Everything is a file)을 얻습니다. 대신 단순한 USB 파일 읽기도 [User read() \rightarrow VFS sys_read() \rightarrow VFS 라우팅 \rightarrow FAT32 fat_read()] 같은 함수 호출 경로를 거치므로 커널 오버헤드가 발생합니다.
  • How to Learn:
    • 1단계: 사용자 앱이 open()을 호출하면 VFS가 struct file을 만들고, 그 안의 read 함수 포인터에 EXT4 파일 시스템의 ext4_read() 같은 구현 함수를 연결하는 다형성 바인딩을 확인합니다.
    • 2단계: 나중에 사용자가 read()를 호출하면 VFS가 연결된 함수 포인터(EXT4, FAT32, Socket 등)로 실행을 전달해 하위 구현이 작업을 수행하는 라우팅 흐름을 살핍니다.
  • Implement: 파이썬 클래스 상속과 다형성을 이용해 가상 VFS 엔진을 모사합니다. VFS_File 베이스 클래스를 상속받는 Ext4_Driver, Socket_Driver 클래스를 만들고, fd_table[3] = Socket_Driver()로 등록한 뒤 fd_table[3].read() 호출만으로 맞는 구현이 실행되도록 구성합니다.

Core Topic 02: Inode와 Data Block 구조 (The Inode & Data Blocks)

  • Why to Learn: 하드디스크에 저장된 test.txt가 하나의 연속 공간에만 놓이는 것이 아니라, 파일 메타데이터(Inode)와 여러 데이터 블록(Blocks)의 조합으로 관리된다는 구조를 이해하기 위해서입니다.
  • What to Learn:
    • Concepts: 아이노드(Inode, Index Node), 데이터 블록(Data Block), 다이렉트/인다이렉트 포인터(Direct/Indirect Blocks).
    • Skills: 파일 메타데이터(크기, 소유자, 권한, 수정시간) 파싱, stat 구조체.
    • Tools: 리눅스 ls -i, stat, df -i (Inode 사용량 확인).
    • Trade-offs: 데이터 블록을 연속으로 배치하면 순차 읽기 속도는 좋아지지만 삭제와 재할당이 반복될 때 외부 단편화가 생길 수 있습니다. Inode 포인터로 여러 블록을 연결하면 빈 공간 활용은 좋아지지만 포인터 탐색과 비연속 접근 비용이 늘 수 있습니다.
  • How to Learn:
    • 1단계: Inode: 파일 이름(test.txt)은 디렉터리에 있고, Inode는 파일 크기, 소유자, 권한, 실제 데이터 블록 주소(예: 15번, 99번, 1024번) 같은 메타데이터를 담는 구조체임을 확인합니다.
    • 2단계: Indirect Blocks: 10GB 같은 큰 파일은 Inode 내부 포인터만으로 모든 블록을 가리키기 어렵습니다. Indirect Block을 통해 추가 주소 목록을 두고 이중/삼중 트리 구조로 데이터 블록을 참조하는 방식을 살핍니다.
  • Implement: 100칸짜리 딕셔너리(Disk Blocks) 기반 파이썬 파일 시스템 모사. Inode = {'size': 8KB, 'blocks': [14, 55]}를 할당하고 파일 write() 시 빈 블록(Bitmap 탐색)을 찾아 번호를 blocks 배열에 엮어 넣음. 나중에 10KB로 팽창(append)할 때 추가로 빈 블록 88번을 잡아 리스트에 박아 넣어 파편화(Fragmentation)된 데이터를 트리 포인터로 꿰매는 로직 덤프.

Practical

Core Topic 03: 디렉터리 엔트리와 링크 (Dentry & Linking)

  • Why to Learn: 폴더(디렉터리)가 별도의 물리 상자가 아니라, 파일 이름 문자열과 Inode 번호를 연결하는 매핑 자료구조라는 점을 이해하기 위해서입니다.
  • What to Learn:
    • Concepts: 디렉토리 엔트리(Dentry), 디렉토리 데이터 구조, 하드 링크(Hard Link), 심볼릭 링크(Soft/Symbolic Link).
    • Skills: 경로 탐색(Path Resolution, /usr/bin/python), 참조 카운트(Reference Counting, i_nlink).
    • Tools: 리눅스 ln, ln -s, strace open.
    • Trade-offs: 하드 링크는 하나의 Inode에 여러 이름을 연결하므로 한 이름을 삭제해도 다른 링크가 남아 있으면 데이터가 유지됩니다. 다만 파일 시스템 경계를 넘기 어렵습니다. 심볼릭 링크는 다른 파티션의 경로도 가리킬 수 있지만, 원본 경로가 사라지면 Broken Link가 됩니다.
  • How to Learn:
    • 1단계: Dentry의 정체: 디렉터리 파일 내부가 ["test.txt" -> Inode 101], ["my_dir" -> Inode 50]처럼 이름과 Inode 번호의 매핑으로 구성될 수 있음을 확인합니다.
    • 2단계: Path Lookup: 사용자가 cat /usr/bin/ls를 실행하면 커널은 루트(/)에서 usr, bin, ls 순서로 각 디렉터리 엔트리를 따라 Inode를 찾습니다.
  • Implement: 파이썬 Directory 딕셔너리와 Inode_Table을 분리해 구현합니다. Dir = {'readme.txt': 55}로 매핑하고, ln readme.txt copy.txt 수행 시 Dir['copy.txt'] = 55만 추가한 뒤 Inode_Table[55].ref_count += 1을 올립니다. 원본 매핑을 삭제해도(del Dir['readme.txt']) 참조 카운트가 남으면 데이터가 유지되는 로그를 출력합니다.

Advanced

Core Topic 04: 저널링과 내결함성 (Journaling & Crash Consistency)

  • Why to Learn: 파일 저장은 Inode 업데이트, 데이터 블록 복사, 디렉터리 엔트리 갱신처럼 여러 단계로 이루어집니다. 중간에 정전이 발생해도 파일 시스템 일관성을 복구할 수 있도록 저널링이 필요한 이유를 이해하기 위해서입니다.
  • What to Learn:
    • Concepts: 저널링(Journaling), WAL(Write-Ahead Logging), 트랜잭션 커밋(Transaction Commit), 복구 리플레이(Recovery Replay).
    • Skills: FSCK(File System Check) 딜레이 타파, EXT4 저널 모드(Writeback, Ordered, Journal).
    • Tools: tune2fs -j (저널 옵션), dmesg (EXT4-fs recovery 로그).
    • Trade-offs: 저널링 없이 데이터를 바로 디스크에 쓰면 쓰기 경로는 단순하지만, 정전 발생 후 FSCK가 전체 디스크를 검사해야 할 수 있습니다. 저널링을 사용하면 로그를 보고 빠르게 롤백하거나 재실행할 수 있지만, 로그 영역과 원본 위치에 쓰는 이중 쓰기(Double Write) 비용이 발생할 수 있습니다.
  • How to Learn:
    • 1단계: 커널이 실제 데이터 위치를 수정하기 전에 "Inode 5번에 데이터 블록 99번을 할당한다"는 변경 기록(Log)을 Journal Area에 먼저 남기고 Commit 표시를 하는 Write-Ahead 흐름을 확인합니다.
    • 2단계: 본 데이터 쓰기 중 크래시가 발생하면, 재부팅된 OS가 Journal을 확인해 미완성 트랜잭션을 롤백(Rollback)하거나 재실행(Redo)해 일관된 상태로 복구하는 과정을 살핍니다.
  • Implement: Commit_Log = [] 리스트를 둔 파일 I/O 스크립트를 작성합니다. f.write(데이터) 수행 전 Commit_Log에 트랜잭션 기록을 남기고, 원본 업데이트 전 sys.exit(1)로 크래시를 모사합니다. 재실행 시 Commit_Log를 스캔해 Commit 표시가 없는 트랜잭션을 롤백하고 Consistent State를 복구합니다.

7. Terminology

Term (EN / ko, abbr) 1문장 정의 단계(기본/권장/실무/심화) 역할/맥락 관련 개념 유사/대비/함께 사용 오해 포인트 Evidence(Primary/Secondary/Industry) Flags(core)
VFS 다수의 물리 파일 시스템 위에 공통 인터페이스를 씌워 앱에게 표준 API를 제공하는 추상화 계층입니다. 기본 추상화 엔진 Interface / Driver Syscall 특정 FS 이름이 아님 P1:CS2023 core
inode (아이노드) 파일의 실제 데이터가 아닌 파일 자체의 속성 정보와 물리 위치를 담고 있는 고유 관리 블록입니다. 기본 메타데이터 핵 Metadata / Link File Name 파일 이름을 포함하지 않음 P1:CS2023 core
Mount (마운트) 특정 물리 장치를 운영체제의 전체 파일 계층 트리(VFS) 중 한 지점에 결합하는 물리적 행정 절차입니다. 추천 장치 결합 Root / Path Attach '단순 연결' 이상의 논리 결합 Industry Unix core
procfs 커널 내부의 데이터나 프로세스 정보를 일반 파일처럼 읽고 쓰게 해주는 램 기반의 가상 파일시스템입니다. 실무 동적 정보 노출 sysfs / Debug Disk FS 디스크 공간을 점유하지 않음 Industry Internals core

8. References

Primary

Secondary

  • [Understanding the Linux Kernel] Bovet & Cesati — Detailed VFS implementation.
  • [Operating Systems: Three Easy Pieces] Remzi — The File System Abstraction.

Industry

  • [Kernel.org: Overview of the Virtual File System] — Official Linux documentation.
  • [Microsoft: Windows File System Architecture] — NTFS and Filter Drivers.

9. Final Checklist

Primary

  • '모든 저장소는 파일이다(Everything is a file)'라는 철학이 VFS를 통해 어떻게 호출 구조로 구현되는지 설명 가능한가? (P1)
  • 'inode'가 가지고 있는 정보 중 왜 '파일 이름'은 제외되는지, 디렉터리와의 관계를 통해 설명할 수 있는가? (P1)

Secondary

  • '심볼릭 링크'와 '하드 링크'가 수정되었을 때 디스크 상의 inode 참조 카운트와 데이터 상태의 차이를 설명할 수 있는가?
  • 대용량 파일 시스템 탐색 시, 왜 dentry 캐시가 시스템 전체의 UI 응답 속도에 영향을 주는지 인과관계를 도출할 수 있는가?

Industry

  • 임베디드 리눅스 시스템 구축 시, /proc/sys를 활용하여 장치 드라이버의 상태를 실시간 모니터링하는 방안을 제안할 수 있는가? (SFIA)
  • 루트 파일시스템(Root FS)이 마운트되지 않았을 때 커널이 부팅 과정에서 겪게 되는 'Panic'의 원인을 기술하고 해결 절차를 마련할 수 있는가?

OS Storage & I/O

4 / 8