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

v6.6 / mm/vmscan.c

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

## folio_check_dirty_writeback

```c

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);
}

```

### 1582행

```c

static void folio_check_dirty_writeback(struct folio *folio,

```

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

### 1583행

```c

				       bool *dirty, bool *writeback)

```

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

### 1585행

```c

	struct address_space *mapping;

```

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

### 1594행

```c

	if (!folio_is_file_lru(folio) ||

```

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

### 1595행

```c

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

```

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

### 1596행

```c

		*dirty = false;

```

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

### 1597행

```c

		*writeback = false;

```

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

### 1598행

```c

		return;

```

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

### 1602행

```c

	*dirty = folio_test_dirty(folio);

```

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

### 1603행

```c

	*writeback = folio_test_writeback(folio);

```

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

### 1606행

```c

	if (!folio_test_private(folio))

```

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

### 1607행

```c

		return;

```

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

### 1609행

```c

	mapping = folio_mapping(folio);

```

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

### 1610행

```c

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

```

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

### 1611행

```c

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

```

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

