XFS 파일시스템 심화

XFS Allocation Group 병렬 설계, B+tree 메타데이터, Extent 관리, 저널링(WAL), Reflink/COW, 성능 튜닝, xfsprogs 도구 종합 가이드.

관련 표준: XFS는 POSIX.1-2017 호환 파일시스템으로, SGI IRIX에서 개발되어 Linux에 이식되었습니다. RHEL 7 이후 기본 파일시스템으로 채택되어 엔터프라이즈 Linux 환경에서 핵심적인 역할을 합니다. 종합 목록은 참고자료 — 표준 & 규격 섹션을 참고하세요.

개요 & 역사

XFS는 1993년 SGI(Silicon Graphics)가 IRIX 운영체제를 위해 개발한 64비트 고성능 저널링 파일시스템입니다. 2001년 Linux 커널 2.4에 이식되었으며, 2014년 RHEL 7에서 기본 파일시스템으로 채택된 이후 엔터프라이즈 Linux의 사실상 표준이 되었습니다.

XFS 역사

연도이벤트
1993SGI IRIX 5.3에서 XFS 최초 공개
2001Linux 커널 2.4에 이식 (SGI 오픈소스 기여)
2006Delayed Allocation 지원 추가
2012v5 on-disk format: CRC32C 셀프체크 메타데이터
2014RHEL 7 기본 파일시스템 채택
2016Reflink / COW 지원 (커널 4.9)
2019Online repair 프레임워크 개발 시작
2023Online fsck (xfs_scrub) 안정화, Large extent counters

XFS 주요 스펙

항목
최대 볼륨 크기8 EiB (263 바이트)
최대 파일 크기8 EiB
최대 파일 수264 (동적 inode 할당)
파일명 길이255 바이트
블록 크기512B / 1K / 2K / 4K (기본 4K, 최대 64K)
타임스탬프 범위1901 ~ 2486 (나노초 정밀도)
저널 방식Metadata-only Write-Ahead Logging (WAL)
On-disk formatv5 (CRC32C self-describing metadata, 기본)

ext4 / Btrfs / XFS 비교

특성ext4XFSBtrfs
최대 볼륨1 EiB8 EiB16 EiB
최대 파일16 TiB8 EiB16 EiB
온라인 축소지원미지원지원
온라인 확장지원지원지원
COW / 스냅샷미지원Reflink (4.9+)기본 COW
저널링JBD2 (데이터+메타)WAL (메타 전용)COW (암묵적)
inode 할당고정 (mkfs 시 결정)동적동적
병렬 I/OBlock Group 단위AG 기반 고도 병렬Chunk 기반
대형 파일 성능우수최우수우수
RHEL 기본 FSRHEL 6RHEL 7+미채택

아키텍처 & 디스크 레이아웃

XFS의 핵심 설계 철학은 Allocation Group(AG) 기반 병렬 처리입니다. 전체 파일시스템을 독립적인 AG로 분할하여 각 AG가 자체 공간 관리 구조를 가지므로, 멀티코어 환경에서 메타데이터 경합 없이 병렬 할당이 가능합니다.

XFS Allocation Group 레이아웃 XFS 파일시스템 (전체 볼륨) AG 0 | AG 1 | AG 2 | ... | AG N-1 Allocation Group 내부 구조 (AG 0) Superblock xfs_sb AGF Free Space B+tree AGI Inode B+tree AGFL Free List 데이터 / 메타데이터 블록 Inode Chunks, Extents, B+tree Nodes AGF 내부: 이중 B+tree Free Space 관리 BNO B+tree (블록 번호 순) CNT B+tree (크기 순) BNO: 인접 할당 최적화 | CNT: 최적 크기 Extent 탐색 각 AG는 독립적 잠금 → 멀티코어 병렬 할당 가능

xfs_sb 주요 필드

/* fs/xfs/libxfs/xfs_format.h */
typedef struct xfs_sb {
    __uint32_t  sb_magicnum;     /* 0x58465342 ('XFSB') */
    __uint32_t  sb_blocksize;    /* 파일시스템 블록 크기 (바이트) */
    xfs_rfsblock_t sb_dblocks;  /* 데이터 영역 총 블록 수 */
    xfs_rfsblock_t sb_rblocks;  /* 리얼타임 영역 블록 수 */
    xfs_rtblock_t  sb_rextents; /* 리얼타임 extent 수 */
    uuid_t      sb_uuid;         /* 파일시스템 UUID */
    xfs_fsblock_t sb_logstart;  /* 내부 로그 시작 블록 (0=외부) */
    xfs_ino_t   sb_rootino;      /* 루트 디렉토리 inode 번호 */
    xfs_agblock_t sb_agblocks;  /* AG당 블록 수 */
    xfs_agnumber_t sb_agcount; /* AG 개수 */
    __uint32_t  sb_sectsize;     /* 디스크 섹터 크기 */
    __uint16_t  sb_inodesize;    /* inode 크기 (기본 512) */
    __uint16_t  sb_inopblock;    /* 블록당 inode 수 */
    __uint32_t  sb_versionnum;   /* 기능 비트 마스크 */
    __uint32_t  sb_features2;    /* 확장 기능 플래그 */
    __uint32_t  sb_features_compat;   /* v5: 호환 기능 */
    __uint32_t  sb_features_incompat; /* v5: 비호환 기능 (reflink 등) */
    __uint32_t  sb_crc;          /* v5: CRC32C 체크섬 */
    ...
} xfs_sb_t;

Allocation Groups 상세

XFS 볼륨은 여러 개의 Allocation Group(AG)으로 등분됩니다. 각 AG는 자체 수퍼블록 복사본, 프리 스페이스 B+tree, inode 관리 구조를 가집니다. 이 설계 덕분에 여러 스레드가 서로 다른 AG에서 동시에 할당 작업을 수행할 수 있습니다.

AGF (AG Free Space)

AGF 헤더는 각 AG의 프리 블록 관리를 담당합니다. 두 개의 B+tree를 유지합니다:

B+tree용도
BNO tree시작 블록 번호특정 위치 근처에서 할당 (공간적 인접성)
CNT treeextent 크기요청 크기에 가장 적합한 free extent 탐색
/* fs/xfs/libxfs/xfs_format.h */
typedef struct xfs_agf {
    __be32   agf_magicnum;      /* 'XAGF' */
    __be32   agf_versionnum;
    __be32   agf_seqno;         /* AG 번호 */
    __be32   agf_length;        /* AG 블록 수 */
    __be32   agf_roots[2];      /* BNO, CNT B+tree 루트 */
    __be32   agf_levels[2];     /* BNO, CNT B+tree 높이 */
    __be32   agf_flfirst;       /* AGFL 첫 활성 항목 */
    __be32   agf_fllast;        /* AGFL 마지막 활성 항목 */
    __be32   agf_flcount;       /* AGFL 활성 항목 수 */
    __be32   agf_freeblks;      /* AG 내 총 free 블록 */
    __be32   agf_longest;       /* 가장 긴 free extent 크기 */
    __be32   agf_rmap_root;     /* v5: reverse mapping B+tree 루트 */
    __be32   agf_refcount_root; /* v5: refcount B+tree 루트 */
    ...
} xfs_agf_t;

AGI (AG Inode Management)

AGI는 AG 내 inode 할당을 관리합니다. Inode B+tree로 사용 중인 inode chunk를 추적하고, Free Inode B+tree로 여유 inode가 있는 chunk를 빠르게 찾습니다.

/* fs/xfs/libxfs/xfs_format.h */
typedef struct xfs_agi {
    __be32   agi_magicnum;     /* 'XAGI' */
    __be32   agi_versionnum;
    __be32   agi_seqno;        /* AG 번호 */
    __be32   agi_length;       /* AG 블록 수 */
    __be32   agi_count;        /* AG 내 할당된 inode 수 */
    __be32   agi_root;         /* Inode B+tree 루트 */
    __be32   agi_level;        /* Inode B+tree 높이 */
    __be32   agi_freecount;    /* AG 내 free inode 수 */
    __be32   agi_newino;       /* 가장 최근 할당 inode chunk */
    __be32   agi_free_root;    /* Free Inode B+tree 루트 */
    __be32   agi_free_level;   /* Free Inode B+tree 높이 */
    ...
} xfs_agi_t;

AGFL (AG Free List)

AGFL은 B+tree 분할/병합 시 필요한 메타데이터 블록을 예약하는 소규모 풀입니다. B+tree 조작 중에 추가 블록이 필요하면 AGFL에서 꺼내 쓰고, B+tree가 축소되면 반납합니다. 이는 B+tree 수정과 공간 할당 사이의 순환 의존성을 해결합니다.

병렬 I/O 스케일링

설계 원리: ext4의 Block Group은 잠금 경합이 발생할 수 있지만, XFS AG는 각각 독립적인 B+tree와 잠금을 가집니다. 따라서 N개 코어가 서로 다른 AG에서 동시에 파일을 생성/확장할 수 있어, 대규모 멀티스레드 I/O 워크로드에서 선형적 성능 확장이 가능합니다.
/* AG별 독립 잠금 — fs/xfs/xfs_mount.h */
typedef struct xfs_perag {
    struct xfs_mount   *pag_mount;
    xfs_agnumber_t      pag_agno;      /* AG 번호 */
    atomic_t            pag_ref;       /* 참조 카운트 */
    struct rw_semaphore pag_ici_lock;  /* inode cache lock */
    struct xfs_buf     *pag_agf_bp;   /* AGF 버퍼 */
    struct xfs_buf     *pag_agi_bp;   /* AGI 버퍼 */
    ...
} xfs_perag_t;

B+tree 구조

XFS는 모든 메타데이터를 B+tree로 관리합니다. 이는 O(log n) 탐색 성능과 대규모 데이터셋에서의 일관된 성능을 보장합니다.

XFS B+tree 종류

B+tree위치용도
BNO B+treeAGF시작 블록 번호Free space (위치별 검색)
CNT B+treeAGFextent 크기Free space (크기별 검색)
Inode B+treeAGIinode 번호Inode chunk 추적
Free Inode B+treeAGIinode 번호Free inode chunk 추적
Reverse Map B+treeAGF (v5)물리 블록역방향 매핑 (online repair)
Refcount B+treeAGF (v5)시작 블록Reflink 참조 카운트
Extent B+treeInode data fork파일 오프셋파일 extent 매핑
Directory B+treeInode data fork해시값대형 디렉토리 엔트리
Attr B+treeInode attr fork이름 해시확장 속성

Short-format vs Long-format

XFS B+tree는 두 가지 포인터 형식을 사용합니다:

형식범위사용처
Short-formatAG 내부 (AG 상대 블록 번호)AGF/AGI의 free space, inode, rmap, refcount B+tree
Long-format전체 파일시스템 (절대 블록 번호)Inode data fork의 extent B+tree, 디렉토리/속성 B+tree
/* B+tree 커서 — fs/xfs/libxfs/xfs_btree.h */
struct xfs_btree_cur {
    struct xfs_mount   *bc_mp;        /* 파일시스템 마운트 */
    const struct xfs_btree_ops *bc_ops;  /* B+tree 연산 함수 */
    uint                bc_btnum;     /* B+tree 종류 식별자 */
    int                 bc_nlevels;   /* 트리 높이 */
    union {
        struct {
            struct xfs_buf  *agbp; /* AG 헤더 버퍼 (short) */
            xfs_agnumber_t  agno; /* AG 번호 */
        } s;
        struct {
            struct xfs_inode *ip; /* inode (long) */
            int             whichfork;
        } l;
    } bc_ino;
    struct xfs_btree_level bc_levels[]; /* 레벨별 상태 */
};

Extent 관리

XFS는 파일 데이터를 extent 단위로 관리합니다. 각 extent는 연속된 파일시스템 블록의 범위를 나타내며, 128비트(16바이트) packed 레코드로 저장됩니다.

Extent 레코드 형식

/* 128비트 Extent 레코드 구조:
 *  비트 [0:8]    — extent flag (1비트) + 논리 오프셋 상위 (8비트)
 *  비트 [9:62]   — 논리 오프셋(54비트): 파일 내 시작 블록
 *  비트 [63:115] — 물리 블록 번호(52비트): AG번호 + AG 내 블록
 *  비트 [116:127]— extent 길이(21비트): 최대 2M 블록
 */
typedef struct xfs_bmbt_rec {
    __be64   l0;   /* flag(1) + offset(54) + startblock 상위(9) */
    __be64   l1;   /* startblock 하위(43) + blockcount(21) */
} xfs_bmbt_rec_t;

/* 언패킹 후 논리적 표현 */
typedef struct xfs_bmbt_irec {
    xfs_fileoff_t   br_startoff;    /* 파일 내 논리 오프셋 */
    xfs_fsblock_t   br_startblock;  /* 물리 블록 번호 */
    xfs_filblks_t   br_blockcount;  /* 블록 수 */
    xfs_exntst_t    br_state;       /* written / unwritten */
} xfs_bmbt_irec_t;

Delayed Allocation (delalloc)

XFS의 Delayed Allocation은 write() 시점에서 실제 블록 할당을 지연시키고, writeback 시점에 한꺼번에 할당합니다. 이를 통해:

/* delalloc extent는 br_startblock에 특수 값을 사용 */
#define DELAYSTARTBLOCK  ((xfs_fsblock_t)-1LL)
#define HOLESTARTBLOCK   ((xfs_fsblock_t)-2LL)

/* delalloc 예약: 실제 블록 없이 카운터만 증가 */
int xfs_bmapi_reserve_delalloc(
    struct xfs_inode    *ip,
    int                 whichfork,
    struct xfs_bmbt_irec *got,
    struct xfs_bmbt_irec *prev,
    xfs_filblks_t       len,
    int                 eof);

Preallocation & Extent Size Hints

fallocate() 또는 xfs_io -c 'extsize'를 통해 extent 할당 크기를 제어할 수 있습니다:

/* Extent size hint 설정 — 데이터베이스 워크로드 최적화 */
$ xfs_io -c 'extsize 16m' /data/tablespace
/* 16MB 단위로 extent 할당하여 단편화 방지 */

/* fallocate로 사전 할당 */
$ fallocate -l 10G /data/bigfile
/* unwritten extent로 10GB 연속 공간 확보 */

Unwritten Extents

Unwritten extent는 물리 블록이 할당되었지만 아직 데이터가 쓰여지지 않은 상태입니다. fallocate()로 사전 할당하면 이 상태가 됩니다. 읽기 시 0을 반환하고, 실제 쓰기 시 written 상태로 전환됩니다. 이를 통해 보안(이전 데이터 노출 방지)과 성능(연속 할당)을 모두 달성합니다.

Inode 구조

XFS inode는 고정 크기(기본 512바이트)로, 동적으로 할당됩니다. 64개의 inode가 하나의 inode chunk를 구성하며, 필요에 따라 AG 내에서 새 chunk를 할당합니다.

Inode 포맷

버전크기특징
v1256B초기 형식, 32비트 프로젝트 ID
v2256B나노초 타임스탬프, 64비트 프로젝트 ID
v3512B (기본)CRC32C 체크섬, change count, 생성 시간
/* fs/xfs/libxfs/xfs_format.h */
typedef struct xfs_dinode {
    __be16   di_magic;         /* 0x494e ('IN') */
    __be16   di_mode;          /* 파일 유형 + 퍼미션 */
    __u8     di_version;       /* inode 버전 (1/2/3) */
    __u8     di_format;        /* data fork 형식 */
    __be32   di_uid;           /* 소유자 UID */
    __be32   di_gid;           /* 소유자 GID */
    __be32   di_nlink;         /* 하드링크 수 */
    __be64   di_size;          /* 파일 크기 (바이트) */
    __be64   di_nblocks;       /* 할당된 블록 수 */
    __be32   di_extsize;       /* extent size hint */
    __be32   di_nextents;      /* data fork extent 수 */
    __be16   di_anextents;     /* attr fork extent 수 */
    __u8     di_forkoff;       /* attr fork 시작 오프셋 (8바이트 단위) */
    __s8     di_aformat;       /* attr fork 형식 */
    /* v3 추가 필드 */
    __be32   di_crc;           /* CRC32C */
    __be64   di_changecount;   /* inode 변경 횟수 */
    __be64   di_flags2;        /* 확장 플래그 (reflink 등) */
    ...
} xfs_dinode_t;

Data Fork 형식 전환

파일의 extent 수에 따라 data fork 저장 형식이 자동 전환됩니다:

형식di_format 값조건설명
Local (Inline)XFS_DINODE_FMT_LOCAL데이터가 inode 내 수용 가능심볼릭 링크, 소형 디렉토리
Extents ListXFS_DINODE_FMT_EXTENTSextent 수가 fork 공간 내extent 레코드를 inode에 직접 저장
B+treeXFS_DINODE_FMT_BTREEextent 수가 fork 초과B+tree 루트만 inode에, 나머지는 외부 블록

Attr Fork

inode 내부는 Data ForkAttr Fork로 분할됩니다. di_forkoff가 경계를 정의하며, 확장 속성(xattr)은 Attr Fork에 저장됩니다. Data Fork와 동일한 Local → Extents → B+tree 전환 메커니즘을 사용합니다.

디렉토리 구조

XFS 디렉토리는 엔트리 수에 따라 5단계로 구조가 확장됩니다:

형식조건구조
Shortforminode 내 수용 가능이름/inode 쌍을 inode data fork에 인라인 저장
Block1 블록에 수용단일 디렉토리 데이터 블록 (해시 정렬)
Leaf다수 데이터 블록데이터 블록 + 별도 리프 블록 (해시→데이터 매핑)
Node리프가 1블록 초과데이터 + 리프 + 내부 노드 블록 (B+tree)
B+treeextent 수 초과inode의 extent list가 B+tree로 전환

디렉토리 해시

XFS는 xfs_da_hashname()으로 파일명의 해시값을 계산합니다. 이 해시는 디렉토리 내 엔트리 검색을 O(log n)으로 만들어 대규모 디렉토리에서도 빠른 lookup을 보장합니다.

/* fs/xfs/libxfs/xfs_da_btree.h */
xfs_dahash_t xfs_da_hashname(
    const __uint8_t *name,
    int              namelen);

/* Leaf 엔트리: 해시값 → 데이터 블록 오프셋 */
typedef struct xfs_dir2_leaf_entry {
    __be32   hashval;    /* 이름 해시 */
    __be32   address;    /* 데이터 블록 내 오프셋 */
} xfs_dir2_leaf_entry_t;

저널링 (Log)

XFS는 Write-Ahead Logging(WAL) 기반의 메타데이터 전용 저널링을 사용합니다. 모든 메타데이터 변경은 로그에 먼저 기록되고, 이후 실제 위치에 반영(checkpoint)됩니다.

Log 구조

XFS Log 구조 순환 로그 버퍼 (Circular Log) Log Record 0 | Log Record 1 | ... | Log Record N | (wrap around) Log Record 내부 Log Record Header Log Item (inode) Log Item (buf/EFI) Log Item (dquot) Commit Record (LSN) LSN(Log Sequence Number)으로 로그 진행 상태 추적

AIL (Active Item List)

AIL은 디스크에 반영되지 않은 로그 항목을 LSN 순서로 추적하는 자료구조입니다. Checkpoint 쓰레드가 AIL의 가장 오래된 항목부터 디스크에 반영하고, 해당 로그 공간을 재사용합니다.

/* fs/xfs/xfs_trans_ail.c — AIL 핵심 동작 */

/* 트랜잭션 커밋 시 로그 아이템을 AIL에 삽입 */
void xfs_trans_ail_insert(
    struct xfs_ail      *ailp,
    struct xfs_log_item *lip,
    xfs_lsn_t           lsn);

/* Checkpoint: AIL tail부터 디스크 반영 */
void xfs_ail_push_all(
    struct xfs_ail  *ailp);

/* 반영 완료 후 AIL에서 제거 → 로그 공간 해제 */
void xfs_trans_ail_delete(
    struct xfs_log_item *lip,
    int                 shutdown_type);

Intent Logging (EFI/EFD, RUI/RUD)

XFS는 Intent Logging으로 복잡한 다단계 연산의 원자성을 보장합니다. Intent 로그 아이템(예: EFI)이 먼저 기록되고, 완료 시 Done 아이템(예: EFD)이 기록됩니다. 복구 시 Done이 없는 Intent를 재실행합니다.

IntentDone용도
EFI (Extent Free Intent)EFDextent 해제 (truncate, rm)
RUI (Rmap Update Intent)RUDreverse mapping 업데이트
CUI (Refcount Update Intent)CUDrefcount 업데이트 (reflink)
BUI (Bmap Update Intent)BUDextent 매핑 업데이트

외부 로그 디바이스

XFS는 저널을 별도 디바이스에 배치할 수 있어, 데이터 I/O와 저널 I/O를 물리적으로 분리하여 성능을 향상시킬 수 있습니다:

# 외부 로그 디바이스를 사용하여 XFS 생성
$ mkfs.xfs -l logdev=/dev/sdb1,size=512m /dev/sda1

# 마운트 시 외부 로그 지정
$ mount -o logdev=/dev/sdb1 /dev/sda1 /mnt/data

고급 기능

Reflink은 두 파일이 동일한 물리 extent를 공유하고, 어느 한쪽이 수정되면 COW(Copy-on-Write)로 분기하는 기능입니다. cp --reflink은 메타데이터만 복사하므로 즉각 완료됩니다.

# instant copy — 실제 데이터 복사 없음
$ cp --reflink=always source.img dest.img

# Reflink 활성화 확인 (v5 포맷 기본 활성)
$ xfs_info /mnt/data | grep reflink
reflink=1
Refcount B+tree: AGF 내의 Refcount B+tree가 각 물리 extent의 참조 수를 추적합니다. 참조 수가 0이 되면 해당 extent가 해제되고, 참조 수가 2 이상이면 COW 시 새 블록을 할당합니다.
/* fs/xfs/xfs_reflink.c — COW fork 처리 */
int xfs_reflink_allocate_cow(
    struct xfs_inode    *ip,
    struct xfs_bmbt_irec *imap,
    bool                *shared,
    uint                *lockmode,
    bool                convert_now);

/* COW extent writeback 완료 후 원본 매핑 교체 */
int xfs_reflink_end_cow(
    struct xfs_inode    *ip,
    xfs_off_t           offset,
    xfs_off_t           count);

Online 확장 (xfs_growfs)

XFS는 마운트 상태에서 파일시스템을 확장할 수 있습니다. 새 AG를 추가하는 방식이므로 기존 데이터 재배치가 불필요합니다:

# LV 확장 후 XFS 온라인 확장
$ lvextend -L +100G /dev/vg0/data
$ xfs_growfs /mnt/data

# 특정 크기로 확장 (블록 단위)
$ xfs_growfs -D 524288000 /mnt/data
축소 불가: XFS는 온라인/오프라인 축소를 모두 지원하지 않습니다. 이는 AG 기반 설계의 한계로, 축소가 필요하면 백업 후 더 작은 볼륨에 재생성해야 합니다.

Project Quotas (디렉토리 기반)

XFS의 Project Quota는 디렉토리 트리 단위로 공간 제한을 적용합니다. uid/gid 기반 quota와 달리, 특정 디렉토리 계층에 용량 한도를 설정할 수 있어 컨테이너나 프로젝트별 공간 관리에 유용합니다:

# Project Quota 설정
$ echo "42:/data/project_a" >> /etc/projects
$ echo "project_a:42" >> /etc/projid

# 마운트 옵션에 pquota 추가
$ mount -o pquota /dev/sda1 /data

# 프로젝트 디렉토리 초기화 및 제한 설정
$ xfs_quota -x -c 'project -s project_a' /data
$ xfs_quota -x -c 'limit -p bhard=100g project_a' /data

Real-time Subvolume

XFS는 선택적으로 별도의 real-time subvolume을 구성할 수 있습니다. 이 영역은 extent 단위 할당으로 일반 AG 메커니즘을 우회하여, 예측 가능한 I/O 지연이 필요한 워크로드(멀티미디어, 실시간 데이터 수집)에 적합합니다:

# real-time subvolume 포함 mkfs
$ mkfs.xfs -r rtdev=/dev/sdb1,extsize=1m /dev/sda1

# 마운트 시 rtdev 지정
$ mount -o rtdev=/dev/sdb1 /dev/sda1 /mnt/rtdata

DAX (Direct Access)

Persistent Memory(pmem) 디바이스에서 XFS를 DAX 모드로 사용하면, 페이지 캐시를 우회하여 CPU가 메모리 매핑을 통해 직접 스토리지에 접근합니다:

# DAX 모드로 마운트 (전체 FS)
$ mount -o dax=always /dev/pmem0 /mnt/pmem

# 파일별 DAX 속성 설정 (커널 5.8+)
$ xfs_io -c 'chattr +x' /mnt/pmem/datafile

CRC32C Self-describing Metadata (v5 포맷)

v5 on-disk 포맷(Linux 3.7+, 기본 활성)은 모든 메타데이터 블록에 다음을 추가합니다:

성능 튜닝

마운트 옵션

옵션기본값설명
logbufs=N8인메모리 로그 버퍼 수 (2-8). 높을수록 쓰기 버스트 흡수
logbsize=N32K/256K로그 버퍼 크기. 대형 트랜잭션 워크로드에서 증가
allocsize=N64K스트리밍 쓰기 시 사전 할당 단위 (최대 1G)
inode64v5 기본모든 AG에서 inode 할당 (32비트 앱 호환 주의)
largeiooffstat()의 st_blksize를 stripe width로 설정
nobarrierbarrier=1쓰기 배리어 비활성 (배터리 캐시 RAID만)
discardoffSSD TRIM 자동 발행
lazytimeoff타임스탬프 업데이트 지연

핵심 sysctl

# XFS 관련 sysctl 파라미터
fs.xfs.xfssyncd_centisecs = 3000   # 동기화 데몬 주기 (30초)
fs.xfs.filestream_centisecs = 3000 # filestream 할당 AG 유지 시간
fs.xfs.speculative_prealloc_lifetime = 300 # delalloc 사전 할당 유지 (초)
fs.xfs.error_level = 3             # 오류 보고 수준 (0-5)

xfs_fsr (단편화 해소)

# 전체 파일시스템 단편화 해소
$ xfs_fsr /mnt/data

# 특정 파일만 defrag
$ xfs_fsr /mnt/data/largefile.dat

# 단편화 상태 확인
$ xfs_db -r -c 'frag -f' /dev/sda1

I/O 패턴별 최적화

워크로드권장 설정
대용량 순차 쓰기 (미디어, 백업)allocsize=1g, logbsize=256k, extent size hint 설정
소형 랜덤 I/O (데이터베이스)inode64, noatime, logbufs=8, AG 수 조정
메타데이터 집중 (메일 서버)외부 로그 디바이스, logbsize=256k, lazytime
가상화 이미지 (VM)reflink=1, extent size hint, allocsize 증가
NVMe/SSDdiscard 또는 fstrim cron, inode64
mkfs 시 최적화: RAID 환경에서는 mkfs.xfs -d su=256k,sw=4로 stripe unit/width를 디스크 배열에 맞추면 데이터 정렬이 최적화됩니다. AG 크기도 -d agcount=N으로 CPU 코어 수에 맞출 수 있습니다.

관리 도구 (xfsprogs)

주요 도구 요약

도구용도
mkfs.xfsXFS 파일시스템 생성
xfs_info마운트된 FS의 지오메트리 정보 출력
xfs_adminUUID, 레이블 변경, lazy-count 전환
xfs_repair오프라인 파일시스템 복구
xfs_db디버그 모드 — 메타데이터 직접 검사/수정
xfs_logprint저널 로그 내용 덤프
xfs_metadump메타데이터 이미지 추출 (버그 리포트용)
xfs_growfs온라인 파일시스템 확장
xfs_fsr파일 단편화 해소 (defrag)
xfs_quota사용자/그룹/프로젝트 quota 관리
xfs_freeze / xfs_thawI/O 일시 중지/재개 (스냅샷용)
xfs_scrub온라인 메타데이터 검증 (v5 포맷)
xfs_io파일 I/O 디버깅 (extent 정보, fallocate, fiemap)

mkfs.xfs 주요 옵션

# 기본 생성 (v5 포맷, reflink 활성, CRC 활성)
$ mkfs.xfs /dev/sda1

# RAID 최적화 (stripe unit 256K, 4 data disks)
$ mkfs.xfs -d su=256k,sw=4 -l su=256k /dev/md0

# 외부 로그, 큰 로그 크기
$ mkfs.xfs -l logdev=/dev/sdb1,size=1g /dev/sda1

# inode 크기 변경, AG 수 지정
$ mkfs.xfs -i size=1024 -d agcount=32 /dev/sda1

# 블록 크기 변경 (1K, 2K, 4K 중 선택)
$ mkfs.xfs -b size=4096 /dev/sda1

디버깅 & 트러블슈팅

xfs_db 실전 활용

# 수퍼블록 검사
$ xfs_db -r /dev/sda1
xfs_db> sb 0
xfs_db> print
magicnum = 0x58465342
blocksize = 4096
dblocks = 524288000
agcount = 4
agblocks = 131072000
...

# 특정 inode 검사
xfs_db> inode 131
xfs_db> print
core.magic = 0x494e
core.mode = 0100644
core.version = 3
core.format = 2 (extents)
core.size = 1048576
...

# AG free space 통계
xfs_db> agf 0
xfs_db> print freeblks longest
freeblks = 95000000
longest = 32000000

# 단편화 통계
xfs_db> frag -f

xfs_repair 복구 절차

주의: xfs_repair는 반드시 언마운트 상태에서 실행해야 합니다. 마운트된 상태에서 실행하면 데이터 손상이 발생할 수 있습니다.
# 1단계: 드라이런 (변경 없이 검사만)
$ xfs_repair -n /dev/sda1

# 2단계: 실제 복구
$ umount /mnt/data
$ xfs_repair /dev/sda1

# 더티 로그가 있을 경우: 먼저 로그 클리어 후 복구
$ xfs_repair -L /dev/sda1
# -L은 로그를 제로화하므로 최근 트랜잭션 손실 가능

# 외부 로그 디바이스 사용 시
$ xfs_repair -l /dev/sdb1 /dev/sda1

커널 로그 메시지 해석

메시지 패턴의미대응
XFS: Corruption detected메타데이터 CRC 불일치xfs_repair 실행
XFS: Log force timed out로그 I/O 응답 없음스토리지 상태 점검
XFS: xfs_do_force_shutdown치명적 오류로 FS 중단dmesg 확인 후 xfs_repair
XFS: Filesystem has duplicate UUIDUUID 충돌 (클론 볼륨)xfs_admin -U generate
XFS: possible memory allocation deadlock메모리 압력 하 할당 실패메모리 부족 원인 해결

Tracepoints (xfs:*)

# 사용 가능한 XFS tracepoints 목록
$ perf list 'xfs:*' 2>&1 | head -20
xfs:xfs_alloc_exact_done
xfs:xfs_alloc_near_first
xfs:xfs_buf_read
xfs:xfs_ilock
xfs:xfs_iomap_found
xfs:xfs_reflink_bounce_dio_write
...

# extent 할당 추적
$ perf record -e 'xfs:xfs_alloc_*' -a -- sleep 10
$ perf script

# trace-cmd로 delalloc 모니터링
$ trace-cmd record -e 'xfs:xfs_iomap*' -e 'xfs:xfs_alloc*'
$ trace-cmd report

# bpftrace로 실시간 분석
$ bpftrace -e 'tracepoint:xfs:xfs_file_buffered_write { printf("%s %d bytes\n", comm, args->count); }'
실전 디버깅 팁: xfs_io -c 'fiemap -v' file로 파일의 extent 매핑을 확인하고, xfs_io -c 'stat' file로 inode 세부 정보를 조회할 수 있습니다. 성능 문제 진단 시 xfs_io -c 'freesp -s' mountpoint로 free space 단편화를 확인하세요.