Linux 시리즈 #03 — 파일·inode 내부: ext4/XFS 온디스크 구조와 익스텐트
이 글의 핵심
온디스크 inode가 메타데이터와 데이터 위치를 어떤 자료구조로 표현하는지(ext4 익스텐트·XFS 포크·B+트리)를 운영·성능 튜닝 관점에서 풀어 씁니다.
시리즈 안내
#03 | 실무 트러블슈팅: Linux 디스크 full vs inode · 블록·저널·I/O 스케줄러: #09 디스크·블록 계층 · 개요: Linux 완전 가이드
1. 들어가며: 새벽 3시, df만 믿다가 큰코 다친 썰
새벽 3시에 디스크는 충분한데 파일 생성 실패 — 이런 거, 한 번 겪으면 잊기가 어렵다. df -h는 멀쩡한데 touch 한 방에 No space left on device가 뜨고, 슬랙은 멘션 지옥이고, 나는 그제야 df -i를 찍어본다. … inode가 바닥난 거였지. 그날 이후로 “용량”이랑 “슬롯”이 다른 축이라는 걸 몸으로 배웠다.
UNIX·리눅스에서 말하는 “파일”은 겉으로 보이는 경로 문자열이랑, 커널이 실제로 붙잡는 inode(아이노드)가 따로 논다. 용량 남아도 생성이 안 되거나, 링크랑 cp가 헷갈리게 다르게 느껴지거나, rm 했는데도 옛 파일에 쓰기가 된다 — 대부분 여기서 설명 가능하다. 이 글은 VFS·ext4·XFS를 한 바퀴 돌고 온디스크 inode의 익스텐트까지 잡아당기면서, 일상 운용이랑 inode 고절·메타데이터 I/O 쪽 트러블도 같이 묶어둔다. 저널·블록 buddy·I/O 스케줄러 를 파고파고 싶으면 #09로 가면 된다, 나는 그렇게 읽는 편.
2. 파일 시스템 개요: VFS, ext4, XFS
2.1 VFS(가상 파일시스템)의 역할
리눅스 커널은 VFS 계층에서 open/read/write/mmap 같은 공통 inode·dentry·file 추상을 내주고, 밑에 ext4, XFS, Btrfs, NFS가 각자 온디스크 포맷을 구현한다(우리는 “경로”로만 쓰지만, 커널은 (파일시스템, inode 번호) 키로 캐시한다). 경로 → dentry → inode를 자주 밟을수록 dentry·inode 캐시 히트가 성능에 박힌다 — 빌드 돌릴 때 체감하는 그 지연, 여기서 일부 설명이 된다.
2.2 ext4(Fourth Extended File System)
ext4는 저널링을 지원하는 익스텐트 기반 범용 로컬 파일시스템입니다. 블록 그룹 단위로 inode 비트맵, 블록 비트맵, inode 테이블이 배치되고, flex_bg 등으로 메타데이터를 묶어 배치를 최적화할 수 있습니다. 소수의 대용량 파일뿐 아니라 다수의 작은 파일이 섞인 워크로드에서, inode 개수와 디렉터리·메타데이터 I/O가 병목이 되기 쉽습니다. 관리 도구로는 tune2fs, debugfs 등이 대표적입니다.
2.3 XFS
XFS는 할당 그룹(AG, allocation group) 으로 디스크를 나누고, 자유 공간·inode 정보를 B+트리로 관리하는 쪽에 가깝습니다. ext4의 “한 번에 깔아 둔 inode 테이블”과 달리, inode 청크를 메타데이터 공간에서 동적으로 확장하는 모델이 흔해, “inode 비트맵이 찼다”보다 메타데이터 공간·AG 밸런스가 함께 논의됩니다. 지연 할당·스펙 프리올로케이션 등은 순차 쓰기·대용량 파일에 유리한 대신, 혼합 워크로드에서 다른 AG의 지연으로 번질 수 있습니다. 관측에 xfs_info, xfs_bmap, xfs_db 등이 쓰입니다.
2.4 그래서 뭘 쓰냐(현장 버전)
이건 조직마다 싸움이 나는 부분인데, 대략 이렇게 말해도 될 듯. ext4는 “어디에나 깔기 좋고, 도구도 익숙하다” 쪽. 루트 파티션이 ext4인 서버, 주변에 꽤 많다. XFS는 대용량·순차 I/O 많은 데이터 쪽, 그리고 inode 쪽 유연성을 더 쳐주는 케이스에서 자주 나온다(표준·벤치가 진짜 정답이긴 하다).
둘 다 결국 inode(정확히는 VFS inode랑 온디스크 dinode)랑 익스텐트 얘기로 수렴하니까, 이제 “inode에 뭐가 들어가냐”로 넘어가 보자.
3. Inode 구조: inode란 무엇인가, 저장 정보
3.1 inode의 역할(개념)
inode는 “데이터가 디스크 어디에, 얼마나”랑 “누군 누구 소유고 권한은 뭔가”를 적어둔 메타데이터 레코드다. 파일 이름은 inode에 안 박힌다 — 기억하라고 세 번은 말하고 싶다. 이름→inode는 부모 디렉터리 엔트리가 들고 있으니, “같은 파일”을 이름만 바꾼다 = 디렉터리만 손댄다, 쯤의 감각이 생긴다.
3.2 일반적으로 inode(및 VFS inode)에 들어가는 정보
- 파일 타입 (일반, 디렉터리, 심볼릭 링크, FIFO, 소켓, 블록/캐릭터 디바이스 등)
- 접근 권한(permission bits) 와 특수 비트 (setuid, setgid, sticky)
- 소유자 UID, 그룹 GID
- 크기, 블록 수
- 타임스탬프 (atime, mtime, ctime; 파일시스템에 따라 birth/ctime 해석이 다를 수 있음)
- 하드 링크 수(링크 카운트,
nlink) — 0이 되면 데이터 블록이 반환될 수 있음(열려 있는 fd가 없을 때) - 데이터 위치 — 익스텐트, 포인터 트리 등(파일시스템별)
3.3 VFS struct inode vs 온디스크 inode
- VFS
struct inode: 캐시 슬래브·락·참조 카운터·i_mapping,i_op/i_fop로 파일시스템별 연산에 연결되는 인메모리 객체입니다. - 온디스크 inode:
mkfs시점 inode 크기(128B, 256B 등)와 슈퍼블록 파라미터에 맞춘 고정 레이아웃의 블록입니다. ext4·XFS·Btrfs는 필드·트리 구조가 서로 다릅니다. FAQ에도 요약한 대로, 둘을 동일한 “inode”로 혼동하면 안 됩니다.
4. Inode vs 파일명: 디렉터리의 역할
4.1 이름은 디렉터리에, inode는 별도
경로 /var/log/nginx/access.log 를 열면, 커널은 루트 → var → log → nginx → access.log 순으로 부모 디렉터리를 읽으며 하위 이름 → inode 번호를 찾습니다. 동일한 inode를 서로 다른 이름으로 가리킬 수 있는데(하드 링크), 한 inode에 여러 이름이 붙은 상태는 링크 카운트로 표현됩니다.
4.2 “같은 디렉터리 안”과 “다른 파티션”
- 하드 링크는 같은 파일시스템(같은 마운트) 내에서만 가능합니다. 다른 파티션에 있는 경로끼리는 inode 공간이 다르므로 하드 링크로 묶을 수 없습니다. 이때는 심볼릭 링크(경로 문자열만 보관)를 쓰는 것이 일반적입니다.
4.3 디렉터리의 온디스크 표현(요지)
ext4 디렉터리는 이름 목록이 단순 리스트에 그치지 않고, 규모가 커지면 해시 디렉터리(htree) 등으로 이름 조회가 트리 탐색이 될 수 있습니다. “같은 ls”라도 콜드 캐시에서는 I/O 패턴이 달라지고, 운영에서 보이는 메타데이터 IOPS로 나타납니다. 이는 뒤의 성능·캐싱 절과 연결됩니다.
5. 하드 링크: 동일 inode 참조, 예제
5.1 정의
하드 링크는 새로운 디렉터리 엔트리(이름) 를 만들어 기존 inode를 가리키게 하는 것입니다. ls -i로 보면 inode 번호가 동일하고, stat의 Links(nlink)가 증가합니다.
5.2 예제
echo 'hello' > a.txt
ln a.txt b.txt
ls -li a.txt b.txt
stat a.txt
a.txt와 b.txt는 같은 inode를 공유하므로, 한쪽을 수정하면 다른 쪽에도 즉시 반영됩니다. “복사”(cp 기본)와 달리 추가 디스크 공간(데이터 블록) 은 늘지 않습니다(엔트리·메타데이터만).
5.3 제약과 운영 팁
- 같은 파일시스템 안에서만 생성 가능.
- 디렉터리에 대한 하드 링크는 일반 사용자에게는 금지되는 것이 기본(루프·이름 붙이기의 혼란 방지)입니다(구현·정책은 환경 확인).
- 백업·동기화 도구는 하드 링크를 그대로 복제하거나 파일로 풀어 복제하도록 옵션이 갈립니다(
cp -l,rsync동작 등; 실습 시-n/--link-dest문서를 확인).
5.4 (잡담) 팀에서 하드 링크 vs 심볼릭 링크로 싸웠던 적이…
전에 배포 스크립트 짤 때였다. A는 “원본이랑 진짜 같은 inode를 쓰게 하드 링크로 박자, 그게 정공법이지”라고 했고, B는 “야 다른 마운트 넘어가면 하드 링크 못 만든다며, 운은 심볼릭이지”라고 했다. … 둘 다 맞는 말이라서 더 짜증 났다. 결국 같은 파일시스템 안에서만 하드 링크가 되고, 넘어가면 심볼릭으로 가야 한다는 걸 화이트보드에 크게 쓴 다음에야 끝났다. 그리고 심볼릭은 상대 경로로 박았다가 배포만 바뀌고 깨지는 case가 많으니, 그건 또 별도로 싸움(이건 6절 예제 쪽).
6. 심볼릭 링크: soft link, 차이점, 사용법
6.1 정의
심볼릭 링크(소프트 링크) 는 자체 inode를 갖는 특수 파일이며, 데이터에 “다른 경로 문자열”을 저장합니다. 대상이 삭제·이동되면 끊긴(broken) 링크가 됩니다. 다른 파티션이나 디렉터리를 가리킬 수 있어, 하드 링크보다 유연합니다.
6.2 하드랑 심볼릭, 표 말고 그냥 썰
표로 정리하려다가 “AI 냄새” 날 것 같아서 뺐다. 그냥 이렇게 기억하면 된다. 하드 링크는 inode를 공유한다. 그래서 ls -i 찍으면 숫자가 똑같고, 데이터 블록을 새로 쓰는 게 아니라 디렉터리에 이름 하나 더 파는 느낌에 가깝다. 같은 파일시스템 안에서만 되고, 경계 넘으면 errno가 뜬다(그때 B가 “내 말이 그 말” 하는 장면). 심볼릭은 inode가 따로 있고, 내용이 문자열이다. FS 넘어가도 되는 대신, 원본이 날아가면 dangling 이 되고, 상대 경로면 지금 위치에 따라 의미가 바뀐다(배포할 때 이거 터지면 꽤 끔찍하다).
6.3 예제
ln -s /var/log/app app.log
ls -l app.log
readlink -f app.log
상대 심볼릭 링크(ln -s ../data/foo)는 현재 위치에 따라 깨질 수 있으므로, 배포·컨테이너·스크립트에서는 절대 경로·canon 경로 사용 여부를 루틴으로 정하는 것이 안전합니다.
7. Inode 테이블: 고갈 문제, df -i
7.1 df와 df -i의 차이
df -h: 데이터 블록 남는 양(사람 눈엔 “디스크 full”).df -i: inode가 몇 슬롯 남았나.
용량이 남는데도 No space left on device 뜨면, 이제는 반사적으로 inode/메타데이터 의심하면 된다(반대로 inode는 풍년인데 블록만 떨어지는 케이스도, 또 있다).
df -h /
df -i /
7.2 ext4의 inode 수
ext4는 포맷 시 inode 밀도(bytes-per-inode 등)에 따라 최대 inode가 달라질 수 있어, “작은 파일이 매우 많은” 애플리케이션이 올라갈 전에 설계·마운트 옵션을 점검하는 것이 좋습니다. (사후에는 백업 후 mkfs 등이 대개 필요합니다.)
7.3 XFS의 표현(요지)
XFS는 AG·메타데이터와 함께 inode가 확장됩니다. df -i만이 아니라 메타데이터 공간, AG 관련 경고가 툴에 함께 뜨는 사례가 있습니다. 자세한 실무 순서는 inode full 트러블슈팅을 권장합니다.
8. 파일 메타데이터: stat, 권한, 타임스탬프
8.1 stat으로 inode와 타임스탬프
stat /path/to/file
ls -l --time=atime
ls -l --time=ctime
- atime: 접근(마운트 옵션
relatime등으로 갱신 빈도가 달라질 수 있음) - mtime: 내용 수정
- ctime: inode 메타데이터 변경(권한, 소유자, 링크 수 등) —
chmod·chown도 여기에 해당하는 경우가 많습니다.
파일시스템/커널에 따라
birth/Btime등의 표기가 달릴 수 있어, “파일이 언제 생겼는가”는 툴·FS에 의존합니다.
8.2 ls가 보여 주는 권한 문자열
ls -l
맨 앞 한 글자는 파일 타입, 이어지는 9자는 rwxrwxrwx (user/group/others)입니다. 추가로 ls -l에서 끝에 +가 있으면 ACL 등 확장 ACL이 붙었을 수 있어 getfacl로 확인하는 편이 안전합니다.
9. 파일 타입: 일반, 디렉터리, 심볼릭, 블록/캐릭터
9.1 ls 맨 앞 한 글자, 그냥 스토리로
표 대신, 온콜에서 맨날 보던 화면만 말해볼게. 맨 앞이 -면 그냥 파일, d면 디렉터리, l이면 심볼릭(옆에 화살표 나오는 그거). b / c 는 블록이랑 캐릭터 디바이스고, p 는 FIFO, s 는 소켓. 첫 글자만 보면 “이게 파일 내용이 있는지, 디렉터리인지, 링크인지, 드라이버랑 붙은 특수 파일인지”가 갈린다. 처음엔 외우기 싫은데, grep 하다 보면 익는다.
9.2 디바이스 파일
/dev 아래 블록·캐릭터 파일은 “디스크에 바이트 나열”이 아니라, 드라이버에 연결된 특수 inode에 해당합니다. major/minor 번호는 ls -l에 표시됩니다. 컨테이너/호스트는 cgroup·드라이버 노출이 달라, 같은 경로라도 의미가 다를 수 있습니다.
10. 권한 시스템: rwx, chmod, umask
10.1 rwx(읽기/쓰기/실행)
- 파일: 읽기·쓰기·실행(바이너리/스크립트)
- 디렉터리:
r은 이름 열람,w는 엔트리 생성/삭제,x는 통과(traverse·접근). 디렉터리에서x없이r만 있으면 이름을 읽을 수는 있으나 하위에 들어가기 어려운 딜레마가 납니다(실제 시나리오는 환경에 따라+t·ACL이 개입).
10.2 8진수 chmod와 심볼 chmod
chmod 644 file.txt
chmod u+rw,go-w somedir
10.3 umask
새로 생성되는 파일·디렉터리의 기본 권한에서 비트를 빼는 값입니다(셸·프로세스별).
umask
( umask 027; touch a; mkdir d; ls -ld a d )
애플리케이션이 open()에 명시 mode를 주면, umask와 합쳐진 결과가 됩니다(코드·런타임마다 기대를 문서화).
11. 소유권: user, group, chown, chgrp
sudo chown user:group /path
sudo chgrp group /path
- root만 임의 소유 변경이 가능한 경우가 일반적(배포 정책·SELinux·ACL과 충돌 시 조사).
- set-group-ID 디렉터리(
chmod g+s)와 합쳐지면 새 파일의 그룹이 부모에 맞춰지는 등, 팀 공유 디렉터리에서 자주 쓰는 패턴입니다(보안·감사 정책과 함께).
12. 특수 비트: setuid, setgid, sticky
12.1 setuid(4000) / setgid(2000) — chmod u+s / g+s
- setuid: 실행 시 이진 파일 소유자 권한으로 동작(전통적 예:
passwd). 보안 민감 — 불필요한 setuid는 제거. - setgid: 실행 시 그룹으로 동작(실행 파일), 디렉터리에 붙이면 새 파일·하위의 그룹 상속 용도로 쓰입니다.
chmod u+s /path/bin
chmod g+s /path/shared_dir
12.2 sticky bit(1000) — chmod +t (흔한 예: /tmp)
디렉터리에 붙이면, 자신이 소유한 항목만 삭제할 수 있게 하여, 쓰기 가능·공용인 디렉터리에서 타인 파일 삭제를 막습니다.
ls -ld /tmp
# ... drwxrwxrwt ... <- 마지막 t
수치로는 chmod 1777이 전형적인 공용·공개 쓰기 패턴(요구·보안 정책에 맞는지는 별도 검토).
12.3 ls로 한눈에: s, S, t, T
- x 자리에
s/t가 소문자이면x가 함께 켜진 것, 대문자이면x없이 특수만 켜진 것으로 해석됩니다(실수 진단에 유용).
13. Inode 넘버 확인: ls -i, stat
ls -i
find . -samefile /path/to/file
stat -c '%i %n' /path/to/file
find -samefile: 동일 inode를 다른 이름으로 가진 전체를 찾을 때 강력합니다(트래버스 권한 주의).
14. 파일 삭제 메커니즘: unlink와 링크 카운트
14.1 unlink(2) / rm이 하는 일
디렉터리에서 이름(엔트리)을 제거하는 것이 unlink입니다. 하드 링크 수(nlink)가 0이 되고, 해당 inode를 열고 있는 fd가 없다면 데이터 블록·inode 슬롯이 해제될 수 있습니다. 프로세스가 파일을 open 해 둔 채 마지막 링크를 지우면, 디스크에서 이름은 사라지지만 inode는 살아 있고, 열린 fd로 읽기/쓰기가 계속됩니다(로그 로테이션·임시·보안·포렌식에서 중요).
14.2 lsof로 “삭제되었는데 잡아 먹는” 파일 찾기
(아래 15절에서 상세) lsof의 DEL/deleted 표기, /proc/PID/fd 탐색이 대표 루틴입니다.
15. 실전 예제: 백업, 로그 로테이션
15.1 백업과 inode·하드 링크
- 하드 링크 기반 증분(예:
rsync의 링크 옵션 조합)은 동일 FS이어야 하며, inode 절약·공간에 유리할 수 있으나, 가시성·복구 절차를 문서화해야 합니다. - 대량의 작은 파일은 아카이브(tar, squashfs 등) 로 묶는 것이, 백업 스캔·restore 측면에서 유리한 경우가 많습니다.
15.2 로그 로테이션과 “공간이 안 늘어남”
일반적 패턴:
# 예시: 앱이 /var/log/app.log 를 열어둔 상태에서
mv /var/log/app.log /var/log/app.log.1
# 앱이 reopen 하지 않으면, 여전히 옛 inode에 쓰는 경우가 있음
- 해결:
copytruncate,logrotate의postrotate에 시그널(예:USR1), 앱의 reopen 지원 등. 삭제·이동 후df는 변해도, open fd가 잡고 있으면 블록이 반환되지 않을 수 있습니다(14절).
15.3 logrotate 구성 스케치(개념)
아래는 의미 전달용 예시이며, 배포 환경·데몬 문서에 맞게 조정해야 합니다. copytruncate는 앱이 reopen을 지원하지 않을 때 쓰지만, 진행 중 쓰기와 경합할 수 있어 앱 지원 여부를 반드시 확인합니다.
# /etc/logrotate.d/app-example (개념 예시)
/var/log/app/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
sharedscripts
postrotate
/bin/kill -USR1 `cat /var/run/app.pid` 2>/dev/null || true
endscript
}
sharedscripts는 여러 로그가 한 번에 돌 때 postrotate를 한 번만 실행하게 합니다. Nginx·기타 데몬은 시그널로 로그 fd를 다시 열도록 설계된 경우가 많아, 공식 문서의 시그널 표를 기준으로 합니다.
15.4 find로 inode·같은 파일 추적
find /var/tmp -xdev -inum 12345678 -ls
find /data -samefile /data/a/file.bin
-xdev는 다른 파일시스템으로 넘어가지 않게 해 하드 링크 탐색에 유리합니다. 악의적/실수로 링크가 많이 생긴 경우 스토리지 회계에 도움이 됩니다.
16. 디버깅: lsof, inode 고갈 해결
16.1 lsof 기본
sudo lsof /path
sudo lsof -p PID
lsof -nP -i
- 누가 파일·소켓·
mmap을 잡고 있는지 보여 줍니다. “삭제된 대용량 로그”가 fd에 살아 있으면, 프로세스 재시작·logrotate 시그널 전까지df가 회복되지 않을 수 있습니다.
16.2 inode는 남는데 “생성 못 함”
- inotify 한도, 디스크 I/O 실패, 쿼터와 혼동 방지(별도
quota,xfs_quota점검). - XFS는 AG 자유·메타데이터와 연관된 특이 실패가 tool 메시지에 드러날 수 있음(위 링크 글·
dmesg).
16.3 ext4: debugfs로 익스텐트 개수(요지, 읽기 전용)
sudo debugfs -R 'stat /path/to/file' /dev/sdXN
Extents:항목이 비정상적으로 크면 조각화·소량 랜덤 쓰기를 의심합니다(피크 타임debugfs는 주의).
16.4 XFS: xfs_bmap
sudo xfs_bmap -v /path/to/file
논리 오프셋 → 물리 익스텐트가 정리됩니다. unwritten 등 예약/미기록 구간 표기는 환경·버전에 따릅니다.
17. 성능 고려 사항: inode·dentry·page 캐시
- VFS: inode·dentry 캐시 히트가 경로 해석·
stat스톰을 줄입니다. 수백만 경로를 랜덤으로 두드리는 워크로드는 샤딩·아카이브·캐시 설계가 필요할 수 있습니다. - ext4 htree: 대규모 디렉터리에서 이름 조회가 트리로 바뀌며 콜드 캐시 I/O가 달라질 수 있음(4절·원문 요지).
- XFS: 지연 할당·AG가 순차 쓰기엔 이점이, 혼합 I/O에선 다른 쓰기와 경합(요지) — 벤치·#09로.
- xattr·SELinux·ACL이 많이 붙는 환경은 XFS attr 포크·ext4 외부 EA가 메타데이터를 씹을 수 있음(원문 프로덕션 패턴).
17.1 VFS inode 캐시와 dentry 캐시
경로를 열 때마다 커널은 dentry(이름 조각) 체인과 inode 객체를 채웁니다. 반복적으로 같은 트리를 탐색하는 워크로드(빌드, 정적 사이트 생성, 대량 git status)는 캐시 히트에 이익을 보고, 수백만 개의 서로 다른 경로를 한 번씩만 건드리는 워크로드는 콜드 미스가 이어져 메타데이터 IOPS가 한계에 닿기 쉽습니다. 운영에서는 “디스크 대역은 남는데 iowait·메타 지연만 큰” 패턴이 이때 흔합니다.
17.2 page cache와 inode의 관계
파일 내용은 페이지 캐시에 올라가고, inode는 “어느 페이지가 이 파일에 속하는가”를 address space(i_mapping)로 연결합니다. 대용량 순차 읽기는 페이지 캐시에 유리하고, 작은 랜덤 쓰기는 익스텐트·트리 갱신과 저널을 자주 건드립니다. 성능 튜닝은 “한 inode에 쓰기가 얼마나 몰리는가”와 “동시에 몇 개의 inode를 갱신하는가”를 나누어 보는 것이 유효합니다.
17.3 메타데이터 I/O를 키우는 대표 패턴
- 짧은 시간에 대량
create/unlink: CI 아티팩트, 임시 빌드 트리, 수백만 조각으로 쪼개진 캐시. - 거대 디렉터리에
readdir+stat: 백업 스캐너, 바이러스 스캔, 잘못된find조합. - xattr·ACL 동시 갱신: 컨테이너 이미지 추출, 대량
chown -R와 겹칠 때 메타데이터 락·저널 경합.
17.4 drop_caches와 inode(주의)
트러블슈팅에서 echo 3 > /proc/sys/vm/drop_caches 를 쓰는 경우가 있으나, 페이지·dentry·inode 캐시를 비우면 즉시 재적재되며 순간 스파이크를 감수해야 합니다. 프로덕션에서는 원인 분석·워크로드 조정이 선이고, 캐시 드롭은 일시 완화로만 이해하는 것이 안전합니다.
17.5 컨테이너·OverlayFS·상위 볼륨
OverlayFS 등 합성 마운트 환경에서는 상·하위 레이어마다 inode 네임스페이스가 달라, 호스트에서 본 inode 번호와 컨테이너 안이 다를 수 있습니다. 바인드 마운트된 볼륨은 호스트 FS의 inode를 그대로 쓰므로, inode 고절은 그 볼륨의 포맷에 직접 연결됩니다. “같은 경로인데 다른 inode” 같은 혼란은 마운트 경계를 먼저 확인합니다.
18. VFS·온디스크 inode(심화): ext4 i_block과 익스텐트
18.1 ext4: 블록 그룹, inode 테이블, i_block
온디스크 inode에는 고정 필드와, 데이터 위치를 담는 i_block 공간이 있습니다(전통 15×__le32 근방). 호환 모드는 직·단일·이중·삼중 간접 해석이었고, 익스텐트 모드에서는 INCOMPAT_EXTENTS 등이 켜진 일반 ext4가 익스텐트 트리로 같은 바이트를 해석합니다.
18.2 익스텐트 헤더와 트리(요지)
- 리프/인덱스 구분, 엔트리 수, 깊이
- 리프
(논리 시작, 길이, 물리 시작)— 연속이면 엔트리 수를 줄여 CPU·메타 I/O를 절약 - 인덱스 — 자식 블록, 담당 논리 오프셋 하한
트리가 깊어지고 쪼개질수록 메타데이터 쓰기와 지연이 늘 수 있어, 조각화는 “데이터뿐 아니라 메타 I/O” 이슈가 됩니다.
18.3 인라인 데이터·fast commit(포인트)
- 인라인 데이터: 아주 작은 파일을 데이터 블록 없이 inode 여유에 — inode당 공간과 밀도 trade-off.
- fast commit(조합): 저널 경로·지연·
fsync와 상호작용 — 상세는 #09.
18.4 debugfs 예시(18절과 동일 루틴, 반복이면 한 번만)
sudo debugfs -R 'stat /path/to/file' /dev/sdXN
익스텐트 개수·최대 깊이 류는 툴 출력에 환경·버전이 반영됩니다.
19. XFS(심화): dinode, 포크, BMBT, 스펙 프리온
19.1 AG와 dinode(요지)
온디스크 dinode는 코어, 데이터 포크(data fork), 속성 포크(attr fork) 로 나뉩니다. 짧은 내용은 인라인, 커지면 익스텐트가 B+트리(BMBT, 블록 맵 B-트리) 로 확장될 수 있습니다.
19.2 attr 포크·xattr
SELinux·컨테이너 라벨·다수의 xattr이 붙는 이미지는 데이터는 작은데 attr 포크가 비대해질 수 있어, getfattr, xfs_bmap, 메타데이터 사용 추적이 필요할 수 있습니다.
19.3 스펙 프리올로케이션(요지)
fallocate·대용량 순차 쓰기는 AG·자유 B+트리에 순간 부하를 주고, 다른 I/O로 지연이 퍼질 수 있습니다(할당·스케줄은 #09).
19.4 xfs_bmap 예
sudo xfs_bmap -v /path/to/file
19.5 ext4 vs XFS, inode만 놓고 보면(표는 안 씀)
둘을 “완벽한 비교표”로 열거하면 위키 같아져서(…) 그냥 감으로 말해볼게. ext4 쪽은 블록 그룹에 inode 테이블·비트맵이 박혀 있고, 데이터 위치는 i_block 쪽 익스텐트 트리로 읽힌다. 작은 건 인라인으로 잡는 경우가 있고, xattr 쪽은 EA 블록이 따로 붙는 그림. 도구는 tune2fs, debugfs 쪽이 익숙하다. XFS는 AG가 나뉘고, dinode / 포크 / BMBT 쪽 이야기로 이어지는 편. 작은 파일·짧은 포크, attr은 attr 포크 쪽이 튀어나온다(SELinux·라벨 말 많은 환경에서 체감). 관측은 xfs_info, xfs_bmap, xfs_db … 이런 툴 루트. 둘 다 “inode라고 한 가지”가 아니라는 것만 머리에 넣고 가면, 문서 읽을 때 덜 멘붕 난다.
20. 프로덕션 “패턴”(요약, inode·메타 I/O)
- 수백만 소파일: inode·dentry·디렉터리 병목 → 샤딩·아카이브·캐시 검토
- 대용량 단일 로그: 익스텐트 수는 적을 수 있으나 저널·flush·락이 맞물림
- xattr 폭증: XFS attr·ext4 EA가 메타데이터 압박
- DB·임시 파일 폭주: “파일 내부”와 별도로 파일시스템 inode/할당이 드러남
20.1 rsync·백업과 하드 링크
rsync의 기본은 “대상에 동일 내용이 있으면 덮어쓰기/전송” 쪽이어서, 소스의 하드 링크 구조를 그대로 옮기고 싶다면 옵션을 명시해야 합니다(버전별: -H 하드 링크 보존, 증분 시 --link-dest 등). 같은 FS 내 링크-온리 백업은 inode·블록을 아끼는 대신, 복구·감사 절차를 팀 루틴에 적어 두어야 “어느 백업 스냅이 실제 몇 inode를 가리키는가”를 추적할 수 있습니다.
20.2 CI·빌드·패키지 캐시
프런트엔드 의존성·도커 빌드 캐시·대형 tar 추출은 짧은 시간에 inode를 대량 소비합니다. 전용 볼륨·할당 정책 없이 루트 파티션에 두면, 서비스 전혀 무관한 빌드만으로 inode full이 날 수 있습니다. 캐시 GC, XDG 경로 분리, noexec/nodev 마운트는 보안뿐 아니라 범위 제한에도 도움이 될 수 있습니다(조직 정책에 따름).
20.3 Too many open files vs inode
EMFILE/ENFILE류는 “열린 fd 개수” 제한(프로세스/시스템)이 전형 원인이고, inode와는 다른 축입니다. df -i가 충분해도 데몬이 select 루프에 누수하면 같은 증상이 납니다. 반대로 inode 0%이면 생성 자체가 막힐 수 있으므로, 로그·알람에 df -h와 df -i를 쌍으로 넣는 것이 좋습니다.
20.4 경로에서 inode로(개념도)
VFS는 “경로 한 번”을 dentry 체인으로 풀고, 마지막에 inode를 적재합니다. NFS·FUSE·Overlay에서는 캐시·재검증이 추가되어, “로컬 ext4에서만 쓰던 직관”이 그대로 맞지 않을 수 있습니다.
flowchart LR path[사용자 경로] --> dent[dentry / 이름 해석] dent --> ino[inode 캐시] ino --> meta[모드·UID·rdev·nlink] ino --> data[익스텐트/포인터]
20.5 정리(운영)
프로덕션에서 inode는 “숨은 슬롯”이자 메타 I/O의 단위입니다. 알람·용량 기획·백업 RPO를 잡을 때, 사용률(%)만이 아니라 초당 생성·삭제 같은 이벤트율도 같이 보면, #09로 넘기기 전에 워크로드를 한 번 나눌 수 있습니다.
21. 마무리
여기까지 inode·이름·링크·권한·삭제 쪽을 VFS랑 ext4/XFS 온디스크(익스텐트·포크·B+트리)로 잡아당겨봤다. 표로 끝판왕 문제 해결 테이블을 깔고 싶었으면, 옛날엔 21절이 있었는데(…) 이번엔 뺐다. 뭐 No space인데 df -h만 보면 inode 트러블슈팅 길 따라가라, 정도? chmod 맞췄는데 ls에 + 뜨고 꼬이면 ACL 의심, ls -Z는 SELinux, root도 Permission denied면 +i 같은 파일 플래그 훑어보기 — 완벽한 체크리스트는 남기지 않았다. (그거까지 쓰면 백과사전이 되잖아.)
저널·복구·할당·스케줄러는 #09 Linux 디스크·블록 계층로 보내고, inode full vs 디스크 full 실전은 트러블슈팅 글이 읽기 쉬울 거다. 메모리 풀 감 잡는 건 C++ 메모리 풀도. 검색 키워드: Linux, ext4, XFS, inode, 익스텐트, 파일시스템.