Linux v6.6 · 개념과 코드 읽기

reclaim: 버릴 수 있는 페이지와 먼저 써야 할 페이지 구분하기

이 코드는 어떤 문제를 푸나요?

빈 페이지가 부족하다고 아무 페이지나 없앨 수는 없습니다. 파일과 같은 내용이면 버렸다가 다시 읽을 수 있지만, 수정한 내용은 저장하지 않고 버리면 사라집니다. 회수 코드는 dirty와 writeback 상태를 확인해 즉시 회수할지, 쓰기를 진행하거나 기다릴지 판단합니다.

읽을 범위: v6.6 · mm/vmscan.c · folio_check_dirty_writeback 1582–1612행입니다. 아래에 이 범위의 원문과 각 줄의 설명을 실었습니다. 주제 전체의 흐름과 다른 경로는 기존 분석에서 함께 읽으실 수 있습니다.

먼저 알아둘 개념

dirty와 writeback

dirty는 저장 대상보다 메모리 내용이 수정되었다는 상태이고 writeback은 쓰기가 진행 중이라는 상태입니다. 둘은 같은 비트도, 같은 시점도 아닙니다.

folio

한 개 이상의 페이지를 묶어 관리하는 단위입니다. 회수 코드의 한 folio를 언제나 4 KiB 한 장이라고 가정하면 큰 folio에서 틀립니다.

익명 메모리와 파일 캐시

익명 메모리는 파일 캐시의 flusher 경로와 같은 방식으로 처리되지 않습니다. 같은 LRU 분류에 놓일 수 있어도 실제 folio 종류를 다시 확인해야 합니다.

처음 읽을 때

깨끗한 파일 캐시, 수정된 파일 캐시, 쓰는 중인 파일 캐시의 세 상태를 비교하세요. 아래 함수는 회수 자체가 아니라 그 결정을 위한 상태 정보를 제공합니다.

더 깊이 살펴볼 때

MADV_FREE 익명 folio가 file LRU에 있어도 왜 추가 검사가 필요한지, filesystem의 is_dirty_writeback 콜백이 공통 flag 판단을 보완하는 이유를 살펴보세요.

그림으로 보는 변화

reclaim: 버릴 수 있는 페이지와 먼저 써야 할 페이지 구분하기의 단계별 개념 그림
각 단계에 화살표 의미와 생략 범위를 표시했습니다. 주소·숫자 예제는 실제 장치 값을 뜻하지 않습니다.
1단계 설명

1단계 고정

GIF 원본 열기

1. 회수 후보 조사

folio 종류와 LRU 분류 확인

화살표는 상태 조사 순서입니다. 모든 후보를 같은 쓰기 경로로 보내지 않습니다.

2. 일반 상태 읽기

dirty / writeback flag

dirty와 writeback은 별도 출력입니다. 두 상태를 하나의 사용 중 표시로 합치지 않습니다.

3. 파일 시스템 정보 보완

필요하면 is_dirty_writeback 호출

화살표는 공통 정보에서 파일 시스템별 판단으로 보완하는 흐름입니다. 이 함수에서 쓰기를 시작한다는 뜻은 아닙니다.

folio_check_dirty_writeback를 한 줄씩 읽기

줄 번호는 v6.6 원문 기준입니다. 주석·빈 줄을 포함한 함수 전체를 먼저 보고, 그 아래에서 각 줄을 설명합니다.

static void folio_check_dirty_writeback(struct folio *folio,
				       bool *dirty, bool *writeback)
{
	struct address_space *mapping;

	/*
	 * Anonymous folios are not handled by flushers and must be written
	 * from reclaim context. Do not stall reclaim based on them.
	 * MADV_FREE anonymous folios are put into inactive file list too.
	 * They could be mistakenly treated as file lru. So further anon
	 * test is needed.
	 */
	if (!folio_is_file_lru(folio) ||
	    (folio_test_anon(folio) && !folio_test_swapbacked(folio))) {
		*dirty = false;
		*writeback = false;
		return;
	}

	/* By default assume that the folio flags are accurate */
	*dirty = folio_test_dirty(folio);
	*writeback = folio_test_writeback(folio);

	/* Verify dirty/writeback state if the filesystem supports it */
	if (!folio_test_private(folio))
		return;

	mapping = folio_mapping(folio);
	if (mapping && mapping->a_ops->is_dirty_writeback)
		mapping->a_ops->is_dirty_writeback(folio, dirty, writeback);
}
static void folio_check_dirty_writeback(struct folio *folio,

회수 후보 folio의 쓰기 관련 상태를 조사하는 함수입니다. 이 함수 자체는 folio를 해제하지 않습니다.

				       bool *dirty, bool *writeback)

dirty와 writeback은 호출자가 제공한 출력 변수의 주소입니다. 별개의 두 상태를 수정해 돌려줍니다.

	struct address_space *mapping;

파일 캐시와 연결된 address_space를 나중에 조회하기 위한 변수를 준비합니다.

	if (!folio_is_file_lru(folio) ||

file LRU 대상이 아닌 folio인지 먼저 봅니다. 일반 익명 folio를 파일 flusher에 따른 지연 대상으로 취급하지 않으려는 검사입니다.

	    (folio_test_anon(folio) && !folio_test_swapbacked(folio))) {

file LRU에 있더라도 익명이고 swapbacked가 아닌 MADV_FREE 유형 등을 따로 거릅니다. 목록 이름만으로 실제 종류를 단정하지 않습니다.

		*dirty = false;

이 조사 결과에서는 dirty에 따른 파일 쓰기 대기 대상으로 표시하지 않습니다. folio 자체의 dirty 비트를 지우는 줄은 아닙니다.

		*writeback = false;

writeback 출력도 false로 설정합니다. 출력 변수와 folio 메타데이터의 비트를 구별하셔야 합니다.

		return;

파일 쓰기 상태 조사를 더 하지 않고 반환합니다.

	*dirty = folio_test_dirty(folio);

일반 경로에서는 folio의 dirty 비트를 기본 결과로 읽습니다.

	*writeback = folio_test_writeback(folio);

writeback 비트도 별도로 읽습니다. 수정됨과 쓰기 진행 중을 각각 표현합니다.

	if (!folio_test_private(folio))

파일 시스템의 부가 private 정보가 없는 folio인지 확인합니다.

		return;

추가 정보가 없다면 앞에서 읽은 기본 flag 결과로 조사를 마칩니다.

	mapping = folio_mapping(folio);

folio가 속한 파일 매핑 정보를 얻습니다. 이후 filesystem 동작 함수를 찾는 연결점입니다.

	if (mapping && mapping->a_ops->is_dirty_writeback)

매핑과 파일 시스템의 보완 콜백이 모두 존재하는지 확인합니다. NULL을 무조건 호출하지 않도록 합니다.

		mapping->a_ops->is_dirty_writeback(folio, dirty, writeback);

파일 시스템이 판단한 dirty와 writeback 상태를 출력 변수에 반영하도록 합니다. 예를 들어 부가 버퍼 상태를 함께 고려할 수 있습니다.

함께 생각해 볼 질문

dirty가 false이면 곧바로 free할 수 있나요?

이 정보만으로 결정할 수 없습니다. 참조, 매핑, 잠금, writeback 등 회수 경로의 다른 조건도 충족해야 합니다.

익명 folio에 dirty=false를 쓰는 것은 내용이 저장됐다는 뜻인가요?

아닙니다. 이 함수는 file flusher에 따른 회수 지연 판단을 위한 결과를 돌려줍니다. 익명 메모리의 실제 내용 저장 상태와 혼동하시면 안 됩니다.

출력 인자가 bool 포인터인 이유는 무엇인가요?

dirty와 writeback 두 결과를 호출자 변수에 기록하려는 방식입니다. 함수 반환형은 void입니다.

출처와 읽은 범위

Linux stable v6.6 · mm/vmscan.c

해당 버전 원본 파일 · 기존 코드 분석 · 설명 원고

맨 위로 ↑