이 코드는 어떤 문제를 푸나요?
빈 페이지가 부족하다고 아무 페이지나 없앨 수는 없습니다. 파일과 같은 내용이면 버렸다가 다시 읽을 수 있지만, 수정한 내용은 저장하지 않고 버리면 사라집니다. 회수 코드는 dirty와 writeback 상태를 확인해 즉시 회수할지, 쓰기를 진행하거나 기다릴지 판단합니다.
읽을 범위: v6.18.37 · mm/vmscan.c · folio_check_dirty_writeback 979–1009행입니다. 아래에 이 범위의 원문과 각 줄의 설명을 실었습니다. 주제 전체의 흐름과 다른 경로는 기존 분석에서 함께 읽으실 수 있습니다.
먼저 알아둘 개념
dirty와 writeback
dirty는 저장 대상보다 메모리 내용이 수정되었다는 상태이고 writeback은 쓰기가 진행 중이라는 상태입니다. 둘은 같은 비트도, 같은 시점도 아닙니다.
folio
한 개 이상의 페이지를 묶어 관리하는 단위입니다. 회수 코드의 한 folio를 언제나 4 KiB 한 장이라고 가정하면 큰 folio에서 틀립니다.
익명 메모리와 파일 캐시
익명 메모리는 파일 캐시의 flusher 경로와 같은 방식으로 처리되지 않습니다. 같은 LRU 분류에 놓일 수 있어도 실제 folio 종류를 다시 확인해야 합니다.
처음 읽을 때
깨끗한 파일 캐시, 수정된 파일 캐시, 쓰는 중인 파일 캐시의 세 상태를 비교하세요. 아래 함수는 회수 자체가 아니라 그 결정을 위한 상태 정보를 제공합니다.
더 깊이 살펴볼 때
MADV_FREE 익명 folio가 file LRU에 있어도 왜 추가 검사가 필요한지, filesystem의 is_dirty_writeback 콜백이 공통 flag 판단을 보완하는 이유를 살펴보세요.
그림으로 보는 변화
!folio_is_file_lru(folio) 또는 folio_test_anon(folio) && !folio_test_swapbacked(folio)*dirty=false, *writeback=false를 출력하고 반환합니다. 이 경로는 folio의 두 상태 비트를 읽지 않으며 비트를 지우지도 않습니다.
folio_test_dirty()와 folio_test_writeback()을 각각 출력에 저장합니다.
!folio_test_private()면 반환합니다. private 정보가 있으면 mapping과 is_dirty_writeback 콜백이 모두 있을 때만 출력값을 추가 검증합니다.
화살표 없는 두 칸은 대안 분기입니다. 이 함수는 쓰기를 시작하거나 folio를 해제하지 않습니다. 근거: Linux v6.18.37 mm/vmscan.c:979–1009.
| 경로 | dirty / writeback 출력 | 다음 동작 |
|---|---|---|
| 첫 조건 참 | false / false | 비트 조회와 filesystem 콜백 없이 반환 |
| 첫 조건 거짓 · private 없음 | 각 folio 비트 값 | 그대로 반환 |
| private 있음 · mapping/콜백 없음 | 각 folio 비트 값 | 콜백 없이 반환 |
| private 있음 · mapping과 콜백 있음 | 기본 비트 값을 먼저 읽고 콜백이 보완 가능 | is_dirty_writeback 호출 뒤 반환 |

1. 회수 후보 조사
folio 종류와 LRU 분류 확인
화살표는 상태 조사 순서입니다. 모든 후보를 같은 쓰기 경로로 보내지 않습니다.
2. 일반 상태 읽기
dirty / writeback flag
dirty와 writeback은 별도 출력입니다. 두 상태를 하나의 사용 중 표시로 합치지 않습니다.
3. 파일 시스템 정보 보완
필요하면 is_dirty_writeback 호출
화살표는 공통 정보에서 파일 시스템별 판단으로 보완하는 흐름입니다. 이 함수에서 쓰기를 시작한다는 뜻은 아닙니다.
folio_check_dirty_writeback를 한 줄씩 읽기
줄 번호는 v6.18.37 원문 기준입니다. 주석·빈 줄을 포함한 함수 전체를 먼저 보고, 그 아래에서 각 줄을 설명합니다.
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.18.37 · mm/vmscan.c
해당 버전 원본 파일 · 기존 코드 분석 · 설명 원고
