우분투를 호스트 OS로 설치하다가 이 글을 쓰게 됐다. 설치 과정에서 파티션을 잡고 파일 시스템을 정하는 단계가 나오는데, 거기 기본값으로 Ext4가 찍혀 있었다. 그대로 넘어가도 됐지만 뭔지 모르고 고르는 게 걸려서 찾아보기 시작했다.
찾다 보니 두 갈래로 번졌다. 하나는 Ext4가 디스크를 실제로 어떻게 다루느냐, 다른 하나는 윈도우와 같이 쓸 드라이브는 뭘로 포맷해야 하느냐다.
그리고 정리하는 동안, 이 둘보다 개발할 때 훨씬 자주 물리는 차이가 따로 있다는 걸 알게 됐다. 윈도우에서 멀쩡히 돌던 빌드가 리눅스에서 파일을 못 찾는 문제다. 결국 그게 이 글에서 제일 실용적인 부분이 됐다.
세 가지를 순서대로 정리했다.
목차
목차
지금 뭘 쓰고 있는지부터
리눅스에서는 df에 -T를 붙이면 파일 시스템 유형이 같이 나온다.
$ df -Th
Filesystem Type Size Used Avail Use% Mounted on
tmpfs tmpfs 1.2G 3.7M 1.2G 1% /run
/dev/sda3 ext4 916G 221G 648G 26% /
tmpfs tmpfs 5.7G 34M 5.7G 1% /dev/shm
/dev/sda2 vfat 512M 5.3M 507M 2% /boot/efi
루트(/)가 ext4, EFI 파티션이 vfat인 전형적인 우분투 배치다. 마운트되지
않은 장치까지 보려면 lsblk -f가 낫다.
윈도우에서는 이렇게 확인한다.
fsutil fsinfo volumeinfo C:
우분투 설치 프로그램은 오래전부터 Ext4를 기본으로 잡아왔다. (자주 인용되는 “9.10부터”라는 시점은 해당 릴리스 노트 원문에서 확인하지 못했다. 확실한 건 지금도 기본이라는 것이고, 그건 위 명령으로 직접 확인하면 된다.)
Ext4가 디스크를 나누는 방식
블록 그룹
Ext4는 디스크를 블록 그룹으로 잘라 관리한다. 한 그룹의 크기는
8 × 블록 크기(바이트) 만큼의 블록이다. 흔한 4 KiB 블록이면 그룹당
32,768블록, 즉 128 MiB가 된다.
왜 나누냐면 관련된 데이터를 가까이 두기 위해서다. 파일의 메타데이터와 실제 데이터가 같은 그룹 안에 있으면 탐색 거리가 줄어든다. HDD 시절에는 헤드 이동 시간이었고, SSD에서도 지역성은 여전히 이득이다.
여담으로 재미있는 비대칭이 하나 있다. Ext4 본체의 필드는 전부 리틀엔디안으로 기록되는데, 저널(jbd2)만 빅엔디안이다. 커널 문서가 대문자로 “HOWEVER”를 써가며 경고할 만큼 헷갈리는 지점이다.
extent — ext3에서 가장 크게 바뀐 것
ext3는 파일이 어느 블록에 있는지를 간접 블록 매핑으로 기록했다. 블록 하나하나에 대한 항목을 만드는 방식이라, 큰 파일일수록 그 지도 자체가 비대해졌다.
Ext4는 extent를 쓴다. 연속된 물리 블록 덩어리를 항목 하나로 표현한다. 1 GiB짜리 파일이 통째로 연속 배치돼 있다면, 이론상 항목 몇 개로 끝난다. 큰 파일을 다룰 때 메타데이터 오버헤드가 확 줄어든다.
지연 할당
Ext4는 쓰기 요청이 오는 즉시 블록을 잡지 않는다. 데이터를 캐시에 두고 할당을 최대한 미룬다.
미루면 뭐가 좋은가. 파일이 최종적으로 얼마나 커질지 알게 된 다음에 자리를 잡을 수 있다. 조금씩 여러 번 append하는 파일도 한 번에 연속 공간을 받을 수 있어 단편화가 줄어든다.
저널
Ext4의 저널에는 체크섬이 붙는다. 저널이 손상됐는지 검사할 수 있게 된 것도 이득이지만, 부수 효과가 더 크다. ext3는 커밋을 2단계로 나눠야 했는데 체크섬이 있으면 한 단계로 끝낼 수 있고, 경우에 따라 최대 20% 정도 빨라진다.
한계치
| ext3 | Ext4 | |
|---|---|---|
| 최대 파일 크기 | 2 TB | 16 TB |
| 최대 파일 시스템 크기 | 16 TB | 1 EB |
| 하위 디렉터리 수 | 32,000 | 무제한 |
NTFS와 리눅스
NTFS의 중심에는 **MFT(Master File Table)**가 있다. 모든 파일과 디렉터리가 MFT의 레코드로 표현되고, 아주 작은 파일은 별도 블록을 받지 않고 레코드 안에 직접 들어간다.
리눅스에서 NTFS를 읽고 쓰는 방법은 그 사이에 한 번 크게 바뀌었다.
ntfs-3g— FUSE 기반. 사용자 공간에서 도는 구현이라 오랫동안 표준이었지만 커널 파일 시스템만큼 빠르지는 않았다.ntfs3— 커널 5.15에 들어간 인커널 드라이버. Paragon Software의 Konstantin Komarov가 주도했다. 풀 리퀘스트 설명 그대로 “NTFS 읽기·쓰기 드라이버이며, 일반/압축/희소 파일을 지원하고 acl과 NTFS 저널 재생을 지원한다.”
커널 문서 기준으로 ntfs3는 NTFS 3.1까지 지원하고, 마운트 옵션으로
umask/fmask/dmask(퍼미션), acl, discard(TRIM), windows_names
(윈도우에서 허용되지 않는 파일명 차단) 등을 제공한다.
windows_names는 실용적인 옵션이다. 리눅스에서는 만들 수 있지만 윈도우에서는
열 수 없는 이름(예: aux, 콜론이 들어간 이름)이 생기는 걸 막아준다.
개발자가 실제로 물리는 지점 — 대소문자
여기가 이 글에서 가장 실질적인 부분이다.
Ext4는 대소문자를 구분한다. Player.png와 player.png는 다른 파일이다.
NTFS도 사실 대소문자를 구분할 수 있다. 그런데 그 위의 윈도우가 기본적으로 무시한다. 마이크로소프트 문서의 표현 그대로다.
윈도우 파일 시스템은 파일과 디렉터리 이름을 대소문자 구분 없이 다룬다.
FOO.txt와foo.txt는 같은 파일로 취급된다.
그래서 이런 일이 벌어진다. 코드에 LoadTexture("player.png")라고 써놓고
실제 파일은 Player.png인 경우, 윈도우에서는 멀쩡히 돌아간다. 그대로
커밋하고 리눅스 빌드 서버에 올리면 파일을 못 찾는다. Unity 프로젝트를 윈도우
에서 작업하고 리눅스 CI에서 빌드할 때 전형적으로 나오는 실패다.
윈도우도 디렉터리 단위로 대소문자 구분을 켤 수 있다.
fsutil.exe file queryCaseSensitiveInfo <경로>
fsutil.exe file setCaseSensitiveInfo <경로> enable
다만 제약이 있다. 디렉터리가 비어 있어야 플래그를 바꿀 수 있다. 이미 파일이 들어찬 프로젝트 폴더에 나중에 켤 수는 없다는 뜻이라, 사후 처방으로는 쓰기 어렵다.
현실적인 방어는 이쪽이다.
- 에셋과 경로 이름 규칙을 정하고 소문자로 통일한다
- CI에 리눅스 빌드를 한 번 태워서 차이를 빌드 단계에서 잡는다
두 OS가 공유할 드라이브 포맷
원문 자료의 결론은 지금도 유효하다. 특별한 이유가 없으면 NTFS. 다만 근거 하나는 갱신이 필요하다.
exFAT — 특허 얘기는 이제 옛날 얘기다
오래된 자료에는 “exFAT은 특허 때문에 우분투가 기본 지원하지 않는다”고 적혀 있다. 그 시절에는 맞았지만 지금은 아니다.
2019년 8월 28일, 마이크로소프트가 exFAT 기술 명세를 공개하며 이렇게 밝혔다.
적합하고 상호 운용 가능한 구현의 개발을 돕기 위해 exFAT 기술 명세를 공개적으로 제공한다.
동시에 Open Invention Network의 리눅스 정의에 포함되는 것을 지지한다고 밝혔고, 그러면 OIN 회원·라이선시 3,040곳 이상의 방어적 특허 약정이 적용된다. 그리고 리눅스 커널 5.4에 exFAT 지원이 들어갔다.
다만 원문의 다른 지적은 여전히 유효하다. exFAT에는 파일 소유권과 퍼미션 개념이 없다. 리눅스에서 마운트하면 마운트 옵션으로 준 값이 일괄 적용된다. 권한을 유지해야 하는 용도에는 여전히 부적합하다.
FAT32 — 4 GiB 벽
FAT32는 4 GiB보다 큰 파일을 담지 못한다. 요즘 게임 빌드 산출물이나 녹화 영상은 이 선을 쉽게 넘는다. 소유권·퍼미션이 없는 것도 exFAT과 같다.
지금 FAT32를 고를 이유는 사실상 아주 오래된 장치와의 호환성뿐이다.
NTFS를 고르되, 알고 고르기
- 파일 소유권과 퍼미션이 유지된다
- 4 GiB 제한이 없다
- 리눅스 쪽 지원이
ntfs3로 커널에 들어오면서 예전보다 낫다
대신 두 가지는 감안해야 한다.
- NTFS에 우분투를 설치할 수는 없다. 루트 파일 시스템으로 못 쓴다.
- 오류 복구는 윈도우 쪽이 낫다. NTFS 볼륨이 깨졌을 때 리눅스가 윈도우 만큼 잘 처리하지 못한다. 우분투만 쓸 시스템이라면 굳이 NTFS를 쓸 이유가 없다는 뜻이기도 하다.
정리하면 이렇다.
| 소유권·퍼미션 | 4 GiB 초과 파일 | 리눅스 지원 | 우분투 설치 | |
|---|---|---|---|---|
| NTFS | ○ | ○ | 커널 ntfs3 | ✗ |
| exFAT | ✗ | ○ | 커널 5.4+ | ✗ |
| FAT32 | ✗ | ✗ | 오래전부터 | ✗ |
| Ext4 | ○ | ○ | 네이티브 | ○ |
정리
- 파일 시스템 확인은
df -Th(리눅스),fsutil fsinfo volumeinfo(윈도우). - Ext4는 extent로 큰 파일의 메타데이터를 줄이고, 지연 할당으로 단편화를 줄이고, 저널 체크섬으로 커밋을 한 단계로 끝낸다.
- 리눅스의 NTFS 지원은 FUSE(
ntfs-3g)에서 인커널ntfs3(5.15) 로 넘어왔다. - 공유 드라이브는 NTFS. exFAT의 특허 문제는 2019년에 정리됐지만, 소유권·퍼미션이 없다는 문제는 그대로다.
- 그리고 실제로 가장 자주 물리는 건 포맷 선택이 아니라 대소문자다. 윈도우에서 되던 게 리눅스에서 안 되면 여기부터 의심하면 된다.
참고
- ext4 Data Structures and Algorithms — Linux Kernel Docs
- Ext4 — KernelNewbies
- NTFS3 — Linux Kernel Docs
- [GIT PULL] ntfs3: new NTFS driver for 5.15 — LKML
- exFAT in the Linux kernel? Yes! — Microsoft Open Source Blog
- Case Sensitivity — Microsoft Learn
이 글의 출발점이 된 자료는 4.2. 파일 시스템 - Ext4와 NTFS이다. 항목 구성을 참고했고, 설명과 검증은 위 공식 문서를 기준으로 다시 작성했다.