Linux Filesystem


파일은 한 덩어리로 한 곳에 있는 게 아니다. 세 부분이 분리돼 서로 연결된 구조다.

  • 이름 = 디렉터리에 저장
  • 메타데이터 = inode 에 저장
  • 실제 데이터 = 디스크 블록에 저장

경로(Path)의 실체

$ /bin/zsh --version
zsh 5.9 (arm64-apple-darwin25.0)
 
$ /bin/../usr/../bin/./zsh --version
zsh 5.9 (arm64-apple-darwin25.0)
  • 파일 경로는 고정된 주소가 아니다. 루트(/)에서 시작해 디렉터리 테이블을 한 단계씩 따라가는 길 안내(route)다.
  • . 과 .. 도 각 디렉터리 테이블에 실제로 들어 있는 항목이다(아래 ls -ali 참고). 그래서 /bin/.. 은 / 로, /usr/.. 도 / 로 돌아가고, 결국 두 경로는 같은 파일에 도착한다.

디렉터리와 테이블

$ ls -ali
total 12
1048577 drwxrwxr-x 2 meatsby meatsby 4096 Oct  3 20:24 .
 262145 drwxr-x--- 7 meatsby meatsby 4096 Oct  3 20:23 ..
1048578 -rw-rw-r-- 1 meatsby meatsby   13 Oct  3 20:26 notes.txt
1048579 -rw-rw-r-- 1 meatsby meatsby    0 Oct  3 20:24 photo.png
  • 디렉터리 = 파일을 담는 상자가 아니라, 파일 이름과 inode 번호를 짝지은 테이블을 내용으로 가진 파일이다.
  • ls -i = 각 이름이 가리키는 inode 번호(맨 앞 컬럼)를 보여준다.
  • . = 이 디렉터리 자신의 inode(1048577), .. = 부모 디렉터리의 inode(262145).

아이노드(inode)의 역할

$ stat notes.txt
  File: notes.txt
  Size: 13              Blocks: 8          IO Block: 4096   regular file
Device: fd01h/64769d    Inode: 1048578     Links: 1
Access: (0664/-rw-rw-r--)  Uid: (  501/ meatsby)   Gid: ( 1000/ meatsby)
Access: 2026-10-03 20:23:57.520195097 +0800
Modify: 2026-10-03 20:26:22.027794491 +0800
Change: 2026-10-03 20:26:22.027794491 +0800
 Birth: 2026-10-03 20:23:57.520195097 +0800
  • inode = 파일의 메타데이터를 담는 구조다. 파일 유형, 크기, 소유자, 권한, 시간, 실제 데이터 블록의 위치가 들어 있다.
  • 파일 이름은 inode 에 없다. 이름은 디렉터리 테이블에만 있다.
  • stat = 파일이 가리키는 inode 의 정보를 보여준다. Links = 이 inode 를 가리키는 이름의 개수.

하드 링크

$ echo "hi" > a
$ ln a b
$ ls -li
total 8
1048581 -rw-rw-r-- 2 meatsby meatsby 3 Oct  3 20:37 a
1048581 -rw-rw-r-- 2 meatsby meatsby 3 Oct  3 20:37 b
  • 하드 링크 = 같은 inode 를 가리키는 이름을 하나 더 만드는 것이다. a 와 b 는 inode 번호가 같다.
  • 원본과 사본의 구분이 없다. 둘 다 같은 자격의 이름이다.
  • a 를 지워도 b 가 같은 inode 를 가리키므로 hi 데이터는 남는다.
  • ls -l 의 2번째 컬럼(2) = 링크 수. 링크 수가 0이 되어야 데이터가 실제로 해제된다.

심볼릭 링크

# 심링크 생성
$ ln -s /bin/bash z
$ ls -l z
lrwxrwxrwx 1 meatsby meatsby 9 Oct  3 20:47 z -> /bin/bash
 
# macOS 의 /tmp 도 심링크다
$ ls -ld /tmp
lrwxr-xr-x@ 1 root  wheel  11 Aug 13 10:51 /tmp -> private/tmp
 
$ cd /tmp
$ pwd
/tmp
$ pwd -P            # 심링크를 풀어낸 실제 경로
/private/tmp
  • 심볼릭 링크(심링크) = 대상의 경로 문자열을 내용으로 가진 별도의 파일이다. 자기만의 inode 를 따로 가진다.
  • 파일 크기가 곧 경로 문자열의 길이다. /bin/bash 는 9바이트, private/tmp 는 11바이트.
  • 경로만 들고 있으므로 대상이 지워지거나 옮겨지면 링크가 깨진다(dangling). 하드 링크와 반대다.
  • pwd = 셸이 기억하는 논리 경로(심링크 이름 그대로), pwd -P = 심링크를 푼 물리 경로.

작업 디렉터리

$ type cd
cd is a shell builtin
  • 현재 작업 디렉터리(pwd) = 커널이 프로세스마다 따로 관리하는 상태다.
  • 프로세스의 작업 디렉터리는 그 프로세스 자신만 바꿀 수 있다.
  • 그래서 cd 는 외부 프로그램이 아니라 셸 빌트인이어야 한다.
    • 셸에서 외부 프로그램을 실행하면 자식 프로세스가 만들어진다. 자식은 부모의 환경을 물려받은 독립된 프로세스다.
    • cd 가 외부 프로그램이면 자식 프로세스의 디렉터리만 바뀌고, 자식이 끝나면 그 변경도 같이 사라진다. 셸은 그대로 원래 자리에 있다.
    • 셸 프로세스 안에서 직접 실행해야 셸 자신의 상태가 바뀌고, 이후 명령에도 반영된다.
  • 같은 이유로 설정 파일은 ./file 이 아니라 source 로 읽는다(01. Bash 기초의 source vs 실행 참고).

Swap 설정


Swap 이란?

Swap은 물리 메모리(RAM)가 부족할 때 디스크 공간을 가상 메모리로 사용하는 기술이다. 메모리 부족 시 사용 빈도가 낮은 데이터를 디스크로 이동시켜 메모리 공간을 확보한다.

사용 사례

  • 01. Amazon EC2 t3.micro 와 같은 free-tier 인스턴스를 사용할 때 OOM Kill process 가 자주 발생하는 경우
  • 물리 메모리가 제한적인 환경에서 시스템 안정성을 높이고자 할 때

Swap 파일 크기 계산

Swap Partition 크기 계산은 AWS 공식 문서를 참고

메모리 확인

free -m

Swap 파일 생성

# dd 명령을 통해 root file system 에 swap file 을 생성
# bs(블록 크기) * count(블록 수) = swap file 의 크기
# bs(블록 크기)는 인스턴스에서 사용 가능한 메모리보다 작아야 함
sudo dd if=/dev/zero of=/swapfile bs=128M count=32

Swap 파일 권한 설정

# swap file 의 rw 권한 업데이트
sudo chmod 600 /swapfile

Swap 영역 설정

# linux swap 영역 설정
sudo mkswap /swapfile

Swap 활성화

# swap 공간에 swap file 을 추가해 즉시 사용할 수 있도록 함
sudo swapon /swapfile
 
# 절차 성공 확인
sudo swapon -s

부팅 시 자동 활성화

# swap file 을 활성화할 수 있게 설정
sudo vi /etc/fstab
 
# 파일 끝에 아래 줄을 추가하고 저장
/swapfile swap swap defaults 0 0

설정 확인

# 메모리 재확인 시 swap memory 가 allocate 된 것을 확인 가능
free -m

References