# 페이지 캐시: 메모리 한 묶음이 파일의 일부가 되려면

v6.6 / mm/filemap.c

페이지 캐시는 파일 내용을 메모리에 보관해 반복 읽기의 저장장치 접근을 줄입니다. folio를 할당한 뒤에는 어느 파일의 어느 위치인지 연결하고 회수 대상 목록에도 넣어야 합니다. v6.6의 filemap_add_folio는 folio 잠금을 표시한 뒤 하위 삽입 함수에 등록을 맡기고, 성공하면 최근 재접근 이력과 LRU를 갱신합니다. 하위 함수가 수행하는 메모리 비용 청구와 현재 함수의 책임을 구분합니다.

## filemap_add_folio

```c

int filemap_add_folio(struct address_space *mapping, struct folio *folio,
				pgoff_t index, gfp_t gfp)
{
	void *shadow = NULL;
	int ret;

	__folio_set_locked(folio);
	ret = __filemap_add_folio(mapping, folio, index, gfp, &shadow);
	if (unlikely(ret))
		__folio_clear_locked(folio);
	else {
		/*
		 * The folio might have been evicted from cache only
		 * recently, in which case it should be activated like
		 * any other repeatedly accessed folio.
		 * The exception is folios getting rewritten; evicting other
		 * data from the working set, only to cache data that will
		 * get overwritten with something else, is a waste of memory.
		 */
		WARN_ON_ONCE(folio_test_active(folio));
		if (!(gfp & __GFP_WRITE) && shadow)
			workingset_refault(folio, shadow);
		folio_add_lru(folio);
	}
	return ret;
}

```

### 932행

```c

int filemap_add_folio(struct address_space *mapping, struct folio *folio,

```

파일의 mapping과 등록할 folio를 받습니다. 이 함수는 데이터를 읽는 것보다 캐시 등록 절차에 초점을 둡니다.

### 933행

```c

				pgoff_t index, gfp_t gfp)

```

파일 내 페이지 인덱스와 메모리 할당·회수 정책을 나타내는 gfp 플래그를 추가로 받습니다.

### 935행

```c

	void *shadow = NULL;

```

해당 위치의 과거 회수 이력이 없다는 초기값으로 shadow를 준비합니다.

### 936행

```c

	int ret;

```

단계별 실패 코드를 담을 변수입니다.

### 938행

```c

	__folio_set_locked(folio);

```

새 folio를 잠긴 상태로 표시하여 등록과 데이터 준비 동안의 접근 규칙을 세웁니다.

### 939행

```c

	ret = __filemap_add_folio(mapping, folio, index, gfp, &shadow);

```

하위 __filemap_add_folio에 삽입을 맡깁니다. v6.6에서는 일반 folio의 memcg 청구와 삽입 실패 정리가 이 하위 함수 안에 있습니다.

### 940행

```c

	if (unlikely(ret))

```

하위 삽입 함수가 오류를 반환했는지 검사합니다. unlikely는 빈도 힌트이며 실패의 의미를 바꾸지 않습니다.

### 941행

```c

		__folio_clear_locked(folio);

```

삽입에 실패했으므로 이 함수가 설정한 folio 잠금 비트를 되돌립니다. 하위 함수가 맡은 청구 정리와 역할을 나눕니다.

### 942행

```c

	else {

```

삽입에 성공한 경우에만 최근 회수 이력과 LRU 등록을 처리합니다.

### 951행

```c

		WARN_ON_ONCE(folio_test_active(folio));

```

아직 활성 상태가 아니어야 하는 새 캐시 folio에 잘못된 active 표시가 있는지 경고합니다.

### 952행

```c

		if (!(gfp & __GFP_WRITE) && shadow)

```

덮어쓰기를 위한 할당이 아니면서 과거 회수 흔적이 있는 경우인지 검사합니다.

### 953행

```c

			workingset_refault(folio, shadow);

```

최근에 쫓겨났다가 다시 필요해진 데이터를 working set 판단에 반영합니다.

### 954행

```c

		folio_add_lru(folio);

```

folio를 LRU 관리에 추가하여 이후 메모리 회수 정책이 추적할 수 있게 합니다.

### 956행

```c

	return ret;

```

등록 성공 0 또는 삽입 오류를 반환합니다.

