File System · Linux v6.6 · source + diagram note

f2fs

v6.6 F2FS의 mount·data writeback·GC를 각각 고정 원문으로 읽고, checkpoint와 실제 쓰기 결과를 구분합니다.

F2FS의 디스크 배치와 mount 경계를 먼저 나누기

F2FS의 SB·CP·SIT·NAT·SSA·Main은 서로 다른 역할을 한다. CP는 mount 시 선택할 복구 기준이고, SIT의 유효 block 정보와 NAT의 node 위치는 그 이후 manager가 사용하는 정보다. 일반 data writeback과 GC는 mount의 다음 고정 단계가 아니라 별도 실행 경로다.

그림 1. 디스크의 영역과 mount가 읽는 기준점
SB기본 지오메트리와 feature
CP유효 checkpoint pack 선택
SITsegment별 유효 block 현황
NATnode ID → node block 위치
SSAblock의 owner 요약
Mainnode·data block 저장

이 순서는 디스크 영역의 배치다. mount는 raw super를 읽고 유효 CP를 확보한 뒤 segment/node manager를 구성한다. 각 영역이 같은 함수를 통해 한 번에 순서대로 쓰인다는 뜻은 아니다.

Documentation/filesystems/f2fs.rst:549–596 · fs/f2fs/super.c:4500–4504 · fs/f2fs/super.c:4562–4573

버전 고정 소스와 세 경로

v6.6에는 f2fs_fill_super(sb, data, silent)와 page 기반 f2fs_write_data_page() wrapper가 있다. 기존 두 번째 발췌는 super.c의 f2fs_drop_inode() 문맥이다. 그 주석이 writeback→GC→evict의 잠재 교착을 언급하지만, 곧바로 writeback 구현을 보여 주는 코드는 아니다.

관심 경로고정 원문이 글의 경계
mountfs/f2fs/super.c:4328–4367raw super → checkpoint → segment/node manager; 기존 첫 발췌는 초기 할당만
writebackfs/f2fs/data.c:2993–3013f2fs_write_data_page → f2fs_write_single_data_page; 실제 f2fs_do_write_data_page는 IPU/OPU 분기
GCfs/f2fs/gc.c:1797–1832__get_victim·gc_data_segment 등 별도 경로
구조·형식Documentation/filesystems/f2fs.rst:549–596SB/CP/SIT/NAT/SSA/Main과 cleaning 설명

대표 코드

f2fs_fill_super 시작과 앞 함수 끝

고정 원문: fs/f2fs/super.c:4323–4362
	}

	sbi->readdir_ra = true;
}

static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
{
	struct f2fs_sb_info *sbi;
	struct f2fs_super_block *raw_super;
	struct inode *root;
	int err;
	bool skip_recovery = false, need_fsck = false;
	char *options = NULL;
	int recovery, i, valid_super_block;
	struct curseg_info *seg_i;
	int retry_cnt = 1;
#ifdef CONFIG_QUOTA
	bool quota_enabled = false;
#endif

try_onemore:
	err = -EINVAL;
	raw_super = NULL;
	valid_super_block = -1;
	recovery = 0;

	/* allocate memory for f2fs-specific super block info */
	sbi = kzalloc(sizeof(struct f2fs_sb_info), GFP_KERNEL);
	if (!sbi)
		return -ENOMEM;

	sbi->sb = sb;

	/* initialize locks within allocated memory */
	init_f2fs_rwsem(&sbi->gc_lock);
	mutex_init(&sbi->writepages);
	init_f2fs_rwsem(&sbi->cp_global_sem);
	init_f2fs_rwsem(&sbi->node_write);
	init_f2fs_rwsem(&sbi->node_change);
	spin_lock_init(&sbi->stat_lock);

읽기 기준: f2fs_sb_info 할당·초기화 시작 부분이다. raw super, 유효 CP, segment/node manager 구축과 mount 성공 여부는 아래 링크의 함수 후반을 읽어야 한다.

f2fs_drop_inode의 I_SYNC·GC 교착 회피 구간

고정 원문: fs/f2fs/super.c:1444–1483
	}

	/*
	 * This is to avoid a deadlock condition like below.
	 * writeback_single_inode(inode)
	 *  - f2fs_write_data_page
	 *    - f2fs_gc -> iput -> evict
	 *       - inode_wait_for_writeback(inode)
	 */
	if ((!inode_unhashed(inode) && inode->i_state & I_SYNC)) {
		if (!inode->i_nlink && !is_bad_inode(inode)) {
			/* to avoid evict_inode call simultaneously */
			atomic_inc(&inode->i_count);
			spin_unlock(&inode->i_lock);

			/* should remain fi->extent_tree for writepage */
			f2fs_destroy_extent_node(inode);

			sb_start_intwrite(inode->i_sb);
			f2fs_i_size_write(inode, 0);

			f2fs_submit_merged_write_cond(F2FS_I_SB(inode),
					inode, NULL, 0, DATA);
			truncate_inode_pages_final(inode->i_mapping);

			if (F2FS_HAS_BLOCKS(inode))
				f2fs_truncate(inode);

			sb_end_intwrite(inode->i_sb);

			spin_lock(&inode->i_lock);
			atomic_dec(&inode->i_count);
		}
		trace_f2fs_drop_inode(inode, 0);
		return 0;
	}
	ret = generic_drop_inode(inode);
	if (!ret)
		ret = fscrypt_drop_inode(inode);
	trace_f2fs_drop_inode(inode, ret);

읽기 기준: f2fs_drop_inode()가 writeback→GC→evict 가능성을 피하려는 경로다. 주석의 f2fs_write_data_page는 호출 사슬 설명이며, 이 상자가 data writeback 구현은 아니다.

f2fs_write_data_page() page wrapper

고정 원문: fs/f2fs/data.c:2993–3013
static int f2fs_write_data_page(struct page *page,
					struct writeback_control *wbc)
{
#ifdef CONFIG_F2FS_FS_COMPRESSION
	struct inode *inode = page->mapping->host;

	if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
		goto out;

	if (f2fs_compressed_file(inode)) {
		if (f2fs_is_compressed_cluster(inode, page->index)) {
			redirty_page_for_writepage(wbc, page);
			return AOP_WRITEPAGE_ACTIVATE;
		}
	}
out:
#endif

	return f2fs_write_single_data_page(page, NULL, NULL, NULL,
						wbc, FS_DATA_IO, 0, true);
}

읽기 기준: 이 wrapper는 compression/CP 오류 조건을 거쳐 f2fs_write_single_data_page로 넘긴다. 여기서 곧바로 OPU가 확정되지는 않는다.

mount·data writeback·GC를 각각 추적

기존 글은 f2fs_fill_super → f2fs_write_data_page를 고정 호출 체인처럼 그렸다. 실제로는 mount가 metadata 기준을 마련하고, 나중의 writeback과 GC가 각 조건에서 실행된다. v6.18.37 비교 발췌는 page wrapper가 아니라 folio 기반 cache-pages dispatch를 다룬다.

그림 2. 서로 다른 세 실행 경로
Mount
f2fs_fill_supersuper·options 확인
valid CPf2fs_get_valid_checkpoint
segment managerf2fs_build_segment_manager
node managerf2fs_build_node_manager
Writeback
f2fs_write_data_page(page)대상 page 준비
single dataf2fs_write_single_data_page
data mappingf2fs_do_write_data_page
IPU 또는 OPU조건에 따라 제자리·새 위치 쓰기
GC
f2fs_gc공간·checkpoint 오류 확인
victim 선택__get_victim
valid 판정SIT/summary와 참조 확인
live data 이동gc_data_segment 등

세 줄은 하나의 강제 호출 체인이 아니다. 쓰기 중 공간 부족이 GC를 유발할 수 있으나 모든 write가 GC를 호출하거나 모든 write가 OPU가 되는 것은 아니다.

fs/f2fs/super.c:4500–4504 · fs/f2fs/data.c:2698–2808 · fs/f2fs/gc.c:1797–1862

경로입력·결정성공/분기대표 발췌의 증거 범위
mountsuperblock, 옵션, CP 유효성CP 후 segment/node manager 구성첫 코드 상자는 sbi 할당·lock 초기화까지; 이후 CP/manager는 링크 원문
writebackdirty page, inode, writeback_controlf2fs_do_write_data_page의 need_inplace_update에 따라 IPU/OPU새 세 번째 코드 상자는 버전별 wrapper 또는 cache-pages dispatch
GCfree section 압박·victim 선택·valid bitmap유효 data를 확인·이동; 필요한 경우 CP 호출두 번째 기존 상자는 GC 구현이 아니라 drop_inode의 교착 회피

메모리 객체와 디스크 metadata의 연결

segment manager는 유효 block·free/dirty segment 상태를, node manager는 NAT 기반 node 위치를 관리한다. CP는 이 정보를 다시 읽을 때의 복구 기준이다. 이것들은 동일한 단일 구조체나 한 개의 순차 호출이 아니다.

그림 3. 메모리의 sbi와 디스크 metadata가 맡는 역할
f2fs_sb_inforaw_super와 ckpt를 가리키고 sm_info·nm_info manager를 보유한다.
data 위치를 찾는 관계inode의 node가 data block 주소를 보유한다. NAT는 node ID를 node block 위치로 잇는다.
유효성과 ownerSIT는 segment의 유효 block 수·bitmap, SSA는 저장 block의 owner summary를 제공한다. GC가 이를 사용해 live data를 판정한다.

CP가 가리키는 NAT/SIT 사본을 기준으로 복구를 시작한다. 메모리의 최근 쓰기 상태와 디스크에 안정적으로 확정된 CP를 같은 시점으로 취급하지 않는다.

대상담당 정보이 글의 읽기 기준
f2fs_sb_inforaw super·checkpoint·manager 포인터mount가 초기화·해제하는 메모리 객체
CP유효 NAT/SIT copy 선택 등 복구 기준mount의 f2fs_get_valid_checkpoint 이후 판단
NAT / nodeNAT는 nid→node block; node는 data mapping데이터 주소만으로 node 위치를 추론하지 않음
SIT / SSAsegment 유효성 / block owner summaryGC는 invalid block을 단순 이동하지 않음

fs/f2fs/f2fs.h:1520–1580 · Documentation/filesystems/f2fs.rst:543–565

실패 위치는 mount·writeback·GC마다 다르다

F2FS가 segment cleaning을 한다고 해서 segment를 즉시 통째로 free하는 것은 아니다. GC는 victim의 live block을 확인·이동하고, checkpoint와 free 상태 반영은 별도 조건이다. 아래 표는 고정 소스의 실제 분기를 기준으로 읽는다.

그림 4. 각 경로의 오류 분기 위치
Mount 중단kzalloc 실패는 -ENOMEM 즉시 반환. raw super 실패는 free_sbi, valid CP 실패는 free_meta_inode로 간다. manager 구축 뒤 실패는 free_sm/free_nm 경계를 확인한다.
Writeback 분기f2fs_cp_error나 SBI_POR_DOING은 일반 data 제출과 다른 경로로 간다. -EAGAIN 재시도·redirty·return 조건은 data.c의 해당 버전 함수에서 확인한다.
GC 중단·전환SB_ACTIVE가 아니면 -EINVAL, CP 오류면 -EIO. free section 부족 시 FG_GC로 바꾸고 prefree segment가 있으면 checkpoint를 요청할 수 있다.

위 label은 각 함수의 실제 분기 이름이다. 세 경로를 한 번에 되돌리는 공통 rollback 순서로 읽지 않는다.

경로·조건고정 소스의 분기오해하지 않을 것
mount: f2fs_get_valid_checkpoint 실패goto free_meta_inodeCP 선택 실패를 빈 새 FS 생성으로 읽지 않음
mount: segment/node manager 실패goto free_sm / goto free_nm이미 확보한 객체 범위가 다름
writeback: CP 오류 또는 recovery 중f2fs_cp_error / SBI_POR_DOING모든 dirty data가 disk에 쓰였다고 단정하지 않음
writeback: IPU 조건 / 그 밖의 OPUneed_inplace_update·f2fs_outplace_write_data모든 쓰기가 새 segment append가 아님
GC: 유효성·공간__get_victim 뒤 valid map 검사victim segment의 모든 block을 옮기지 않음

fs/f2fs/super.c:4500–4573 · fs/f2fs/data.c:2698–2808 · fs/f2fs/gc.c:1797–1857

복구 지점과 쓰기 결과를 혼동하지 않기

Mount

유효 CP 선택과 manager 구성에 실패하면 함수의 해당 goto 정리 경로로 간다. 초기 sbi 할당만으로 mount 완료가 아니다.

Writeback

page/folio가 dirty였다는 사실, IO 제출, IO 완료, fsync/checkpoint 이후 복구 가능 상태는 서로 다른 단계다. IPU/OPU 선택도 조건부다.

GC

SIT/summary와 상위 참조를 확인한 live data만 이동한다. cleaning을 단순 free 호출로, FTL 내부 GC와 같은 정책으로 취급하지 않는다.

drop_inode 주석

두 번째 대표 발췌는 writeback→GC→evict 가능성 때문에 I_SYNC inode를 다루는 보호 경로다. 실제 data writeback 함수 정의와 구분한다.

읽기 전용으로 범위를 좁혀 관찰

먼저 mount 여부, 준비된 debugfs 통계, 노출된 F2FS trace event 목록을 읽어 어떤 경로를 조사할지 정한다. 경로와 항목은 커널 설정과 mount 상태에 따라 없을 수 있다. 공용 tracefs의 tracer·filter를 예제로 변경하지 않는다.

확인할 가설읽기 전용 관찰한계
mount된 F2FS·옵션cat /proc/mounts, 존재할 때 ls /sys/fs/f2fs장치별 설정·실제 writeback 성공을 증명하지 않음
segment·SIT 현황debugfs가 이미 준비돼 있으면 cat /sys/kernel/debug/f2fs/status순간 통계이며 CP durability 증거가 아님
이용 가능한 F2FS eventtracefs가 이미 준비돼 있으면 grep '^f2fs:' /sys/kernel/tracing/available_eventsevent 존재만 확인; 활성화·기록은 하지 않음
원문 분기선택한 태그의 super.c·data.c·gc.c와 오류 로그 대조실기 mount/write/GC 시험은 별도 절차

Documentation/filesystems/f2fs.rst:372–389 · fs/f2fs/gc.c:1797–1820

선택한 워크로드에서 확인할 질문

  • 해당 mount에서 어떤 CP pack이 선택되고 segment/node manager 구축 중 어떤 오류 label까지 도달했는가?
  • 실제 data writeback은 page(v6.6)와 folio(v6.18.37) 중 어느 경로이며 IPU·OPU의 어느 조건을 만족했는가?
  • GC가 실행됐다면 victim의 어떤 block이 valid로 판정돼 이동했으며 free section·checkpoint 조건은 무엇이었는가?
  • drop_inode 발췌의 I_SYNC 보호는 writeback→GC→evict 가능성과 어떻게 연결되는가?
  • 관찰한 write 제출을 fsync/checkpoint 뒤의 복구 가능 상태와 혼동하지 않았는가?