7장 : 파일시스템
Last updated
Last updated
6장에서 각종 장치는 디바이스 파일
로 접근 가능하다고 설명했습니다. 하지만 대부분의 저장
장치는 이 장에서 설명하는 파일 시스템
으로 접근 가능합니다.
데이터를 디스크 어떤 위치에 저장할지 직접 정해야 합니다
다른 데이터를 훼손하지 않도록 비어 있는 영역도 관리가 필요
쓰기가 끝나 서 나중에 다시 읽어오려면 어느 위치에 파일 크기가 얼마이고, 어떤 데이터를 배치했는지 기 억해야 함
파일 시스템은 위의 정보를 대신해서 관리
파일 시스템은 사용자에게 의미 있는 데이
터 뭉치를 파일 단위
로 관리
각각의 데이터가 어디에 있는지 사용자가 직접 관리하지 않 아도 저장 장치의 관리 영역에 기록됩니다
파일 시스템은 운영체제가 저장매체에 파일을 쓰기 위한 자료구조 또는 알고리즘입니다.
파일 형식으로 데이터를 관리하는 저장 장치
의 영역(관리 영
역 포함)과 해당 저장 영역을 다루는 처리
(그림에서 '파일 시스템 코드) 양쪽을 모두 합쳐서 파
일 시스템이라고 부릅니다.
흐름
프로세스 → 디바이스 파일 → 디바이스 드라이버 → 저장 장치
프로세스 → 파일 시스템에 있는 파일 → 파일 시스템 코드 → 디바이스 드라이버 → 저장 장치
목적
저장 장치 특정 주소(예: 70GiB~80GiB)로 바로 접근
파일 이름(ex. /home/test.txt
)을 통해 접근
특징
- 파일 시스템 없이 직접 저장장치 영역을 다룸- 파일 손상 위험 있음
- 파일 시스템이 중간에 있으므로 사용 편리- 안정성과 데이터 보호 기능을 제공
프로세스가 직접 디바이스 파일(ex. /dev/sda
)에 접근합니다.
"70GiB~80GiB 영역을 읽어주세요!" 같은 식으로 "주소 기반" 요청을 보냅니다.
디바이스 드라이버가 이 요청을 받아서 장치에 직접 명령을 내립니다.
저장 장치에서 데이터가 읽힙니다.
➡️ 파일 시스템을 거치지 않기 때문에, 사용자가 잘못 접근하면 파일 시스템 구조를 깨버릴 수 있음.
프로세스가 파일 이름(예: /home/test.txt
)을 열려고 합니다.
커널의 파일 시스템 코드가 동작합니다. ("이 파일은 저장 장치의 어느 주소에 있을까?")
파일 시스템이 주소(70GiB~80GiB)로 매핑해서 디바이스 드라이버에 전달합니다.
디바이스 드라이버가 실제 장치에서 데이터를 읽어옵니다.
➡️ 파일 이름만 알면 복잡한 저장소 구조를 몰라도 되고, 데이터 안전성도 높습니다.
접근 방식
장치 주소 기반
파일 이름 기반
중간 매개체
없음 (파일 시스템 무시)
파일 시스템이 매개
위험성
높음 (파일 깨짐 가능)
낮음 (파일 시스템이 관리)
사용 예시
복구 작업, 저수준 디스크 조작
일반 파일 읽기/쓰기 작업
디바이스 파일 접근: "창고에 들어가서 직접 원하는 박스를 꺼내오는 것"
파일 시스템 접근: "창고 관리자에게 '책상 위 서랍 속 파란 파일' 요청하는 것"
리눅스 파일 시스템은 각 파일을 디렉터리
라고 하는 특수한 파일을 사용해서 분류할 수
있습니다.
디렉터리가 다르면 동일한 파일명을 사용할 수 있습니다.
또한 디렉터리 안에 또 다 시 디렉터리를 만들어서 트리 구조를 만들 수 있습니다.
리눅스 파일 시스템은 계층적 구조를 사용하여 트리 모양으로 이루어져 있습니다.
루트 디렉토리(/)를 최상위 디렉토리로 시작하여 그 아래에 다양한 디렉토리와 파일들이 존재합니다.
파일 시스템 안에는 두 가지 종류의 데이터가 존재합니다.
사용자가 직접 작성하거나 저장한 문서, 이미지, 동영상, 프로그램 파일 같은 실제 정보입니다.
우리가 직접 보고 사용하는 '콘텐츠'에 해당합니다.
파일을 효율적으로 관리하기 위해 파일 시스템 내부에 저장된 부가적인 정보입니다.
사용자에게는 보이지 않는, '파일을 설명하고 관리하는 정보'라고 생각하면 됩니다.
파일 이름
파일을 식별할 수 있는 이름
저장 위치 및 크기
저장 장치 내에서 파일이 저장된 실제 위치와 크기
파일 종류
일반 파일, 디렉터리, 디바이스 파일 등 어떤 종류인지
파일 시간 정보
파일 생성, 최종 수정, 최종 접근 날짜와 시간
파일 권한 정보
누가 파일을 읽고, 쓰고, 실행할 수 있는지에 대한 권한 설정
디렉터리 데이터
디렉터리 내부에 포함된 파일 목록과 그 구조
데이터는 우리가 쓰는 내용, 메타 데이터는 파일 시스템이 파일을 관리하기 위한 비서 노트!
1. 빠른 파일 탐색을 가능하게 한다
파일 시스템은 "메타 데이터"를 통해 파일 이름 → 저장 위치를 빠르게 찾아낼 수 있어요.
만약 메타 데이터가 없다면, 파일을 찾으려고 디스크 전체를 뒤져야 하는 대참사가 벌어집니다.
비유하자면,
메타 데이터가 있는 경우 = "도서관 사서가 책 번호를 알려줘서 바로 찾음"
메타 데이터가 없는 경우 = "도서관 책장을 하나하나 다 뒤져야 함"
메타 데이터 안에는 파일 소유자, 읽기/쓰기/실행 권한 정보가 들어 있습니다.
이 덕분에 파일마다 "누가 접근할 수 있는지"를 구체적으로 설정할 수 있어요.
예를 들면, 회사 서버의 중요 문서 파일이 아무나 읽지 못하도록 막는 것도 모두 메타 데이터의 '권한 설정' 덕분입니다.
디스크에 문제가 생겼을 때, 복구 프로그램은 메타 데이터를 읽어서 파일 구조를 복구해요.
메타 데이터가 손상되면 파일은 살아 있어도 무용지물이 될 수 있습니다.
파일 탐색
빠른 위치 찾기
파일 보호
접근 권한 설정
파일 복구
복구 시 필수 정보 제공
메타 데이터는 파일 시스템의 뇌이자, 보안관이자, 구조대장이다!
파일 시스템은 메타 데이터를 저장할 때 두 가지 중요한 구조를 사용합니다:
아이노드(i-node)는 리눅스 파일 시스템에서 사용되는 데이터 구조
파일의 진짜 몸통을 담당하는 데이터 구조입니다.
하나의 파일이나 디렉터리마다 하나의 inode가 존재해요.
간단히 말하면, 파일에 대한 중요한 정보를 담고 있는 "주민등록증" 같은 역할을 합니다.
이 아이노드는 파일이 실제로 어디에 저장되어 있는지, 파일의 크기, 수정 시간 등 파일에 관한 다양한 정보를 관리합니다.
inode에는 어떤 정보가 들어 있을까요?
파일 소유권과 접근 권한
파일을 누가 소유하고 있는지, 어떤 권한(읽기/쓰기/실행)을 가지고 있는지
파일 내용이 저장된 물리적 주소
파일의 데이터가 실제로 저장된 저장 장치의 위치 정보
파일의 링크 수
해당 파일을 참조하고 있는 링크(하드 링크)의 개수
파일의 크기
파일이 차지하는 전체 용량
파일 생성 시간
파일이 처음 만들어진 시각
최근 사용 시간
파일이 마지막으로 읽히거나 접근된 시각
최근 수정 시간
파일의 내용이 마지막으로 수정된 시각
아이노드의 최근 수정 시간
파일 내용이 아닌 아이노드(메타데이터) 자체가 수정된 시각
🧩 inode는 파일 내용을 직접 저장하지 않고, "내용은 어디에 저장되어 있다"는 주소만 관리해요.
이 정보들은 파일 시스템에서 파일이 어떻게 저장되고 관리되는지에 대한 중요한 정보를 제공합니다!
각 파일이나 디렉토리는 고유한 아이노드 번호를 가지며, 이 번호를 통해 파일 시스템은 파일의 메타데이터를 찾습니다.
파일 이름: 사용자가 파일을 식별할 때 사용하는 이름으로, 디렉토리 구조에서 파일 이름이 저장된다. 이 파일 이름은 아이노드 번호를 참조하여 파일의 실질적인 위치를 찾는다.
아이노드: 파일의 메타데이터(파일 크기, 권한, 생성 시간 등)를 포함하며, 파일 내용이 저장된 데이터 블록의 위치를 가리키는 정보가 담겨 있다. 즉, 파일 이름은 아이노드를 가리키고, 아이노드는 파일 내용을 가리킨다.
파일 내용: 실제 파일의 데이터가 저장된 블록으로, 아이노드의 정보를 통해 접근된다.
이를 통해 리눅스 파일 시스템은 파일 이름을 통해 간접적으로 파일 내용에 접근하게 된다.
아이노드를 사용하면 하드 링크와 소프트 링크 같은 다양한 파일 참조 방식이 가능해진다.
아이노드의 예제
내 컴퓨터에서 엄청 큰 파일이 있다 가정해봅시다.
컴퓨터의 용량이 부족해서, 이 파일을 휴지통에 버렸을 때 내 드라이브의 용량이 줄지 않은 것을 확인 해 본 적이 있을 것입니다.
휴지통에서 완전히 비우기
를 했을 때, 비로소 그 파일 만큼의 용량이 확보되는것을 확인해 볼 수 있다.
이처럼 파일을 휴지통에만 버린 것이 특정 파일의 inode를 삭제한 것입니다. (위치값만 삭제한 것)
즉, inode는 위치값만 전달하는 노드이며 그렇기 때문에 DNS Server와 비슷한 역할을 한다 말한 것입니다.
디렉터리는 일종의 파일 목록표입니다.
"파일 이름"과 "inode 번호"를 짝지어서 기록해둡니다.
구성 예시
hello.txt
1024
picture.png
1025
my_folder
1026
📂 즉, 디렉터리는 "파일 이름 → inode 번호"를 알려주는 지도 역할을 해요.
디렉터리가 이름을 알려주고,
inode가 진짜 몸통(속성 + 위치)을 관리하는 방식!
디렉터리
백화점 안내판 (매장 이름 + 매장 번호)
inode
각 매장의 실제 위치와 정보
inode와 디렉터리 엔트리는 파일 시스템의 두 날개! 하나라도 없으면 파일을 찾을 수도, 관리할 수도 없다!
아이노드는 64바이트 크기의 표로, 파일에 대한 모든 정보를 담고 있습니다.
그리고 이 아이노드들은 아이노드 블록에 저장되며, 전체 디스크의 약 1% 정도를 차지합니다.
파일이나 디렉토리가 생성되면, 해당 파일을 관리할 아이노드가 만들어지고, 이 아이노드는 아이노드 테이블에 등록
되어 관리됩니다.
아이노드(inode): 파일이나 디렉토리의 중요한 정보를 담고 있는 64바이트 크기의 데이터 구조입니다.
아이노드 테이블(inode table): 시스템 내의 모든 파일과 디렉토리의 아이노드를 관리하는 표입니다.
아이노드 번호(inumber): 아이노드가 아이노드 테이블에서 고유하게 등록된 번호입니다.
아이노드 테이블은 파일 시스템에서 파일이나 디렉토리들이 어디에 저장되고 있는지 추적하는 역할을 합니다.
파일이나 디렉토리가 생성되면, 아이노드 번호는 i-list라는 표에 등록되고, 이 번호를 통해 해당 파일에 대한 정보를 빠르게 찾을 수 있습니다.
inode에는 파일이 저장된 "진짜 데이터"의 위치를 기록합니다. 그런데 큰 파일을 저장하려면 단순히 주소 하나만으로는 부족해요. 그래서 inode는 다단계 포인터 구조를 사용합니다!
inode 안에 바로 기록된 포인터입니다.
직접적으로 "이 블록에 데이터가 있어요"를 가리킵니다.
예를 들어,
Direct Pointer 1 → 블록 123번
이러면 바로 123번 블록에서 파일 조각을 읽어옵니다.
보통 12개 정도의 직접 포인터가 있어요.
파일이 커져서 직접 포인터만으로는 부족할 때 사용하는 방식입니다.
1단계 간접 포인터 (Single Indirect)
inode 안의 포인터가 "또 다른 블록"을 가리키고,
그 블록 안에 진짜 데이터 블록 번호 목록이 있어요!
inode → 인덱스 블록 → 데이터 블록
(= 주소를 한 번 더 거쳐야 합니다.)
2단계 간접 포인터 (Double Indirect)
inode가 "인덱스 블록"을 가리키고,
그 인덱스 블록이 또 "다른 인덱스 블록"을 가리키고,
그 다음에야 데이터 블록을 가리킵니다.
inode → 인덱스 블록 → 인덱스 블록 → 데이터 블록
3단계 간접 포인터 (Triple Indirect)
이건 진짜 크~게 큰 파일을 저장할 때.
인덱스 블록 → 인덱스 블록 → 인덱스 블록 → 데이터 블록
📂 📂 📂 📄 (주소책을 세 번 열어야 데이터에 도착!)
직접 포인터
"내 주머니에 바로 들어있는 열쇠"
1단계 간접 포인터
"내 친구가 가진 창고 열쇠"
2단계 간접 포인터
"친구의 친구가 가진 창고 열쇠"
3단계 간접 포인터
"친구의 친구의 친구가 가진 창고 열쇠"
"파일이 커지면 커질수록 점점 더 복잡한 열쇠놀이를 하게 되는 구조입니다."
개념
원본 파일과 동일한 데이터를 가리키는 또 다른 이름.
원본 파일과 같은 아이노드 번호를 가짐.
사실상 "같은 파일" 이 두 군데 있는 것처럼 보이는 것.
왜 배워야 할까?
파일 중복 없이 여러 위치에서 하나의 파일을 관리 가능.
디스크 공간 절약.
백업 시스템, 중복 파일 관리 등에 유용.
비유: "이름을 하나 더 붙이는 것"
한 사람에게 '홍길동', '길동이' 두 이름을 붙여 부르는 것과 같음.
누가 이름을 부르든, 같은 사람(파일)을 가리킴.
특징
아이노드 번호
원본과 동일
수정 시
모든 링크에 반영됨
원본 삭제 시
다른 하드링크가 남아 있으면 파일 유지
파일 내용
동일한 실제 데이터 참조
개념
원본 파일의 위치(경로) 를 가리키는 별도의 파일.
원본 파일의 주소를 적어 놓은 종이와 같음.
왜 배워야 할까?
자주 바뀌는 파일 경로 관리.
여러 버전의 프로그램, 설정 파일을 쉽게 연결.
시스템 전체를 관리할 때 유연성을 제공.
비유: "주소를 적어놓은 종이"
친구 집 주소를 적어놓은 종이를 들고 가는 것.
집이 이사 가면, 종이는 무용지물이 됨.
특징
아이노드 번호
원본과 다름
수정 시
소프트링크 자체를 수정할 뿐, 원본은 영향 없음
원본 삭제 시
소프트링크가 깨짐(Dead Link)
파일 내용
원본 파일 경로만 보관
아이노드 번호
원본과 동일
원본과 다름
수정 사항
동기화됨
별도 (동기화 X)
원본 삭제 시
문제 없음
링크 깨짐
파일 내용
동일한 데이터
원본 경로만 기억
하드링크는 "같은 사람에 여러 이름을 붙이는 것", 소프트링크는 "집 주소를 종이에 적어 놓은 것"입니다.
어째서 소프트링크는 원본과 다른 아이노드 번호를 가지고 있는데 원본을 삭제하면 문제가 생기는 걸까요?
소프트링크(심볼릭 링크)는 파일 자체를 가리키는 게 아니라, "원본 파일의 경로(주소)"만 저장하기 때문입니다. 즉, 소프트링크는 "파일의 내용"이 아니라 "파일 위치"를 기억하는 종이쪽지 같은 거예요.
소프트링크는 원본 파일의 아이노드 번호를 저장하지 않습니다.
대신 "이 경로로 가보세요!" 라고 파일 경로 문자열만 들고 있어요.
그래서 원본 파일이 삭제되면? 👉 소프트링크는 가리키던 경로를 따라가지만, "더 이상 존재하지 않는 경로" 라서 깨져버리는 겁니다.
하드링크: "같은 집의 두 개 현관문" → 한쪽 문이 막혀도 다른 문으로 들어갈 수 있어요. (아이노드가 같음)
소프트링크: "집 주소를 써놓은 쪽지" → 집이 사라지면? 쪽지를 따라가도 없음. (아이노드가 다름)
아이노드
원본과 동일
원본과 다름
가리키는 것
파일 데이터(내용)
파일 경로(주소)
원본 삭제 시
다른 링크로 여전히 접근 가능
경로를 따라가도 파일이 없어서 깨짐
하드링크는 같은 파일 시스템(같은 디스크 안)에서만 사용할 수 있어요.
서로 다른 디스크(예: C드라이브, D드라이브)에는 하드링크를 만들 수 없습니다.
소프트링크는 파일 시스템이 달라도 만들 수 있어요!
즉, 다른 디스크, 다른 파티션이라도 "경로"만 알고 있으면 연결이 됩니다.
그래서 소프트링크는 다른 디렉토리나 다른 디스크에 파일을 연결해야 할 때 아주 유리합니다.
아이노드 번호
원본과 같음
원본과 다름
저장 내용
파일 데이터 직접 가리킴
파일 경로를 문자열로 저장
원본 파일 삭제 시
다른 링크에서 계속 접근 가능
깨진 링크(경로를 못 찾음) 발생
파일 시스템 제한
같은 파일 시스템 안에서만 가능
다른 파일 시스템, 다른 디스크도 가능
사용 예시
같은 디스크에서 파일 복제처럼 사용할 때
다른 위치에 있는 파일을 연결하거나, 자주 변경될 파일을 참조할 때
우리가 파일을 만들거나 읽거나 삭제할 때, 사실은 POSIX 표준에 따라 제공되는 함수들을 사용합니다.
파일 작성/삭제
creat()
, unlink()
파일 열기/닫기
open()
, close()
파일 읽기/쓰기
read()
, write()
, mmap()
디렉터리 생성/삭제
mkdir()
, rmdir()
디렉터리 열기/닫기/읽기
opendir()
, closedir()
, readdir()
현재 디렉터리 이동
chdir()
사용자는 ext4든 XFS든 Btrfs든 파일 시스템 종류를 신경 쓸 필요 없이 creat(), open() 같은 통일된 함수를 호출합니다!
이게 가능한 이유는 뭘까요?
사용자 태스크들은 open(), read(), write(), close() 등의 시스템 콜을 사용해 파일시스템에 접근합니다.
반대로 파일시스템은 함수를 구현하여 상위계층에 제공해야하는 데 이는 구현하기 나름입니다. 파일시스템 자체는 특정 운영체제에 구애받지 않고, 심지어 운영체제가 없는 상황에서도 동작 가능한 독립적인 구조로 설계
되고 구현되어야 합니다.
그럼에도 불구하고 대부분의 경우 사용자 태스크는 POSIX 표준 시스템 콜을 이용하면 파일시스템에 접근할 수 있을거라 가정하기에 파일시스템은 외부로 함수를 제공할 때 이를 고려해야 합니다.
각각의 파일시스템이 상위로 인터페이스를 제공하지만 사용자 태스크 입장에서 이런 함수들을 직접 호출하여 사용한다는 것은 성가신 일입니다.
예를 들어 하나의 디스크를 여러 파티션으로 나누고 서로 다른 파일시스템(각각 자신만의 고유한 함수를 구현한)이 올려져있다면, 파일을 쓰고, 읽고, 생성하고, 삭제하는 작업에서 파일이 저장된 파일시스템에 맞게 달리 함수를 호출해야 한다는 불편함이 있어요.
실제 파일이 어느 파일시스템에 속해있던 상관없이 단순히 open(), read(), write(), close() 등의 함수만을 통해 접근하면 한결 수월할 것입니다.
따라서 파일시스템과 사용자 태스크 사이에 가상적인(virtual) 층을 하나 도입하여 상위 계층에서 open(), read() 등의 단일한 함수를 통해 파일시스템에 접근하려하면, 인자에 담겨있는 파일 이름을 보고 파일을 관리하고 있는 파일시스템이 무엇인지 판단하도록 합니다.
그리고 해당 파일시스템의 고유한 함수를 호출하는 것입니다. 이러한 접근 방식을 리눅스가 채택한 VFS(Virtual File System)이라 합니다.
우리가 함수를 호출하면 내부적으로 다음과 같은 순서로 흘러갑니다:
VFS 계층: 파일 시스템 종류에 상관없이 공통된 인터페이스를 제공하는 중간 관리자입니다.
디바이스 드라이버: 실제 하드웨어(디스크)를 읽고 쓰는 역할을 합니다.
예를 들어 동일한 디바이스 드라이버로 조작할 수 있는 블록 장치 A, B, C가 있을 때 각각 ext4, XFS, Btrf's 파일 시스템이 존재한다면 [그림 07-05]처럼 됩니다.
사용자 프로그램
creat(), open() 호출
bash, python, etc
시스템 콜
커널로 요청 전달
sys_open()
, sys_read()
등
VFS 계층
ext4, XFS, Btrfs 구분 없이 처리
파일 종류 인식 없이
실제 파일 시스템 처리
ext4용, XFS용, Btrfs용 코드 실행
파일 생성/삭제 등
디바이스 드라이버
물리 장치 I/O 처리
SATA, NVMe 드라이버
저장 장치
데이터가 실제 저장되는 곳
SSD, HDD 등
VFS 덕분에 우리는 파일 시스템 종류를 몰라도
open()
,read()
같은 함수 하나로 모든 파일 시스템을 통합적으로 다룰 수 있다!
이 VFS를 통해 리눅스에서 다양한 파일시스템을 지원하는 것이 가능해졌습니다.
심지어 커널의 내부 상태를 볼 수 있는 proc 파일시스템, 장치를 통합 관리하는 sysfs 등의 가상(pseudo) 파일시스템(memory-based)도 지원해요.
txt 파일이 저장된 디스크의 한 파티션을 관리하고 있는 ext2에 읽기 요청을 하려는 태스크가 있다 가정.
사용자 태스크가 read("a.txt"...) 시스템 콜을 호출.
VFS는 a.txt 파일이 어떤 파일시스템에 속해있는지 판단.
a.txt 정보를 담을 목적으로 여러 가지 정보를 담기에 충분한 구조체 생성.
이 구조체를 인자로 하여 ext2 파일시스템 내부에 구현되어 있는 고유한 읽기 함수 호출.
ext2 자체의 관리 방법을 통해 요청된 파일 내용을 읽음.
읽은 내용을 바탕으로 넘겨받은 구조체에 채워서 리턴
파일의 내용을 가상 주소 공간에 매핑하는 기능입니다.
mmap()
함수를 사용하여 파일을 메모리처럼 직접 읽고 쓸 수 있게 합니다.
파일을 메모리에 읽어올 필요 없이, 메모리 접근만으로 파일 조작이 가능해집니다.
📌 한마디로: "파일 내용을 메모리처럼 다룰 수 있다."
메모리 맵에 저장된 파일은 메모리와 같은 방법으로 접근할 수 있습니다. 데이터를 변경하면 나 중에 저장 장치에 있는 파일에도 정해진 타이밍에 반영(타이밍은 8장)
파일을 open()
으로 엽니다.
mmap()
으로 파일 내용을 가상 주소 공간에 매핑합니다.
매핑된 메모리 영역을 수정하면, 파일 내용도 자동으로 변경됩니다.
수정한 내용은 일정 시점에 저장 장치로 반영(sync) 됩니다. (타이밍은 운영체제가 결정. 강제로 msync()
호출 가능)
프로세스가 메모리를 수정하면, 이게 나중에 파일에 반영됩니다!
파일 준비
Go 프로그램 작성 (filemap.go
)
파일을 open()
mmap()
으로 매핑
매핑된 메모리 수정 ("HELLO"
로 덮어쓰기)
프로세스 메모리 맵 상태 확인
/proc/<pid>/maps
파일 출력
매핑 전후를 비교해서, 매핑된 주소 확인
파일 내용 확인
①에서 mmap() 함수 실행에 성공해서 testfile 파일 데이터 시작 주소가 0xffffa3f69000가 되 었습니다.
2에서는 이 주소로 시작하는 영역이 실제로 메모리 매핑된 걸 알 수 있습니다.
마지 막으로 3에서 실제로 파일 내용이 변경된 걸 확인했습니다.
mmap()으로 매핑한 영역은 메모리 접근하듯이 읽고 쓸 수 있지만, 반드시 파일과 싱크(sync)를 맞춰야 파일에도 실제 반영됩니다.
파일 수정은 메모리에 먼저 이루어지고, 디스크에 쓰기(sync)는 지연될 수 있음.
mmap() 을 사용하면, 파일을 메모리에 직접 매핑해서 고속으로 파일 입출력을 수행할 수 있다! (단, 변경사항은 싱크(sync) 시점에 파일에 기록된다는 점 주의)
ext4
예전부터 사용된 ext2, ext3에서 쉽게 전환 가능. 리눅스 기본 파일 시스템으로 안정적.
XFS
대용량 파일과 확장성에 매우 강함. 고성능 서버나 대형 스토리지에 적합.
Btrfs
스냅샷, 압축, RAID 지원 등 다양한 기능을 기본 탑재. 차세대 파일 시스템으로 주목받음.
리눅스 파일 시스템은 다음 항목에서 서로 차이를 가집니다.
파일 시스템 최대 크기
파일 하나당 최대 크기
최대 파일 개수
파일 이름 최대 길이
파일 접근/수정 속도
추가 기능(스냅샷, 압축 등) 지원 여부
📌 즉, 어떤 파일 시스템을 고르느냐에 따라 '성능', '기능', '제한사항'이 모두 달라진다!
시스템을 다양한 용도로 사용하다 보면 파일 시스템 용량이 한쪽에서 과도하게 사용되어 다른 기능이 멈추거나, 시스템 전체가 불안정해질 수 있습니다.
용도별로 사용 가능한 파일 시스템 용량을 제한하는 기능이 바로 "쿼터"입니다.
쿼터의 목적:
시스템 자원을 과도하게 사용하는 사용자를 제한하여,
디스크 공간 부족 문제를 방지하고,
시스템 전체 안정성을 유지합니다.
리눅스에서는 quota
명령어를 통해 쿼터를 설정하고 관리할 수 있습니다.
"파일 시스템 용량 사용을 사용자/디렉터리/볼륨 단위로 제한하는 기능"
예시: 특정 용도 A에 대해 최대 사용 가능 용량을 설정하면, A는 이 범위까지만 데이터를 저장할 수 있습니다.
리눅스 파일 시스템에서 디스크 공간 또는 파일 개수에 대해 사용량을 제한하는 기능입니다.
시스템 관리자는 특정 사용자 또는 그룹 단위로 디스크 사용량을 제한하고 모니터링할 수 있습니다.
용도 A에게만 일정 부분만 사용하도록 제한합니다.
디스크 용량 쿼터 → 디스크에서 사용할 수 있는 전체 용량을 제한합니다. 예) 사용자 A는 1GB까지만 사용 가능.
파일 개수 쿼터 → 디스크에 생성할 수 있는 파일 수를 제한합니다. 예) 사용자 B는 최대 100개의 파일 생성 가능.
사용자 쿼터
사용자별 용량 제한 (예: /home
디렉터리가 꽉 차는 걸 방지)
ext4, XFS
디렉터리 쿼터 (프로젝트 쿼터)
특정 디렉터리마다 용량 제한 (예: 팀별 공유 디렉터리)
ext4, XFS
서브 볼륨 쿼터
서브 볼륨 단위로 용량 제한 (Btrfs 고유 기능)
Btrfs
업무용 시스템에서는 특정 사용자나 프로그램이 과도한 저장 공간을 사용하지 않도록 쿼터를 설정해 안정적인 시스템 운영을 유지합니다.
/etc/fstab 수정
파일 시스템 마운트 옵션에 쿼터 관련 설정 추가.
재부팅 또는 리마운트
수정한 내용을 적용하기 위해 재부팅하거나 파일 시스템을 다시 마운트합니다.
쿼터 DB 생성
quotacheck
, quotaon
, quotaoff
등의 명령어를 이용하여 쿼터 데이터베이스를 생성합니다.
개인별 쿼터 설정
edquota
명령어를 이용하여 사용자나 그룹별로 개별 쿼터를 설정합니다.
예시: 파일 이동 중 디렉터리 수정 → 중간 단계에서 전원 꺼짐
결과:
파일 시스템 구조가 어중간한 상태로 남아 오류 발생
마운트 실패, 읽기 전용 마운트, 시스템 패닉(크래시) 등
root 아래에 foo, bar라는 2개의 디렉터리가 있고 foo 아래에는 hoge, huga라는 파일이 존재 하는 파일 시스템을 예제로 파일 시스템 오류가 어떤 건지 설명
이런 처리 흐름은 프로세스에서 보자면 중간에 끼어들 수 없는 아토믹 처리
입니다. 첫 번째 쓰
기(foo 파일 데이터 갱신)가 끝나고 두 번째 쓰기(root 데이터 갱신)가 끝나기 전에 전원이 껴
졌다면 [그림 07-10]처럼 파일 시스템이 어중간한 오류 상태가 될지도 모릅니다.
이후에 파일 시스템이 오류를 감지하는데 마운트 작업 중이라면 파일 시스템이 마운트 불가능 하거나, 읽기 전용 모드로 다시 마운트합니다. 또는 시스템 패닉 (윈도의 블루 스 크린에 해당)이 일어납니다.
파일 시스템 안에 저널 영역을 따로 만들어 사용
처리 순서:
먼저, 처리할 작업 목록을 저널에 기록한다.(=저널 로그)
그 다음, 실제 파일 시스템을 변경한다.(=갱신한다)
모두 끝난 후, 저널을 삭제한다.
장점:
중간에 꺼져도 저널만 보면 복구 가능
처리 완료 전에 꺼지면 → 기록 무시
처리 완료 직전에 꺼지면 → 기록 재실행
실제 데이터를 갱신하던 도중(그림 07-11에서)에 강제로 전원이 끊기면 저널 로그를 다시 시작해서 처리를 완료 상태로 만듭니다.(그림 07-13)
사용 예시: ext4, XFS
기존 데이터를 직접 덮어쓰지 않고, 새로운 공간에 변경본 작성
마지막에 링크만 새로운 데이터로 변경
전원 꺼져도 구 데이터가 안전하게 남아 복구 가능
사용 예시: Btrfs
Btrfs에서는 파일 이동 같은 작업을 안전하게 처리하기 위해, 기존 데이터를 직접 수정하지 않고 새롭게 작성 → 링크를 바꿔치기하는 방식(Copy-on-Write)을 사용합니다.
1️⃣ 초기 상태
디렉터리 foo
안에 hoge
, huga
, bar
파일 존재
2️⃣ 새 데이터 생성
hoge
, huga
, bar
를 가리키는 새로운 inode를 작성
3️⃣ 링크 변경
root
에서 foo
디렉터리를 새로운 inode로 가리키도록 변경
4️⃣ 완료 처리
기존 inode를 삭제해서 정리
전원 꺼짐 발생
작업 중 생성된 새로운 inode가 남아 있음
시스템 재시작
새로운 데이터를 삭제하면 원래 상태로 정합성 유지 가능
즉, 중간에 전원이 꺼져도 기존 데이터는 건드리지 않았기 때문에, 복구가 간단하게 됩니다. 🔥
✅ Btrfs는 파일 이동 시 새로운 복사본을 먼저 만든 후 링크만 교체합니다. ✅ 중간에 꺼져도, 새 복사본만 삭제하면 이전 상태로 깨끗하게 복구할 수 있습니다. ✅ 그래서 Btrfs는 파일 시스템 정합성 유지에 매우 강합니다.
ext4나 XFS 등은 일단 저장 장치에 파일 데이터를 썼다면 이후 파일을 갱신할 때는 저 장장치의 동일한 위치에 데이터를 써넣습니다
ext4: fsck.ext4
XFS: xfs_repair
Btrfs: btrfs check
주의사항:
시간이 매우 오래 걸릴 수 있음 (수십 시간~며칠)
원하는 형태로 복구 보장 ❌
잘못된 데이터는 가차없이 삭제됨
따라서 fsck는 최후 수단으로만 사용하고, 평소에는 정기 백업을 하는 것이 가장 좋습니다!
방식
변경 목록을 저널에 기록 후 실제 반영
수정 내용을 새로운 위치에 기록 후 링크 변경
장점
오류 발생 시 복구 가능, 데이터 손상 방지
항상 안전한 데이터 보관, 복구 용이
단점
다소 속도 저하
공간 사용량 증가 가능성
스냅샷 작성 전
이때 파일 시스템의 스냅샷을 만들면 [그림 07-20]처럼 스냅샷의 root는 foo, bar를 향한 링크 를 만들기만 하고 foo, bar 데이터 자체는 복사하지 않습니다.
기존 데이터(foo, bar)를 가리키는 새 root를 만듬 (데이터 복사 없음)
이후 파일(foo 등)을 수정하면, 수정된 데이터만 새 영역에 저장 (Copy-on-Write)
foo 데이터를 다른 새로운 영역에 복사
새로운 영역 데이터를 갱신
마지막으로 root에서 갱신한 영역으로 포인터 교체
스냅샷 작성 후 데이터 갱신
위의 그림에서 본 것처럼 스냅샷은 원본 파일 시스템과 데이터를 공유하므로 공유한 데이터에 문제가 생기면 스냅샷 데이터에도 문제가 생깁니다. 따라서 스냅샷은 백업 목적으로 사용하는 기능이 아닙니다.
백업을 작성하려면 스냅샷을 만든 후에 해당 데이터를 별도로 다른 곳에 복사 해야 합니다
빠른 복사
적은 저장 공간 사용
주의: 스냅샷은 백업이 아님. (원본과 데이터를 공유하기 때문)
스냅샷 생성 → 스냅샷에서 데이터 복사 → 본 시스템의 입출력 영향 최소화
파일 시스템 수준에서 백업을 작성하려면 일반적으로 파일 시스템 입출력을 멈춰야 하는데 스 냅샷을 사용하면 그 시간을 줄일 수 있습니다.
스냅샷을 작성하는 짧은 시 간 동안만 입출력을 멈추고 그후에는 스냅샷을 사용해서 백업을 만든다면 파일 시스템 본체의 입출력을 멈추지 않아도 됩니다
ext4나 XFS는 1개의 파티션에 1개의 파일 시스템을 작성합니다.
Btrfs
는 1개 또는 여러 저장 장치와 파티션으로 커다란 저장소 풀 pool을 만들어서 거기에 마운트 가능한 서브 볼륨
영역을 작성합니다.
: 여러 저장 장치/파티션을 하나로 묶어 대규모 저장소를 구성하는 기능
저장소 풀(Pool): 여러 디스크 묶음, Logical Volume Manager(LVM)에서 다루는 볼륨 그룹과 비슷
서브 볼륨(Subvolume): 논리적으로 구분된 공간 (LVM의 논리 볼륨처럼 사용 가능)
Btrfs는 기존의 파일 시스템 종류로 생각하기 보다는 파일 시스템 + LVM처럼 동작하는 볼륨 매니저로 보는 편이 알기 쉽습니다.
디스크 1개 = 파일 시스템 1개
디스크 여러 개 묶어서 하나의 저장소 풀 구성
Btrfs는 자체적으로 RAID 구성 지원
지원 종류: RAID 0, 1, 10, 5, 6, dup
예시: RAID 1 구성
sda, sdb 두 디스크에 동일한 데이터 저장
만약 sda가 고장나도 sdb에서 복구 가능
ext4
전통적인 안정성, 리눅스 표준
XFS
대용량 파일에 강함, 뛰어난 확장성
Btrfs
다양한 고급 기능 제공 (스냅샷, 멀티볼륨, RAID 등)
주의:
사용 목적, 데이터 특성에 따라 선택해야 함.
벤치마크 결과만으로 결정할 수 없고, 직접 테스트하고 평가하는 것이 중요.
Btrfs는 스냅샷, 멀티볼륨, RAID 등을 지원하는 차세대 파일 시스템입니다.
하지만 모든 상황에 최고의 파일 시스템은 없습니다.
목적에 맞게 선택하고 직접 테스트하는 것이 가장 중요합니다.
파일 시스템은 쉽게 말하면, 디스크 안에 파일을 체계적으로 정리하고 저장하는 방법이에요.
예를 들어 ext4, XFS 같은 것들은 파일을 디스크에 저장하고 읽는 규칙을 정하는 시스템입니다.
그런데!
일반적인 파일 시스템(ex. ext4, XFS)은 기본적으로 "한 개의 디스크 또는 파티션" 위에만 파일 시스템을 만들어요.
디스크 하나 → 파일 시스템 하나
파티션 하나 → 파일 시스템 하나
뭔가 좀 단순하죠?
LVM은 조금 더 똑똑한 기능이에요.
여러 개의 디스크를 묶어서 하나의 큰 저장소처럼 만들고,
그 저장소 안에 논리적인 볼륨(논리 디스크)을 자유롭게 나누는 기능을 합니다.
❓ 간단 비유 디스크 여러 개를 '큰 수조'에 붓고, 거기서 물을 원하는 대로 '양동이'로 나눠 담는 느낌!
덕분에 디스크 추가, 삭제, 크기 조절 등을 유연하게 할 수 있어요.
즉, 하드웨어(디스크)에 묶이지 않고 저장 공간을 훨씬 유연하게 관리할 수 있게 해주는 시스템입니다.
Btrfs는 그냥 파일 저장만 하는 게 아닙니다.
파일 저장(파일 시스템 역할) + 디스크 관리(LVM 역할)를 동시에 합니다.
여러 디스크를 하나로 묶어서 저장소 풀(Pool)을 만들고, 그 안에 서브볼륨(Subvolume)이라는 작은 단위 공간을 만들어서 파일을 관리합니다.
즉, Btrfs 자체가 → "파일 시스템도 되고" → "디스크 묶는 볼륨 매니저 역할도 한다" 는 뜻이에요!
파일 관리
O
O
O
디스크 묶기, 볼륨 관리
X (불가)
LVM이 대신
O (Btrfs 자체가)
스냅샷/RAID 등 고급 기능
제한적
일부 가능
매우 풍부
LVM: 여러 디스크를 묶어서 자유롭게 저장 공간을 관리하는 시스템
Btrfs: 파일 저장과 디스크 묶기를 동시에 지원하는 "파일 시스템 + 볼륨 매니저" 하이브리드
Btrfs는 단순히 ext4처럼 "파일만 저장하는 시스템"이 아니라, 디스크를 묶고, 나누고, 스냅샷 찍고, RAID 구성까지 다 할 수 있는 강력한 시스템입니다.
ext4 = 양동이 하나, LVM = 수조+양동이, Btrfs = 수조+양동이+자동물펌프
하드웨어 오류, 디스크 노후화 등으로 파일 시스템의 데이터가 망가질 수 있습니다. 일반 파일 시스템(ext4, XFS 등)은 손상 여부를 스스로 알 수 없습니다. 그러나 Btrfs는 모든 데이터에 체크섬을 저장합니다.
데이터 손상이 감지되면 → 즉시 해당 블록을 버리고, 읽기 요청자에게 에러를 통보합니다.
RAID1 구성처럼 같은 데이터를 다른 디스크에도 저장해두었다면, 정상 데이터를 복구할 수 있습니다.
📚 예시 흐름:
이렇게 Btrfs는 자체적으로 데이터 보호 및 복구가 가능한 강력한 파일 시스템입니다.
레이드 구성을 해줬으면 남아 있는 올바른 데이터를 바탕으로 손상된 데이터를 원상 복구할 수 있습니다.
/dev/sda와 /dev/sdb를 사용해서 RAID1을 구성했을 때 복구 처리가 [그림 07- 26]입니다.
리눅스에는 저장장치 대신 메모리(RAM) 를 이용해서 파일 시스템을 만드는 tmpfs
가 있습니다.
tmpfs는 재시작할 때 기존 파일이 남아 있지 않아도 되는
/tmp/var/run
에서 주로 사용합 니다.
✅ tmpfs 특징
데이터는 메모리에만 존재 → 속도가 매우 빠름
전원이 꺼지면 → 데이터는 모두 사라짐 (휘발성)
주로 /tmp
, /run
같은 임시 데이터 저장용으로 사용
✅ tmpfs 동작방식
mount -t tmpfs tmpfs /mnt -o size=1G
명령어로 직접 1GB 크기 tmpfs 생성 가능
처음부터 메모리를 다 차지하지 않고, 접근 시에만 페이지 단위로 메모리 할당
✅ 활용 예시
빠른 임시 저장 공간이 필요할 때
OS 부팅 중에 필요한 짧은 생명주기의 파일 저장
컴퓨터가 하나의 저장장치만 쓰는 시대는 끝났습니다. 리눅스는 네트워크를 통해 다른 컴퓨터의 디스크도 마치 내 디스크처럼 사용할 수 있습니다.
✅ 주요 네트워크 파일 시스템
NFS (Network File System): 유닉스/리눅스 간 원격 파일 공유에 사용
CIFS (Common Internet File System): 윈도우 시스템 간 파일 공유에 사용
CephFS: 여러 서버의 디스크를 하나로 묶어 초대형 분산 파일 시스템 구성
✅ NFS 예시 구조
리눅스에서는 시스템 정보도 파일처럼 제공됩니다.
✅ procfs (/proc
)
현재 실행 중인 프로세스 정보를 파일 형태로 제공
/proc/[pid]/maps
, /proc/[pid]/status
등에서 프로세스 상태 확인 가능
✅ sysfs (/sys
)
하드웨어 장치 및 드라이버 정보를 파일처럼 제공
/sys/block/nvme0n1/size
, /sys/block/nvme0n1/queue/rotational
등에서 디스크 정보 확인 가능
방식
먼저 변경사항을 저널(로그)에 기록하고, 그 후 실제 파일에 적용
변경 전 데이터를 놔두고, 새로운 영역에만 수정하여 저장
장점
장애 발생 시 저널만 복구하면 되므로 빠른 복구 가능
장애 발생 시 기존 데이터 유지로 높은 복구 안정성
단점
저널 기록 오버헤드
데이터 중복 기록으로 디스크 소모
✅ 요약
ext4, XFS는 "로그를 남긴 후 변경"
Btrfs는 "복사해서 새로 만든 후 교체"
스냅샷
매우 빠른 복사본 생성 (파일 변경분만 추적)
멀티 볼륨 구성
여러 디스크를 묶어 하나의 저장소처럼 사용 (LVM+파일시스템 통합)
RAID 지원
RAID 0/1/10/5/6 등 다양한 중복 구성 지원
데이터 체크섬
파일 손상 자동 감지 및 복구 기능 제공
파일 시스템이 아무리 강력해도 백업이 최고의 보호책입니다.
특히 Btrfs처럼 복구 기능이 풍부한 시스템이라도 정기적인 스냅샷과 외부 백업을 반드시 해야 합니다.
잘 정리 되어 있는 곳 발견! :
내용출처 :
출처 :
출처 :
출처 :
출처 :
읽어보면 좋을 것 같은 글 :