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

독자가 빠져나왔는지 추적할 기반을 만듭니다

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

RCU는 읽는 쪽의 부담을 줄이는 대신, 예전 객체를 볼 수 있는 독자가 끝난 뒤에 회수하도록 시간을 나눕니다. rcu_init은 CPU별 상태와 트리, 콜백 처리 기반을 준비합니다. 초기화 함수 안에서 한 객체를 바로 해제하는 예제는 아닙니다.

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

먼저 알아둘 개념

유예 기간

기존 독자들이 더 이상 예전 객체를 참조하지 않음을 확인하기 위해 기다리는 구간입니다.

콜백

유예 기간 뒤에 실행하도록 넘긴 작업입니다. 단순한 타이머 지연과는 보장하는 조건이 다릅니다.

처음 읽을 때

코드를 읽을 때 CPU들을 묶는 RCU 트리와 전역 상태를 준비합니다. 그다음 어느 상태가 바뀌는지 각 줄에서 확인하세요.

더 깊이 살펴볼 때

이 경로의 호출 문맥, 잠금·인터럽트 상태, 오류 시 남는 자원을 함께 추적해 보세요. 호출된 함수가 수행하는 작업과 현재 함수가 직접 보장하는 범위를 구분하는 것이 중요합니다.

그림으로 보는 변화

독자가 빠져나왔는지 추적할 기반을 만듭니다의 단계별 개념 그림
각 단계에 화살표 의미와 생략 범위를 표시했습니다. 주소·숫자 예제는 실제 장치 값을 뜻하지 않습니다.
1단계 설명

1단계 고정

GIF 원본 열기

1. 트리와 기본 상태

CPU들을 묶는 RCU 트리와 전역 상태를 준비합니다.

화살표는 초기화 순서입니다.

2. 부트 CPU 연결

현재 CPU를 준비·시작·온라인 단계에 등록합니다.

현재 CPU 번호와 트리 노드 주소는 다릅니다.

3. 후속 처리 기반

작업 큐·콜백과 테스트를 준비합니다.

초기화 완료가 모든 종류의 RCU 독자 종료를 뜻하지 않습니다.

rcu_init를 한 줄씩 읽기

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

void __init rcu_init(void)
{
	int cpu = smp_processor_id();

	rcu_early_boot_tests();

	kfree_rcu_batch_init();
	rcu_bootup_announce();
	sanitize_kthread_prio();
	rcu_init_geometry();
	rcu_init_one();
	if (dump_tree)
		rcu_dump_rcu_node_tree();
	if (use_softirq)
		open_softirq(RCU_SOFTIRQ, rcu_core_si);

	/*
	 * We don't need protection against CPU-hotplug here because
	 * this is called early in boot, before either interrupts
	 * or the scheduler are operational.
	 */
	pm_notifier(rcu_pm_notify, 0);
	WARN_ON(num_online_cpus() > 1); // Only one CPU this early in boot.
	rcutree_prepare_cpu(cpu);
	rcu_cpu_starting(cpu);
	rcutree_online_cpu(cpu);

	/* Create workqueue for Tree SRCU and for expedited GPs. */
	rcu_gp_wq = alloc_workqueue("rcu_gp", WQ_MEM_RECLAIM, 0);
	WARN_ON(!rcu_gp_wq);
	rcu_alloc_par_gp_wq();

	/* Fill in default value for rcutree.qovld boot parameter. */
	/* -After- the rcu_node ->lock fields are initialized! */
	if (qovld < 0)
		qovld_calc = DEFAULT_RCU_QOVLD_MULT * qhimark;
	else
		qovld_calc = qovld;

	// Kick-start in case any polled grace periods started early.
	(void)start_poll_synchronize_rcu_expedited();

	rcu_test_sync_prims();
}
void __init rcu_init(void)

RCU가 CPU들의 읽기 구간 종료를 추적하고 지연된 콜백을 처리할 전역·CPU별 상태를 마련합니다. 독자가 끝나기 전에 공유 객체를 회수하지 않도록 하는 기반입니다.

	int cpu = smp_processor_id();

RCU 초기 상태를 설정할 현재 부트 CPU 번호를 얻습니다. 이 시점에는 아래 검사처럼 여러 CPU가 이미 온라인인 상황을 예상하지 않습니다.

	rcu_early_boot_tests();

RCU의 이른 부팅 테스트를 실행해 초기 상태의 동작을 점검합니다.

	kfree_rcu_batch_init();

유예 기간 뒤 객체 회수를 묶어 처리할 kfree_rcu 배치 기반을 준비합니다.

	rcu_bootup_announce();

사용할 RCU 구성과 주요 설정을 부팅 로그에 알립니다.

	sanitize_kthread_prio();

RCU 커널 스레드 우선순위 설정이 사용할 수 있는 범위에 있는지 정리합니다.

	rcu_init_geometry();

CPU들을 추적할 RCU 노드 트리의 크기와 구조를 정합니다.

	rcu_init_one();

RCU 전역 상태와 노드 구조를 초기화합니다.

	if (dump_tree)

RCU 트리 진단 출력이 요청된 경우에만 아래 출력을 수행합니다.

		rcu_dump_rcu_node_tree();

요청된 경우 구성한 RCU 노드 트리를 진단용으로 출력합니다.

	if (use_softirq)

RCU 핵심 처리를 softirq로 수행하는 구성이면 해당 핸들러를 연결합니다.

		open_softirq(RCU_SOFTIRQ, rcu_core_si);

지정 softirq 번호에 RCU 처리 함수를 연결합니다.

	pm_notifier(rcu_pm_notify, 0);

절전·복귀 상태 변화에 대응할 RCU 통지 함수를 등록합니다.

	WARN_ON(num_online_cpus() > 1); // Only one CPU this early in boot.

RCU 트리를 준비하는 이른 부팅 단계에서 온라인 CPU가 둘 이상이면 경고합니다. 아래의 CPU별 초기 등록이 부트 CPU부터 시작된다는 순서 조건을 확인합니다.

	rcutree_prepare_cpu(cpu);

해당 CPU의 RCU 자료구조를 준비합니다.

	rcu_cpu_starting(cpu);

현재 CPU가 시작하는 상태를 RCU에 알립니다. 이 버전의 함수 이름과 호출 위치를 기준으로 읽습니다.

	rcutree_online_cpu(cpu);

해당 CPU를 RCU의 온라인 추적에 반영합니다.

	rcu_gp_wq = alloc_workqueue("rcu_gp", WQ_MEM_RECLAIM, 0);

Tree SRCU와 expedited grace period 처리를 위한 작업 큐를 만듭니다. grace period는 기존 독자의 읽기 구간이 끝나기를 기다리는 기간입니다. v6.6에서는 WQ_UNBOUND를 주지 않으면 CPU에 묶이는 방식이며, WQ_MEM_RECLAIM은 메모리 부족 때도 실행 문맥을 확보하게 합니다. 마지막 0은 동시 실행 한도에 기본값을 쓰라는 뜻입니다.

	WARN_ON(!rcu_gp_wq);

유예 기간의 후속 작업을 맡길 rcu_gp 작업 큐 생성이 실패했는지 확인합니다. NULL 큐로 정상 후속 처리를 진행할 수 없다는 진단입니다.

	rcu_alloc_par_gp_wq();

병렬 유예 기간 처리에 사용할 작업 큐 기반을 준비합니다.

	if (qovld < 0)

콜백 과부하 임계값을 사용자가 따로 지정하지 않은 경우인지 검사합니다.

		qovld_calc = DEFAULT_RCU_QOVLD_MULT * qhimark;

콜백 큐의 높은 수위 기준에 기본 배수를 적용해 과부하 임계값을 계산합니다.

	else

앞 조건이 성립하지 않은 경로를 선택합니다. 앞쪽 처리와 아래 처리를 모두 수행하는 것이 아닙니다.

		qovld_calc = qovld;

사용자가 지정한 과부하 임계값을 그대로 사용합니다.

	(void)start_poll_synchronize_rcu_expedited();

완료 여부를 나중에 확인할 수 있는 expedited 유예 기간 요청을 시작합니다.

	rcu_test_sync_prims();

RCU 동기화 기본 동작의 초기 테스트를 수행합니다.

함께 생각해 볼 질문

일정 시간만 기다리면 RCU 유예 기간인가요?

아닙니다. RCU가 요구하는 독자 종료 상태를 확인해야 합니다.

왜 부트 CPU부터 준비하나요?

이 시점의 CPU 온라인 상태와 후속 SMP 초기화 순서에 맞춰야 하기 때문입니다.

RCU 읽기 잠금이 mutex처럼 독자를 막나요?

일반적인 RCU 읽기 경로는 mutex와 역할과 비용이 다릅니다. 객체 수명과 업데이트 규칙을 함께 읽어야 합니다.

출처와 읽은 범위

Linux stable v6.6 · kernel/rcu/tree.c

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

맨 위로 ↑