파일 · 권한 · 사용자 관리 13 / 50 · Part 2. Linux 파일 종류와 속성
실습 환경: Rocky Linux 9.8 · Ubuntu 24.04.5 (Docker 격리 컨테이너, 테스트 계정analyst)
기초편 연계: 「리눅스 시스템 기초」 14. inode와 파일 시스템
01편과 02편에서 inode를 "파일의 메타데이터를 담은 구조체"라고 소개했다. 이번 글에서는 inode를 직접 열어 본다. debugfs로 ext4 inode의 실제 필드를 확인하고, inode가 가진 정보와 가지지 않은 정보를 구분한다.
그리고 운영과 관제 모두에 영향을 주는 inode 고갈 을 재현한다. 디스크 용량은 1%만 썼는데 파일을 더 만들 수 없는 상황이다.
「리눅스 시스템 기초 14편」이 inode·링크·타임스탬프를 한 번에 개괄했다면, 이 시리즈는 inode(13편), 링크(14편), 타임스탬프(15편), stat(16편)으로 나누어 각각 깊게 다룬다.
| 필드 | 설명 | 확인 |
|---|---|---|
| inode 번호 | 파일 시스템 안에서의 고유 번호 | ls -i, stat %i |
| 종류 + 권한 (mode) | 파일 종류, 특수 권한, rwx | stat %f, %A |
| UID / GID | 소유자·그룹 번호 | stat %u %g |
| 크기 | 바이트 단위 | stat %s |
| 링크 수 | 이 inode를 가리키는 이름의 수 | stat %h |
| 타임스탬프 | atime, mtime, ctime, crtime(birth) | stat |
| 블록 위치 | 데이터가 저장된 블록 (ext4는 extent 방식) | debugfs stat |
| 확장 속성 참조 | ACL, SELinux 컨텍스트 등 | getfattr |
inode 번호는 파일 시스템 단위로만 고유 하다. 서로 다른 파일 시스템에는 같은 번호가 존재할 수 있다. 그래서 파일을 정확히 식별하려면 장치 번호 + inode 번호 쌍이 필요하다 (stat의 Device + Inode).

ext4는 mkfs 시점에 inode 테이블의 크기(= 최대 파일 수)를 고정 한다. 기본값은 용량 대비 비율(bytes-per-inode)로 정해지며, 나중에 늘릴 수 없다. xfs는 필요할 때 inode를 동적으로 할당하므로 ext4보다 고갈 가능성이 낮지만, 전체 용량 중 inode에 쓸 수 있는 비율 상한(imaxpct)은 있다.
| 번호 | 용도 |
|---|---|
| 2 | 루트 디렉터리 (/) |
| 11 | 첫 번째 일반 inode (보통 lost+found) |
이번 실습에서는 /data의 lost+found를 미리 지웠기 때문에 첫 파일 a.txt가 inode 11을 받았다.
빈 파일도 inode를 하나 쓴다. 세션 파일, 캐시 조각, 메일 큐처럼 작은 파일이 대량으로 생기는 서비스 에서는 데이터 블록보다 inode가 먼저 소진된다. 이때 커널은 ENOSPC(No space left on device)를 반환한다. 메시지만 보면 용량 부족과 구분되지 않는다.
inode 고갈 실습을 위해 root가 inode 32개짜리 8MB ext4 볼륨 을 만들어
/mnt/small에 연결했다 (mkfs.ext4 -N 32). 운영 파일 시스템에서 이 실습을 하지 않는다.
# 1) 파일 하나의 inode 정보
cd /data && echo "inode lab" > a.txt && ls -i a.txt
stat -c 'inode=%i links=%h uid=%u mode=%a size=%s blocks=%b' a.txt
df -i /data
# 2) inode 고갈 재현
df -h /mnt/small && df -i /mnt/small
cd /mnt/small/lab && for i in $(seq 1 40); do touch f$i 2>/dev/null || { echo "touch f$i 실패"; break; }; done
touch one-more.txt
df -h /mnt/small && df -i /mnt/small
# 3) (root) debugfs 로 inode 직접 보기 — 읽기 전용 조회
sync
debugfs -R 'stat /a.txt' /root/lab-ext4.img 2>/dev/null | head -14
debugfs -R 'ls -l /' /root/lab-ext4.img 2>/dev/null
debugfs는 기본적으로 읽기 전용 으로 열린다. -w 옵션을 주면 inode를 직접 수정할 수 있어 파일 시스템을 손상시킬 수 있으므로 실습에서도 사용하지 않는다.


텍스트 원본(실제 출력):
[analyst@rocky9-lab ~]$ cd /data && echo "inode lab" > a.txt && ls -i a.txt
11 a.txt
[analyst@rocky9-lab data]$ stat -c 'inode=%i links=%h uid=%u mode=%a size=%s blocks=%b' a.txt
inode=11 links=1 uid=1000 mode=644 size=10 blocks=8
[analyst@rocky9-lab data]$ df -i /data
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/loop0 65536 11 65525 1% /data
[analyst@rocky9-lab data]$ df -h /mnt/small && df -i /mnt/small
Filesystem Size Used Avail Use% Mounted on
/dev/loop1 7.0M 15K 6.4M 1% /mnt/small
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/loop1 32 12 20 38% /mnt/small
[analyst@rocky9-lab data]$ cd /mnt/small/lab && for i in $(seq 1 40); do touch f$i 2>/dev/null || { echo "touch f$i 실패"; break; }; done
touch f21 실패
[analyst@rocky9-lab lab]$ touch one-more.txt
touch: cannot touch 'one-more.txt': No space left on device
[analyst@rocky9-lab lab]$ df -h /mnt/small && df -i /mnt/small
Filesystem Size Used Avail Use% Mounted on
/dev/loop1 7.0M 15K 6.4M 1% /mnt/small
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/loop1 32 32 0 100% /mnt/small
[root@rocky9-lab ~]# sync
[root@rocky9-lab ~]# debugfs -R 'stat /a.txt' /root/lab-ext4.img 2>/dev/null | head -14
Inode: 11 Type: regular Mode: 0644 Flags: 0x80000
Generation: 683426729 Version: 0x00000000:00000001
User: 1000 Group: 1000 Project: 0 Size: 10
File ACL: 0
Links: 1 Blockcount: 8
Fragment: Address: 0 Number: 0 Size: 0
ctime: 0x6ab47e53:15dc9d98 -- Thu Sep 24 10:35:15 2026
atime: 0x6ab47e53:15dc9d98 -- Thu Sep 24 10:35:15 2026
mtime: 0x6ab47e53:15dc9d98 -- Thu Sep 24 10:35:15 2026
crtime: 0x6ab47e53:15dc9d98 -- Thu Sep 24 10:35:15 2026
Size of extra inode fields: 32
Inode checksum: 0xb77d1f32
EXTENTS:
(0):4139
[root@rocky9-lab ~]# debugfs -R 'ls -l /' /root/lab-ext4.img 2>/dev/null
2 40755 (2) 1000 1000 4096 24-Sep-2026 10:35 .
2 40755 (2) 1000 1000 4096 24-Sep-2026 10:35 ..
11 100644 (1) 1000 1000 10 24-Sep-2026 10:35 a.txt
| 출력 | 해석 |
|---|---|
inode=11 links=1 uid=1000 mode=644 size=10 blocks=8 | inode가 가진 핵심 필드. uid는 숫자 |
df -i /data → 65536 | 256MB ext4 볼륨의 inode 총량 (기본 비율 적용) |
/mnt/small Inodes 32 IUsed 12 | 32개 중 12개는 루트·예약 inode·lab 디렉터리가 사용 |
touch f21 실패 | f1~f20의 20개로 남은 inode 20개를 모두 소진 |
No space left on device | 용량 부족과 같은 메시지 |
이후 df -h → 1% / df -i → 100% | 용량은 충분하지만 inode가 없다 |
debugfs Inode: 11 Type: regular Mode: 0644 | inode 11의 종류·권한 |
User: 1000 Group: 1000 | 이름이 아닌 번호로 저장됨 |
ctime: 0x6ab47e53:15dc9d98 | 앞은 Unix 초(16진), 뒤는 나노초 관련 확장 필드 |
crtime | 생성 시각(birth). stat의 Birth 값의 출처 |
EXTENTS: (0):4139 | 파일의 0번째 논리 블록이 디스크 블록 4139에 있음 |
debugfs ls -l / → 11 100644 ... a.txt | 이름 a.txt는 루트 디렉터리(inode 2)의 엔트리 에 있다. 100644 = 일반 파일(100) + 권한 644 |
sync를 먼저 실행한 이유도 중요하다. 마운트 중인 파일 시스템의 변경 내용은 메모리에 먼저 쌓이므로, 디스크 이미지를 직접 읽는 도구는 아직 기록되지 않은 변경을 보지 못할 수 있다. 이 점은 라이브 시스템 포렌식에서도 동일하게 적용된다.
| 주제 | 내용 |
|---|---|
| 서비스 거부 | 일반 사용자라도 쓰기 가능한 공용 경로(/tmp)에 대량의 빈 파일을 만들면 같은 파일 시스템의 inode를 소진시킬 수 있다. /tmp를 별도 파티션이나 tmpfs로 분리하는 이유 중 하나다 |
| 로그 공백 | /var의 inode가 고갈되면 새 로그 파일(로테이션)이 생성되지 않아 관제 데이터가 끊긴다 |
| 제한 | 디스크 쿼터는 블록뿐 아니라 inode 수(파일 개수) 도 사용자별로 제한할 수 있다 |
| 증거의 한계 | inode에는 이름·경로·계정명이 없다. "누가 만들었나"는 UID → 당시 계정 매핑으로 추가 확인이 필요하다 |
| debugfs 사용 흔적 | root 권한으로 debugfs -w를 쓰면 ctime까지 바꿀 수 있다. 따라서 타임스탬프는 로그 등 다른 증거와 교차 검증 해야 한다 |
[Detection] 모니터링: /var 파일 시스템 inode 사용률 95% 초과 경보
↓
[확인] df -i /var → IUse% 100
find /var -xdev -type f -newermt '1 hour ago' | cut -d/ -f1-4 | sort | uniq -c | sort -rn | head
↓
[판단] 특정 디렉터리에 1시간 동안 수십만 개 파일 생성 → 장애 또는 악의적 대량 생성
↓
[Evidence] 생성 파일 소유 UID, 생성 프로세스(auditd), 최초 생성 시각(birth)
↓
[Response] 원인 프로세스 중지 → 불필요 파일 정리 → 로그 수집 공백 구간 기록
| 관점 | 내용 |
|---|---|
| SIEM | 용량(df -h)만 수집하는 모니터링은 inode 고갈을 놓친다. inode 사용률 지표 를 함께 수집한다 |
| 공백 관리 | 로그 수집이 끊긴 구간은 보고서에 "관측 불가 구간"으로 명시한다. 로그가 없다는 것이 행위가 없었다는 뜻은 아니다 |
| Evidence | 파일 식별은 장치 + inode로 기록한다. 이름은 바뀔 수 있다 |
| 실수 | 결과 | 예방 |
|---|---|---|
No space left를 보고 용량만 확인 | 원인 파악 지연 | df -h와 df -i를 함께 |
| ext4에서 inode 수를 나중에 늘리려 함 | 불가능 | 작은 파일이 많은 용도는 mkfs 시 -i/-N 조정 또는 xfs 사용 |
마운트 중인 디스크를 debugfs -w로 수정 | 파일 시스템 손상 | 읽기 전용 조회만, 수정은 언마운트 후 |
| inode 번호만으로 파일 식별 | 다른 FS의 같은 번호와 혼동 | 장치 번호와 함께 기록 |
수십만 파일 디렉터리에서 rm * | 인자 길이 초과 오류 | find DIR -type f -delete |
[ ] stat 으로 inode 번호·링크 수·UID·크기를 확인했다
[ ] df -i 로 inode 사용량을 확인했다
[ ] 작은 테스트 볼륨에서 inode 고갈을 재현했다
[ ] 용량은 남았지만 파일 생성이 실패하는 것을 확인했다
[ ] debugfs 로 inode 필드와 extent 를 읽었다
[ ] inode 에 파일 이름이 없다는 것을 debugfs 로 확인했다
No space left on device가 발생한다./var inode 고갈은 로그 생성 실패 → 관제 공백으로 이어진다. inode 사용률도 모니터링한다.debugfs는 읽기 전용으로 조회하고, 타임스탬프는 다른 증거와 교차 검증한다.다음 글 「14. 하드 링크와 심볼릭 링크」 에서는 한 inode에 이름을 여러 개 붙이는 하드 링크와, 경로 문자열을 저장하는 심볼릭 링크를 비교한다. 원본 이름을 바꿨을 때 두 링크가 어떻게 다르게 반응하는지, 그리고 링크가 권한 검사를 우회하지 못한다 는 점을 실제로 확인한다.
-N, -i 옵션 — https://man7.org/linux/man-pages/man8/mke2fs.8.html