파일 시스템 구현 ⭐⭐⭐⭐

파일 시스템 구현 ⭐⭐⭐⭐

개요

파일 시스템이 디스크에 데이터를 어떻게 저장하고 관리하는지 학습합니다. 블록 할당 방식, inode 구조, 저널링, RAID 등 실제 구현에 필요한 핵심 개념을 다룹니다.


목차

  1. 파일 시스템 구조
  2. 디스크 블록 할당
  3. inode 구조
  4. 디렉토리 구현
  5. 파일 시스템 예시
  6. 저널링
  7. RAID
  8. 연습 문제

1. 파일 시스템 구조

1.1 디스크 레이아웃

┌─────────────────────────────────────────────────────────────────────────┐
│                     일반적인 파일 시스템 레이아웃                        │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │                         디스크 전체                              │   │
│   ├──────┬──────┬──────┬──────┬──────┬───────────────────────────────┤   │
│   │ MBR  │ 파티션│ 파티션│ 파티션│      │                            │   │
│   │      │  1   │  2   │  3   │ ...  │       빈 공간               │   │
│   └──────┴──────┴──────┴──────┴──────┴───────────────────────────────┘   │
│                  │                                                       │
│                  ▼                                                       │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │                      파티션 구조 (ext4 예)                       │   │
│   ├──────┬──────────┬──────────┬────────────────────────────────────┤   │
│   │ 부트 │  슈퍼   │  그룹    │            블록 그룹들             │   │
│   │ 블록 │  블록   │ 디스크립터│   0    │   1    │   2   │  ...   │   │
│   └──────┴──────────┴──────────┴────────────────────────────────────┘   │
│                                           │                              │
│                                           ▼                              │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │                        블록 그룹 구조                            │   │
│   ├──────────┬──────────┬──────────┬──────────────────────────────────┤  │
│   │  블록    │  inode   │  inode   │          데이터 블록            │  │
│   │  비트맵  │  비트맵  │  테이블  │                                  │  │
│   └──────────┴──────────┴──────────┴──────────────────────────────────┘  │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

1.2 주요 구성 요소

┌─────────────────────────────────────────────────────────────────────────┐
│                      파일 시스템 구성 요소                               │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌────────────────┬────────────────────────────────────────────────┐    │
│  │    구성 요소    │                    역할                        │    │
│  ├────────────────┼────────────────────────────────────────────────┤    │
│  │ 부트 블록       │ 부트스트랩 코드 (OS 로딩)                     │    │
│  │ (Boot Block)   │ 파티션 0번 블록                                │    │
│  ├────────────────┼────────────────────────────────────────────────┤    │
│  │ 슈퍼블록        │ 파일 시스템 메타데이터                         │    │
│  │ (Superblock)   │ - 블록 크기, 총 블록/inode 수                  │    │
│  │                │ - 자유 블록/inode 수                           │    │
│  │                │ - 마운트 횟수, 마지막 검사 시간                 │    │
│  ├────────────────┼────────────────────────────────────────────────┤    │
│  │ 블록 비트맵     │ 각 블록의 사용 여부 (0/1)                      │    │
│  │ (Block Bitmap) │ 빠른 자유 블록 탐색                            │    │
│  ├────────────────┼────────────────────────────────────────────────┤    │
│  │ inode 비트맵    │ 각 inode의 사용 여부 (0/1)                     │    │
│  ├────────────────┼────────────────────────────────────────────────┤    │
│  │ inode 테이블    │ 모든 inode 저장                                │    │
│  │                │ 파일 메타데이터의 핵심                         │    │
│  ├────────────────┼────────────────────────────────────────────────┤    │
│  │ 데이터 블록     │ 실제 파일/디렉토리 내용                        │    │
│  └────────────────┴────────────────────────────────────────────────┘    │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

2. 디스크 블록 할당

2.1 연속 할당 (Contiguous Allocation)

┌─────────────────────────────────────────────────────────────────────────┐
│                         연속 할당                                        │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   디렉토리 엔트리:                                                       │
│   ┌───────────┬─────────┬────────┐                                      │
│   │ 파일명    │ 시작블록 │  길이  │                                      │
│   ├───────────┼─────────┼────────┤                                      │
│   │ file_a    │    0    │   3    │                                      │
│   │ file_b    │    6    │   2    │                                      │
│   │ file_c    │   10    │   4    │                                      │
│   └───────────┴─────────┴────────┘                                      │
│                                                                          │
│   디스크 블록:                                                           │
│   ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐        │
│   │ A │ A │ A │   │   │   │ B │ B │   │   │ C │ C │ C │ C │   │        │
│   └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘        │
│    0   1   2   3   4   5   6   7   8   9  10  11  12  13  14            │
│                                                                          │
│   장점:                                                                  │
│   - 순차 접근 빠름 (디스크 헤드 이동 최소)                              │
│   - 직접 접근 쉬움: 블록 n = 시작 + n                                   │
│                                                                          │
│   단점:                                                                  │
│   - 외부 단편화 발생 (블록 3-5, 8-9 낭비)                               │
│   - 파일 크기 증가 어려움                                               │
│   - 미리 크기 알아야 함                                                 │
│                                                                          │
│   사용: CD-ROM, DVD (읽기 전용)                                         │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

2.2 연결 할당 (Linked Allocation)

┌─────────────────────────────────────────────────────────────────────────┐
│                         연결 할당                                        │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   디렉토리 엔트리:                                                       │
│   ┌───────────┬─────────┬─────────┐                                     │
│   │ 파일명    │ 시작블록 │ 끝블록  │                                     │
│   ├───────────┼─────────┼─────────┤                                     │
│   │ file_a    │    0    │   12    │                                     │
│   └───────────┴─────────┴─────────┘                                     │
│                                                                          │
│   디스크 블록 (각 블록에 다음 블록 포인터 포함):                        │
│                                                                          │
│   ┌───────────┐   ┌───────────┐   ┌───────────┐   ┌───────────┐        │
│   │ 블록 0    │   │ 블록 5    │   │ 블록 8    │   │ 블록 12   │        │
│   │ 데이터    │──▶│ 데이터    │──▶│ 데이터    │──▶│ 데이터    │        │
│   │ 다음: 5   │   │ 다음: 8   │   │ 다음: 12  │   │ 다음: -1  │        │
│   └───────────┘   └───────────┘   └───────────┘   └───────────┘        │
│        0               5               8              12                │
│                                                                          │
│   장점:                                                                  │
│   - 외부 단편화 없음                                                    │
│   - 파일 크기 동적 증가 가능                                            │
│                                                                          │
│   단점:                                                                  │
│   - 직접 접근 비효율 (n번째 블록 접근 시 n번 따라가야 함)               │
│   - 포인터 공간 낭비 (각 블록에 4바이트)                                │
│   - 신뢰성 문제 (포인터 손상 시 파일 손실)                              │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

2.3 FAT (File Allocation Table)

┌─────────────────────────────────────────────────────────────────────────┐
│                             FAT 구조                                     │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   FAT (메모리에 캐시됨)           디스크 블록                            │
│   ┌─────────────────┐            ┌───────────────────────────────────┐  │
│   │인덱스│ 다음블록 │            │                                   │  │
│   ├─────┼──────────┤            │  0  │  1  │  2  │  3  │  4  │ ... │  │
│   │  0  │    5     │────────────┼─ A ─┼─────┼─ B ─┼─────┼─────┼─────┤  │
│   │  1  │   FREE   │            │     │     │     │     │     │     │  │
│   │  2  │    4     │────────────┼─────┼─────┼─────┼─────┼─ B ─┼─────┤  │
│   │  3  │   FREE   │            │                                   │  │
│   │  4  │   EOF    │────────────┼─────┼─ A ─┼─────┼─────┼─────┼─────┤  │
│   │  5  │    7     │            │                                   │  │
│   │  6  │   FREE   │            │                                   │  │
│   │  7  │   EOF    │            └───────────────────────────────────┘  │
│   └─────┴──────────┘                                                    │
│                                                                          │
│   file_a: 0 → 5 → 7 → EOF                                              │
│   file_b: 2 → 4 → EOF                                                   │
│                                                                          │
│   장점:                                                                  │
│   - FAT가 메모리에 있으면 직접 접근 빠름                                │
│   - 포인터가 데이터 블록 외부에 있어 신뢰성 향상                        │
│                                                                          │
│   단점:                                                                  │
│   - FAT 크기가 클 수 있음 (대용량 디스크)                               │
│   - FAT 손상 시 전체 파일 시스템 문제                                   │
│                                                                          │
│   사용: MS-DOS, Windows (FAT32), USB 드라이브                           │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

2.4 인덱스 할당 (Indexed Allocation)

┌─────────────────────────────────────────────────────────────────────────┐
                        인덱스 할당                                       
├─────────────────────────────────────────────────────────────────────────┤
                                                                          
   디렉토리 엔트리:                                                       
   ┌───────────┬───────────┐                                             
    파일명     인덱스블록                                              
   ├───────────┼───────────┤                                             
    file_a         8                                                  
   └───────────┴───────────┘                                             
                                                                         
                                                                         
   인덱스 블록 (블록 8):          데이터 블록:                           
   ┌───────────────────┐          ┌───────────────────────────────────┐  
    [0]  블록 3                                                     
    [1]  블록 10                 3   10   15   21    ...       
    [2]  블록 15               데이터데이터데이터데이터          
    [3]  블록 21                                               
    [4]  -1 ()               └───────────────────────────────────┘  
    ...                                                                
   └───────────────────┘                                                 
                                                                          
   장점:                                                                  
   - 직접 접근 가능: 블록 n = 인덱스[n]                                  
   - 외부 단편화 없음                                                    
                                                                          
   단점:                                                                  
   - 인덱스 블록 오버헤드                                                
   - 작은 파일에 비효율적                                                
                                                                          
   확장:                                                                  
   - 연결 인덱스: 인덱스 블록들을 연결                                   
   - 다단계 인덱스: 트리 구조 (Unix inode)                               
   - 결합 방식: 직접 + 간접 포인터 (Unix inode)                          
                                                                          
└─────────────────────────────────────────────────────────────────────────┘

3. inode 구조

3.1 Unix/Linux inode

┌─────────────────────────────────────────────────────────────────────────┐
│                        inode 구조 (Unix/ext4)                            │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │                         inode                                    │   │
│   ├─────────────────────────────────────────────────────────────────┤   │
│   │  mode (권한, 유형)                                              │   │
│   │  uid (소유자)                                                   │   │
│   │  gid (그룹)                                                     │   │
│   │  size (파일 크기)                                               │   │
│   │  atime (접근 시간)                                              │   │
│   │  mtime (수정 시간)                                              │   │
│   │  ctime (상태 변경 시간)                                         │   │
│   │  link count (하드 링크 수)                                      │   │
│   ├─────────────────────────────────────────────────────────────────┤   │
│   │  블록 포인터 (데이터 위치)                                       │   │
│   │                                                                  │   │
│   │  ┌─────────────────────────────────────────────────────────┐    │   │
│   │  │ 직접 포인터    [0-11]  → 데이터 블록 (12개)            │    │   │
│   │  ├─────────────────────────────────────────────────────────┤    │   │
│   │  │ 단일 간접     [12]    → 인덱스 블록 → 데이터           │    │   │
│   │  ├─────────────────────────────────────────────────────────┤    │   │
│   │  │ 이중 간접     [13]    → 인덱스 → 인덱스 → 데이터       │    │   │
│   │  ├─────────────────────────────────────────────────────────┤    │   │
│   │  │ 삼중 간접     [14]    → 인덱스 → 인덱스 → 인덱스 → 데이터│   │   │
│   │  └─────────────────────────────────────────────────────────┘    │   │
│   └─────────────────────────────────────────────────────────────────┘   │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

3.2 직접/간접 블록 포인터

┌─────────────────────────────────────────────────────────────────────────┐
│                  inode 블록 포인터 구조                                  │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   블록 크기 = 4KB, 포인터 크기 = 4바이트                                │
│   포인터/블록 = 4KB / 4B = 1024개                                       │
│                                                                          │
│   inode                                                                  │
│   ┌───────────────┐                                                     │
│   │ 직접 [0]     │────────────────────────────────────▶ [데이터 블록]  │
│   │ 직접 [1]     │────────────────────────────────────▶ [데이터 블록]  │
│   │ ...          │                                                      │
│   │ 직접 [11]    │────────────────────────────────────▶ [데이터 블록]  │
│   ├───────────────┤                                                     │
│   │ 단일 간접[12]│──▶┌──────────┐                                      │
│   │              │    │인덱스블록│──▶ [데이터] × 1024                   │
│   │              │    └──────────┘                                      │
│   ├───────────────┤                                                     │
│   │ 이중 간접[13]│──▶┌──────────┐    ┌──────────┐                      │
│   │              │    │인덱스블록│──▶│인덱스블록│──▶ [데이터] × 1024   │
│   │              │    │ × 1024   │    └──────────┘    × 1024            │
│   │              │    └──────────┘                                      │
│   ├───────────────┤                                                     │
│   │ 삼중 간접[14]│──▶ (3단계 인덱스)                                   │
│   └───────────────┘                                                     │
│                                                                          │
│   최대 파일 크기 계산 (4KB 블록):                                       │
│   직접: 12 × 4KB = 48KB                                                 │
│   단일 간접: 1024 × 4KB = 4MB                                           │
│   이중 간접: 1024 × 1024 × 4KB = 4GB                                    │
│   삼중 간접: 1024 × 1024 × 1024 × 4KB = 4TB                             │
│   총: 약 4TB                                                             │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

3.3 inode 크기 계산 예제

// 파일의 n번째 블록 위치 찾기
#define BLOCK_SIZE 4096
#define PTRS_PER_BLOCK (BLOCK_SIZE / sizeof(uint32_t))  // 1024

#define DIRECT_BLOCKS 12
#define SINGLE_INDIRECT_LIMIT (DIRECT_BLOCKS + PTRS_PER_BLOCK)
#define DOUBLE_INDIRECT_LIMIT (SINGLE_INDIRECT_LIMIT + PTRS_PER_BLOCK * PTRS_PER_BLOCK)

uint32_t get_block_number(inode_t* inode, uint32_t logical_block) {
    if (logical_block < DIRECT_BLOCKS) {
        // 직접 블록
        return inode->direct[logical_block];
    }

    logical_block -= DIRECT_BLOCKS;

    if (logical_block < PTRS_PER_BLOCK) {
        // 단일 간접
        uint32_t* indirect = read_block(inode->single_indirect);
        return indirect[logical_block];
    }

    logical_block -= PTRS_PER_BLOCK;

    if (logical_block < PTRS_PER_BLOCK * PTRS_PER_BLOCK) {
        // 이중 간접
        uint32_t index1 = logical_block / PTRS_PER_BLOCK;
        uint32_t index2 = logical_block % PTRS_PER_BLOCK;

        uint32_t* level1 = read_block(inode->double_indirect);
        uint32_t* level2 = read_block(level1[index1]);
        return level2[index2];
    }

    // 삼중 간접 (생략)
    return 0;
}

4. 디렉토리 구현

4.1 디렉토리 엔트리 구조

┌─────────────────────────────────────────────────────────────────────────┐
                      디렉토리 구현 방식                                  
├─────────────────────────────────────────────────────────────────────────┤
                                                                          
   선형 리스트 (간단한 구현):                                            
   ┌──────────────────────────────────────────────────────────────────┐  
    디렉토리 파일 내용                                                  
   ├────────────┬────────────────┬──────────────────────────────────────┤ 
    inode 번호  엔트리 길이     파일 이름                            
   ├────────────┼────────────────┼──────────────────────────────────────┤ 
       2            12          .                                    
       2            12          ..                                   
      15            16          file1.txt                            
      23            20          documents                            
      45            24          long_filename.doc                    
   └────────────┴────────────────┴──────────────────────────────────────┘ 
                                                                          
   ext4 디렉토리 엔트리 (struct ext4_dir_entry_2):                       
   ┌─────────────────────────────────────────────────────────────────┐   
    inode (4바이트)           : inode 번호                             
    rec_len (2바이트)         :  엔트리의  길이                     
    name_len (1바이트)        : 파일 이름 길이                          
    file_type (1바이트)       : 파일 유형 (파일/디렉토리/링크 )       
    name (가변)               : 파일 이름                               
   └─────────────────────────────────────────────────────────────────┘   
                                                                          
└─────────────────────────────────────────────────────────────────────────┘

4.2 해시 테이블 디렉토리

┌─────────────────────────────────────────────────────────────────────────┐
│                     해시 테이블 디렉토리                                 │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   파일 이름 → 해시 함수 → 버킷 인덱스                                   │
│                                                                          │
│   해시 테이블                                                            │
│   ┌─────────┐                                                           │
│   │    0    │ → [readme.txt, inode 15]                                 │
│   ├─────────┤                                                           │
│   │    1    │ → [config.json, inode 23] → [data.csv, inode 45]         │
│   ├─────────┤                                                           │
│   │    2    │ → (비어있음)                                              │
│   ├─────────┤                                                           │
│   │    3    │ → [main.c, inode 67] → [test.c, inode 89]                │
│   ├─────────┤                                                           │
│   │   ...   │                                                           │
│   └─────────┘                                                           │
│                                                                          │
│   장점:                                                                  │
│   - 검색 O(1) 평균 (선형 리스트는 O(n))                                │
│   - 대용량 디렉토리에서 효과적                                          │
│                                                                          │
│   ext4의 htree (HTree Index):                                           │
│   - B-tree 기반 해시 디렉토리                                           │
│   - 수천 개 파일도 빠르게 검색                                          │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

5. 파일 시스템 예시

5.1 FAT32

┌─────────────────────────────────────────────────────────────────────────┐
│                          FAT32 구조                                      │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │ Reserved │   FAT   │  FAT    │       데이터 영역              │   │
│   │  영역    │   1     │   2     │  (클러스터들)                   │   │
│   └─────────────────────────────────────────────────────────────────┘   │
│                                                                          │
│   특징:                                                                  │
│   - 클러스터 크기: 4KB ~ 32KB                                          │
│   - FAT 엔트리: 32비트 (28비트 사용)                                   │
│   - 최대 파일 크기: 4GB - 1 (32비트 크기 필드)                         │
│   - 최대 볼륨 크기: 2TB                                                 │
│                                                                          │
│   디렉토리 엔트리 (32바이트):                                           │
│   ┌───────────────────────────────────────────────────────────────┐     │
│   │ 파일명 (8바이트) + 확장자 (3바이트) = 8.3 형식               │     │
│   │ 속성 (1바이트): 읽기전용, 숨김, 시스템, 디렉토리 등          │     │
│   │ 생성/수정/접근 시간 (10바이트)                                │     │
│   │ 시작 클러스터 번호 (4바이트)                                  │     │
│   │ 파일 크기 (4바이트)                                           │     │
│   └───────────────────────────────────────────────────────────────┘     │
│                                                                          │
│   VFAT: 긴 파일 이름 지원 (별도 엔트리 사용)                           │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

5.2 ext4

┌─────────────────────────────────────────────────────────────────────────┐
│                          ext4 주요 특징                                  │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   1. Extents (익스텐트)                                                 │
│      연속된 블록을 하나의 엔트리로 표현 → 대용량 파일에 효율적          │
│      ┌──────────────────────────────────────────────┐                   │
│      │ 시작 블록: 1000, 길이: 500                   │                   │
│      │ → 블록 1000~1499를 한 번에 참조             │                   │
│      └──────────────────────────────────────────────┘                   │
│                                                                          │
│   2. 저널링 (Journaling)                                                │
│      - 메타데이터 저널: 기본 모드, 빠름                                 │
│      - 데이터 저널: 데이터까지 저널링, 안전                            │
│                                                                          │
│   3. 대용량 지원                                                        │
│      - 최대 파일 크기: 16TB                                             │
│      - 최대 볼륨 크기: 1EB (Exabyte)                                    │
│                                                                          │
│   4. 기타 기능                                                          │
│      - Delayed allocation: 쓰기 최적화                                  │
│      - Multi-block allocation: 여러 블록 한 번에 할당                   │
│      - 디렉토리 htree: 빠른 검색                                        │
│      - 온라인 조각 모음                                                 │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

6. 저널링

6.1 저널링의 필요성

┌─────────────────────────────────────────────────────────────────────────┐
│                         저널링 개념                                      │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   문제: 파일 시스템 비일관성                                            │
│                                                                          │
│   파일 삭제 과정 (저널링 없이):                                         │
│   1. 디렉토리에서 엔트리 제거                                           │
│   2. inode를 자유 목록에 추가                    ← 여기서 크래시!       │
│   3. 데이터 블록을 자유 목록에 추가                                     │
│                                                                          │
│   크래시 후 문제:                                                        │
│   - 디렉토리에서 삭제됨                                                 │
│   - 하지만 inode와 블록은 여전히 '사용 중' 표시                         │
│   - 해당 공간 접근 불가 + 복구 불가                                     │
│                                                                          │
│   해결: 저널링                                                          │
│   변경 전에 로그(저널)에 기록 → 크래시 후 로그 기반 복구                │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

6.2 저널링 동작

┌─────────────────────────────────────────────────────────────────────────┐
│                       저널링 동작 방식                                   │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│                          저널 영역                                     │
│   ├─────────────────────────────────────────────────────────────────┤   │
│    TxB  데이터블록  메타데이터  TxE  TxB  ...  TxE  ...       │
│   └──┬──┴───────────┴────────────┴──┬──┘                               │
│                                                                       │
│            Transaction 1                 Transaction 2                │
│                                                                       │
│   TxB: Transaction Begin                                                 │
│   TxE: Transaction End (Commit)                                          │
│                                                                          │
│   쓰기 과정:                                                            │
│   1. Transaction Begin 기록                                             │
│   2. 변경할 블록들을 저널에 기록                                        │
│   3. Transaction End 기록 (커밋)                                        │
│   4. 실제 위치에 데이터 쓰기 (Checkpoint)                               │
│   5. 저널에서 해당 트랜잭션 제거                                        │
│                                                                          │
│   복구 과정 (부팅 ):                                                   │
│   1. 저널 검사                                                          │
│   2. 완료된 트랜잭션 (TxE 있음): 실제 위치에 다시 쓰기                 │
│   3. 미완료 트랜잭션 (TxE 없음): 무시 (rollback)                       │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

6.3 저널 모드

┌─────────────────────────────────────────────────────────────────────────┐
│                        ext4 저널 모드                                    │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌───────────────┬──────────────────────────────────────────────────┐   │
│  │    모드       │                     설명                         │   │
│  ├───────────────┼──────────────────────────────────────────────────┤   │
│  │ journal       │ 데이터 + 메타데이터 모두 저널링                  │   │
│  │               │ 가장 안전하지만 가장 느림 (2배 쓰기)            │   │
│  ├───────────────┼──────────────────────────────────────────────────┤   │
│  │ ordered       │ 메타데이터만 저널링                              │   │
│  │ (기본값)      │ 데이터 먼저 쓰고 메타데이터 저널링              │   │
│  │               │ 데이터 일관성 보장, 적절한 성능                  │   │
│  ├───────────────┼──────────────────────────────────────────────────┤   │
│  │ writeback     │ 메타데이터만 저널링                              │   │
│  │               │ 데이터 쓰기 순서 보장 안 함                      │   │
│  │               │ 가장 빠르지만 크래시 시 데이터 손실 가능         │   │
│  └───────────────┴──────────────────────────────────────────────────┘   │
│                                                                          │
│   # 마운트 시 옵션 지정                                                 │
│   $ mount -o data=ordered /dev/sda1 /mnt                                │
│   $ mount -o data=journal /dev/sda1 /mnt                                │
│   $ mount -o data=writeback /dev/sda1 /mnt                              │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

7. RAID

7.1 RAID 개요

┌─────────────────────────────────────────────────────────────────────────┐
│                          RAID 개요                                       │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   RAID = Redundant Array of Independent Disks                           │
│                                                                          │
│   목표:                                                                  │
│   1. 성능 향상 (Striping - 데이터 분산)                                 │
│   2. 신뢰성 향상 (Mirroring/Parity - 중복 저장)                         │
│   3. 대용량 (여러 디스크 결합)                                          │
│                                                                          │
│   구현 방식:                                                             │
│   - 하드웨어 RAID: RAID 컨트롤러 카드                                   │
│   - 소프트웨어 RAID: OS에서 구현 (mdadm)                                │
│   - 하이브리드: 메인보드 내장 RAID                                      │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

7.2 RAID 레벨

┌─────────────────────────────────────────────────────────────────────────┐
│                       RAID 0 (Striping)                                  │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   ┌───────────────────────────────────────────────────┐                 │
│   │               데이터: A B C D E F G H             │                 │
│   └───────────────────────────────────────────────────┘                 │
│                           │                                              │
│           ┌───────────────┼───────────────┐                             │
│           ▼               ▼               ▼                             │
│      ┌─────────┐     ┌─────────┐     ┌─────────┐                       │
│      │ 디스크0 │     │ 디스크1 │     │ 디스크2 │                       │
│      │  A D G  │     │  B E H  │     │  C F    │                       │
│      └─────────┘     └─────────┘     └─────────┘                       │
│                                                                          │
│   특징:                                                                  │
│   - 모든 디스크에 데이터 분산 (스트라이핑)                              │
│   - 읽기/쓰기 속도: n배 향상                                            │
│   - 용량: 디스크 수 × 단일 용량                                         │
│   - 중복 없음: 한 디스크 고장 → 전체 데이터 손실                       │
│   - 용도: 성능 중요, 데이터 손실 감수 가능한 경우                       │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────┐
│                       RAID 1 (Mirroring)                                 │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   ┌───────────────────────────────────────────────────┐                 │
│   │               데이터: A B C D                      │                 │
│   └───────────────────────────────────────────────────┘                 │
│                           │                                              │
│           ┌───────────────┴───────────────┐                             │
│           ▼                               ▼                             │
│      ┌─────────┐                     ┌─────────┐                       │
│      │ 디스크0 │                     │ 디스크1 │                       │
│      │ A B C D │ ◀── 동일 ──▶      │ A B C D │                       │
│      │ (원본)  │                     │ (미러)  │                       │
│      └─────────┘                     └─────────┘                       │
│                                                                          │
│   특징:                                                                  │
│   - 완벽한 복제 (미러링)                                                │
│   - 읽기 속도: 2배 (두 디스크에서 병렬 읽기)                            │
│   - 쓰기 속도: 동일 (두 곳에 써야 함)                                   │
│   - 용량: 단일 디스크 용량 (50% 효율)                                   │
│   - 한 디스크 고장해도 데이터 보존                                      │
│   - 용도: 중요 데이터, 시스템 드라이브                                  │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────┐
│                  RAID 5 (Striping with Parity)                           │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   ┌─────────────┬─────────────┬─────────────┬─────────────┐             │
│   │  디스크 0   │  디스크 1   │  디스크 2   │  디스크 3   │             │
│   ├─────────────┼─────────────┼─────────────┼─────────────┤             │
│   │     A1      │     A2      │     A3      │   Ap (패리티)│            │
│   ├─────────────┼─────────────┼─────────────┼─────────────┤             │
│   │     B1      │     B2      │  Bp (패리티)│     B3      │             │
│   ├─────────────┼─────────────┼─────────────┼─────────────┤             │
│   │     C1      │  Cp (패리티)│     C2      │     C3      │             │
│   ├─────────────┼─────────────┼─────────────┼─────────────┤             │
│   │  Dp (패리티)│     D1      │     D2      │     D3      │             │
│   └─────────────┴─────────────┴─────────────┴─────────────┘             │
│                                                                          │
│   패리티 계산: Ap = A1 XOR A2 XOR A3                                    │
│   복구: A1 = Ap XOR A2 XOR A3 (A1 손실 시)                              │
│                                                                          │
│   특징:                                                                  │
│   - 패리티가 분산됨 (RAID 4는 전용 디스크)                              │
│   - 용량: (n-1) × 단일 용량                                             │
│   - 1개 디스크 고장 허용                                                │
│   - 읽기 속도 향상, 쓰기는 패리티 계산으로 약간 느림                    │
│   - 용도: 대부분의 서버                                                 │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────┐
│                  RAID 6 (Dual Parity)                                    │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   ┌─────────────┬─────────────┬─────────────┬─────────────┐             │
│   │  디스크 0   │  디스크 1   │  디스크 2   │  디스크 3   │             │
│   ├─────────────┼─────────────┼─────────────┼─────────────┤             │
│   │     A1      │     A2      │   Ap (P)    │   Aq (Q)    │             │
│   ├─────────────┼─────────────┼─────────────┼─────────────┤             │
│   │     B1      │   Bp (P)    │   Bq (Q)    │     B2      │             │
│   └─────────────┴─────────────┴─────────────┴─────────────┘             │
│                                                                          │
│   특징:                                                                  │
│   - 2개의 패리티 (P, Q) - 다른 알고리즘                                 │
│   - 2개 디스크 동시 고장 허용                                           │
│   - 용량: (n-2) × 단일 용량                                             │
│   - 최소 4개 디스크 필요                                                │
│   - RAID 5보다 안전, 쓰기 성능은 더 낮음                                │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────┐
│                     RAID 10 (1+0, Mirror + Stripe)                       │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│                          데이터: A B C D                                │
│                               │                                         │
│               ┌───────────────┴───────────────┐                        │
│               ▼                               ▼                        │
│        ┌─────────────┐                 ┌─────────────┐                │
│        │  스트라이프0 │                 │  스트라이프1 │                │
│        │     A C     │                 │     B D     │                │
│        └──────┬──────┘                 └──────┬──────┘                │
│               │                               │                        │
│        ┌──────┴──────┐                 ┌──────┴──────┐                │
│        ▼             ▼                 ▼             ▼                │
│   ┌─────────┐   ┌─────────┐       ┌─────────┐   ┌─────────┐          │
│   │ 디스크0 │   │ 디스크1 │       │ 디스크2 │   │ 디스크3 │          │
│   │   A C   │   │   A C   │       │   B D   │   │   B D   │          │
│   │ (원본)  │   │ (미러)  │       │ (원본)  │   │ (미러)  │          │
│   └─────────┘   └─────────┘       └─────────┘   └─────────┘          │
│                                                                          │
│   특징:                                                                  │
│   - RAID 1 (미러) + RAID 0 (스트라이프) 결합                           │
│   - 성능: RAID 0에 가까움                                               │
│   - 안정성: RAID 1에 가까움                                             │
│   - 용량: 50% 효율                                                      │
│   - 각 미러 쌍에서 1개씩 고장 허용 (최대 2개)                           │
│   - 용도: 고성능 + 고신뢰성 필요한 경우                                 │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

7.3 RAID 레벨 비교

┌────────────────────────────────────────────────────────────────────────────────┐
│                           RAID 레벨 비교표                                      │
├──────────┬──────────┬──────────┬──────────┬──────────┬─────────────────────────┤
│  RAID    │ 최소     │ 용량     │ 읽기     │ 쓰기     │ 고장 허용               │
│  레벨    │ 디스크   │ 효율     │ 속도     │ 속도     │                         │
├──────────┼──────────┼──────────┼──────────┼──────────┼─────────────────────────┤
│  RAID 0  │    2     │  100%    │  n배     │  n배     │ 0개 (위험)              │
├──────────┼──────────┼──────────┼──────────┼──────────┼─────────────────────────┤
│  RAID 1  │    2     │  50%     │  2배     │  1배     │ 1개                     │
├──────────┼──────────┼──────────┼──────────┼──────────┼─────────────────────────┤
│  RAID 5  │    3     │  (n-1)/n │  빠름    │  보통    │ 1개                     │
├──────────┼──────────┼──────────┼──────────┼──────────┼─────────────────────────┤
│  RAID 6  │    4     │  (n-2)/n │  빠름    │  느림    │ 2개                     │
├──────────┼──────────┼──────────┼──────────┼──────────┼─────────────────────────┤
│  RAID 10 │    4     │  50%     │  빠름    │  빠름    │ 각 쌍에서 1개          │
└──────────┴──────────┴──────────┴──────────┴──────────┴─────────────────────────┘

연습 문제

문제 1: inode 블록 포인터

4KB 블록, 4바이트 포인터를 사용하는 Unix 파일 시스템에서 100MB 파일을 저장하려면 몇 개의 간접 블록이 필요한가?

정답 보기
블록 크기: 4KB = 4096 바이트
포인터/블록: 4096 / 4 = 1024개
파일 크기: 100MB = 102,400KB = 25,600 블록

직접 블록: 12개 → 12 블록 커버
단일 간접: 1024개 → 1024 블록 커버
이중 간접: 1024 × 1024 = 1,048,576 블록 커버

필요 블록: 25,600개

직접: 12개 사용
단일 간접: 1024개 사용 (간접 블록 1개)
남은 블록: 25,600 - 12 - 1024 = 24,564개

이중 간접:
- 1차 간접 블록 수: ceil(24564 / 1024) = 24개
- 2차 간접 블록: 1개

총 간접 블록:
- 단일 간접 블록: 1개
- 이중 간접 1차: 1개
- 이중 간접 2차: 24개
총: 26개

문제 2: FAT 체인

FAT 테이블이 다음과 같을 때 파일 A(시작: 3)의 클러스터 체인을 나열하시오.

클러스터
0 FREE
1 8
2 FREE
3 7
4 EOF
5 1
6 FREE
7 4
8 EOF
정답 보기
파일 A 시작: 클러스터 3

체인 추적:
3 → FAT[3]=7 → FAT[7]=4 → FAT[4]=EOF

파일 A의 클러스터 체인: 3 → 7 → 4 → EOF

파일 크기: 3개 클러스터

참고로 클러스터 5부터 시작하는 또 다른 파일:
5 → FAT[5]=1 → FAT[1]=8 → FAT[8]=EOF
체인: 5 → 1 → 8 → EOF

문제 3: 저널링 복구

시스템 크래시 후 저널에 다음 상태가 있습니다. 복구 후 파일 시스템 상태는?

저널 내용:
[TxB_1] [Block 100: 데이터A] [Block 101: 메타데이터A] [TxE_1]
[TxB_2] [Block 200: 데이터B] [Block 201: 메타데이터B]
(TxE_2 없음)
정답 보기
복구 과정:

1. Transaction 1 검사:
   - TxB_1과 TxE_1 모두 존재
   - 완료된 트랜잭션
   - Block 100, 101을 실제 위치에 다시 쓰기 (redo)

2. Transaction 2 검사:
   - TxB_2만 있고 TxE_2 없음
   - 미완료 트랜잭션
   - 이 트랜잭션 무시 (undo)
   - Block 200, 201의 변경 적용 안 함

결과:
- Transaction 1의 변경사항: 적용됨 (파일 A의 변경 완료)
- Transaction 2의 변경사항: 적용 안 됨 (파일 B 변경 없음)

파일 시스템은 Transaction 1까지만 완료된 일관된 상태

문제 4: RAID 용량 계산

각각 2TB 디스크 6개로 다음 RAID를 구성할 때 사용 가능한 용량은?

  1. RAID 0
  2. RAID 1
  3. RAID 5
  4. RAID 6
  5. RAID 10
정답 보기
디스크: 6 × 2TB = 12TB  용량

1. RAID 0: 6 × 2TB = 12TB (100%)
   - 모든 공간 사용
   - 중복 없음

2. RAID 1: 2 × 2TB = 4TB (미러링, 3)
   또는 단순 2 미러: 2TB
   - 6개를 3쌍으로 미러링    2TB
   - 합계: 3 × 2TB = 6TB (50%)

3. RAID 5: (6-1) × 2TB = 10TB (83%)
   - 패리티에 1 디스크분 사용

4. RAID 6: (6-2) × 2TB = 8TB (67%)
   - 패리티에 2 디스크분 사용

5. RAID 10: 6/2 × 2TB = 6TB (50%)
   - 3 스트라이프, 각각 미러
   - 또는: (디스크  / 2) × 단일 용량

문제 5: 파일 삭제 과정

Unix 파일 시스템에서 /home/user/file.txt 삭제 시 일어나는 과정을 inode와 블록 관점에서 설명하시오.

정답 보기
삭제 명령: rm /home/user/file.txt

1. 경로 분석:
   - /home 디렉토리의 inode 찾기
   - /home/user 디렉토리의 inode 찾기
   - file.txt의 inode 번호 찾기 (예: inode 12345)

2. 권한 확인:
   - 디렉토리(/home/user)에 쓰기 권한 있는지 확인
   - 파일이 쓰기 잠금 상태인지 확인

3. 디렉토리 엔트리 제거:
   - /home/user 디렉토리 파일에서 "file.txt" 엔트리 삭제
   - rec_len 조정하여 공간 병합

4. inode 링크 카운트 감소:
   - inode 12345의 link_count--
   - link_count > 0이면 여기서 끝 (다른 링크 존재)

5. link_count == 0이고 열린 파일 없으면:
   - inode 비트맵에서 12345 해제 (0으로 표시)
   - inode의 데이터 블록 포인터 확인
   - 모든 데이터 블록을 블록 비트맵에서 해제
   - 간접 블록도 해제

6. 슈퍼블록 업데이트:
   - 자유 inode 수 증가
   - 자유 블록 수 증가

주의: 실제 데이터는 지우지 않음
- 블록이 '사용 가능'으로 표시될 뿐
- 새 데이터로 덮어쓰기 전까지 복구 가능

다음 단계

18_IO와_IPC.md에서 I/O 시스템과 프로세스 간 통신을 배워봅시다!


참고 자료

  • Silberschatz, "Operating System Concepts" Chapters 14-15
  • Linux kernel source: fs/ext4/, fs/fat/
  • ext4 documentation: https://www.kernel.org/doc/html/latest/filesystems/ext4/
  • RAID fundamentals: https://en.wikipedia.org/wiki/RAID
to navigate between lessons