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

compaction: 연속 빈 공간을 만들되 실패를 무한 반복하지 않기

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

빈 페이지 수가 충분해도 고차 order의 연속 블록은 없을 수 있습니다. compaction은 이동 가능한 페이지를 옮겨 빈 공간을 모읍니다. 하지만 이동할 수 없는 페이지가 막고 있다면 같은 시도를 계속하는 데 비용만 들 수 있어 재시도를 잠시 미루기도 합니다.

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

먼저 알아둘 개념

외부 단편화

총 빈 용량은 충분하지만 요청한 크기의 연속 구간이 없는 상태입니다. 회수로 빈 페이지 수를 늘리는 것과 compaction으로 배치를 바꾸는 것은 다른 일입니다.

defer shift

재시도 간격의 기준을 2의 거듭제곱으로 만드는 값입니다. 시간 단위 sleep 길이가 아니라 판단 횟수를 기반으로 한 지연입니다.

order별 지연 대상 경계

compact_order_failed는 이번 요청을 지연 대상으로 검사할지 가르는 경계값입니다. 실패 경로와 성공 경로에서 갱신될 수 있으므로 단순히 마지막 실패 order로 읽으면 안 됩니다.

처음 읽을 때

8페이지 중 빈 곳이 짝수 위치에만 있는 예를 그려 보세요. 빈 페이지 4개와 연속 4페이지 블록 1개가 다르다는 것을 먼저 확인한 뒤 재시도 조건을 읽으시면 됩니다.

더 깊이 살펴볼 때

compaction_deferred의 true가 실패 결과가 아니라 이번 시도 생략 판단임을 구분하세요. compact_considered의 포화 처리와 order 비교가 서로 다른 목적을 갖습니다.

그림으로 보는 변화

한 번의 호출은 먼저 order를 가른 뒤, 지연 대상만 카운터를 검사합니다

compaction_deferred() 168–184행을 세 반환 경로로 펼쳤습니다. 아래 숫자 예시는 compact_defer_shift=3, compact_considered=0에서 시작하며 같은 zone을 반복 검사하고 사이에 상태 변경은 없다고 가정합니다.

shift 3 → 한도 1UL << 3 = 8판단 횟수 기준이며 8초 타이머가 아닙니다.
경로 A · 먼저 비교order < compact_order_failed

기록된 지연 대상 경계값보다 작은 요청은 false로 즉시 반환합니다. compact_considered는 증가하지 않습니다.

경로 B/C · 지연 대상order ≥ compact_order_failed → ++compact_considered

카운터를 먼저 올리고 한도 8과 비교합니다.

1–7 < 8 → true

앞의 일곱 검사에서 이번 compaction을 미룹니다.

8 ≥ 8 → false

여덟 번째에는 8로 고정하고 이 함수는 더 미루지 않습니다.

false의 범위: 이 함수의 지연 판단을 통과했다는 뜻입니다. 호출자의 다른 검사와 실제 compaction·페이지 할당 결과까지 보장하지 않습니다. true 역시 compaction의 성공·실패 결과가 아닙니다.

shift=3, 시작 카운터=0인 가상 반복 호출의 문턱
호출호출 전 → 비교값 → 반환 뒤반환해석
1–7번째 · 지연 대상 order0→1, …, 6→7true각 선증가 값이 8 미만이므로 이번 호출은 미룸
8번째 · 지연 대상 order7 → 8 → 8false8에 도달해 이 함수의 지연 해제
9번째 이후 · 상태 불변 가정8 → 9 → 8false증가 뒤 8로 다시 고정; 별도 리셋 전까지 같은 판단
별도 경로 · 더 작은 order기존 값 → 그대로falseorder 비교에서 조기 반환; 위 순차 호출에 포함하지 않음

앞서 실패를 기록하는 defer_compaction() 153–165행은 카운터를 0으로 돌리고 shift를 증가시키되 6에서 멈춥니다. 실제 호출자에는 우선순위 조건이나 watermark·적합성 검사도 있어 이 표의 숫자를 곧바로 실제 실행 횟수로 읽으면 안 됩니다.

기존 PNG/GIF의 2→3 아래 화살표는 지연 대상 order의 경로만 요약합니다. 더 작은 order는 위 경로 A에서 즉시 false를 반환하며 compact_considered를 증가시키지 않습니다.

compaction: 연속 빈 공간을 만들되 실패를 무한 반복하지 않기의 단계별 개념 그림
각 단계에 화살표 의미와 생략 범위를 표시했습니다. 주소·숫자 예제는 실제 장치 값을 뜻하지 않습니다.
1단계 설명

1단계 고정

GIF 원본 열기

1. 연속 블록 필요

빈 페이지 수와 연속성 별도 확인

화살표는 정책 판단 순서입니다. 실제 페이지 이동은 compact_zone 등의 다른 함수가 수행합니다.

2. 지연 대상 경계와 요청 크기 비교

경계값보다 작은 order는 카운터 증가 없이 통과

이 함수는 경계값보다 작은 요청을 미루지 않습니다.

3. 시도 횟수 기준으로 재시도

considered가 limit 미만이면 미루고 도달하면 허용

화살표는 호출 사이에 누적되는 카운터 변화를 뜻합니다. 이 함수 안에서 잠드는 타이머가 아닙니다.

compaction_deferred를 한 줄씩 읽기

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

static bool compaction_deferred(struct zone *zone, int order)
{
	unsigned long defer_limit = 1UL << zone->compact_defer_shift;

	if (order < zone->compact_order_failed)
		return false;

	/* Avoid possible overflow */
	if (++zone->compact_considered >= defer_limit) {
		zone->compact_considered = defer_limit;
		return false;
	}

	trace_mm_compaction_deferred(zone, order);

	return true;
}
static bool compaction_deferred(struct zone *zone, int order)

zone에서 해당 order 요청의 compaction을 이번에는 미룰지 판단합니다. 반환 true의 의미를 함수 이름과 함께 읽으셔야 합니다.

	unsigned long defer_limit = 1UL << zone->compact_defer_shift;

지연 shift에서 판단 횟수 한도를 계산합니다. shift=3이면 한도는 8입니다. 카운터 0에서 시작한 지연 대상 order는 1–7번째 검사에서 미루고, 8번째에는 미루지 않습니다. 8초를 뜻하지 않습니다.

	if (order < zone->compact_order_failed)

이번 요청이 기록된 지연 대상 경계값 compact_order_failed보다 작은지 봅니다. 이 값은 성공 경로에서도 갱신될 수 있습니다.

		return false;

경계값보다 작은 요청은 카운터를 올리지 않고 false를 반환합니다. 이 함수가 미루지 않는다는 뜻이며 실제 실행 여부는 호출자의 다른 조건에도 달려 있습니다.

	if (++zone->compact_considered >= defer_limit) {

고차 요청에 대해 검토 횟수를 하나 늘리고 한도에 도달했는지 확인합니다.

		zone->compact_considered = defer_limit;

한도에 도달한 카운터를 그 값에 고정하여 계속 증가할 때 발생할 수 있는 overflow를 피합니다.

		return false;

카운터가 한도에 도달했으므로 이 함수는 이번 compaction을 미루지 않습니다. 실제 실행·할당 성공을 확정하는 반환값은 아닙니다.

	trace_mm_compaction_deferred(zone, order);

이번 시도를 지연한 사실을 trace에 남겨 지연 정책의 영향을 관찰할 수 있게 합니다.

	return true;

이번에는 compaction을 생략하도록 true를 반환합니다. 실제 이동 성공 여부를 반환하는 함수가 아닙니다.

함께 생각해 볼 질문

compaction은 전체 빈 페이지 수를 늘리나요?

주목적은 이동을 통해 빈 공간을 연속으로 모으는 것입니다. 사용하지 않는 내용을 버려 공간을 얻는 reclaim과 구분합니다.

true를 반환하면 압축에 성공한 것인가요?

아닙니다. compaction_deferred의 true는 이번 compaction을 미루겠다는 뜻입니다.

작은 order에서 false를 즉시 반환하는 이유는 무엇인가요?

compact_order_failed보다 작은 요청은 이 함수의 지연 대상에서 제외됩니다. 조기 반환하므로 카운터도 증가하지 않습니다. 이 경계값은 성공 경로에서도 갱신될 수 있습니다.

출처와 읽은 범위

Linux stable v6.6 · mm/compaction.c

그림의 분기와 흐름 표현은 문C 블로그의 compaction, isolation, alloc_pages slowpath 글에서 확인한 관련 절·그림 구성을 참고했습니다. 세 글은 Linux v5.0 기준이며 전편을 정독한 것은 아닙니다. 위 v6.6 분기와 숫자는 보존된 v6.6 mm/compaction.c로 대조했고 문C 그림·본문을 복제하지 않았습니다.

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

맨 위로 ↑