이 코드는 어떤 문제를 푸나요?
lockdep은 관찰한 잠금 획득 순서를 이용해 모순된 의존 관계를 찾는 검사기입니다. 이름만 보고 lockdep_init 안에서 그래프 전체를 새로 할당한다고 생각하기 쉽지만, 이 버전의 함수는 주로 설정 한도와 메모리 사용량을 보고합니다. 실제 의존성 기록·검사는 별도 경로입니다.
읽을 범위: v6.18.37 · kernel/locking/lockdep.c · lockdep_init 6632–6669행입니다. 아래에 이 범위의 원문과 각 줄의 설명을 실었습니다. 주제 전체의 흐름과 다른 경로는 기존 분석에서 함께 읽으실 수 있습니다.
먼저 알아둘 개념
잠금 클래스
같은 역할의 잠금을 묶어 획득 순서를 분석하는 단위입니다.
의존성 사이클
A를 가진 채 B를 기다리는 흐름과 B를 가진 채 A를 기다리는 흐름이 함께 가능하면 교착 위험이 생깁니다.
처음 읽을 때
코드를 읽을 때 설정된 클래스·깊이·체인 한도를 출력합니다. 그다음 어느 상태가 바뀌는지 각 줄에서 확인하세요.
더 깊이 살펴볼 때
이 경로의 호출 문맥, 잠금·인터럽트 상태, 오류 시 남는 자원을 함께 추적해 보세요. 호출된 함수가 수행하는 작업과 현재 함수가 직접 보장하는 범위를 구분하는 것이 중요합니다.
그림으로 보는 변화

1. 검사기 준비 상태 확인
설정된 클래스·깊이·체인 한도를 출력합니다.
그림은 이 초기화 함수의 보고 순서입니다.
2. 자료구조 크기 집계
정적 배열과 조건부 구조의 sizeof를 합칩니다.
sizeof는 새 메모리 할당이 아닙니다.
3. 태스크별 비용 확인
각 태스크의 held_locks 기록 크기를 출력합니다.
이후 실행 중 잠금 획득을 검사하는 경로는 별도입니다.
lockdep_init를 한 줄씩 읽기
줄 번호는 v6.18.37 원문 기준입니다. 주석·빈 줄을 포함한 함수 전체를 먼저 보고, 그 아래에서 각 줄을 설명합니다.
void __init lockdep_init(void)
{
pr_info("Lock dependency validator: Copyright (c) 2006 Red Hat, Inc., Ingo Molnar\n");
pr_info("... MAX_LOCKDEP_SUBCLASSES: %lu\n", MAX_LOCKDEP_SUBCLASSES);
pr_info("... MAX_LOCK_DEPTH: %lu\n", MAX_LOCK_DEPTH);
pr_info("... MAX_LOCKDEP_KEYS: %lu\n", MAX_LOCKDEP_KEYS);
pr_info("... CLASSHASH_SIZE: %lu\n", CLASSHASH_SIZE);
pr_info("... MAX_LOCKDEP_ENTRIES: %lu\n", MAX_LOCKDEP_ENTRIES);
pr_info("... MAX_LOCKDEP_CHAINS: %lu\n", MAX_LOCKDEP_CHAINS);
pr_info("... CHAINHASH_SIZE: %lu\n", CHAINHASH_SIZE);
pr_info(" memory used by lock dependency info: %zu kB\n",
(sizeof(lock_classes) +
sizeof(lock_classes_in_use) +
sizeof(classhash_table) +
sizeof(list_entries) +
sizeof(list_entries_in_use) +
sizeof(chainhash_table) +
sizeof(delayed_free)
#ifdef CONFIG_PROVE_LOCKING
+ sizeof(lock_cq)
+ sizeof(lock_chains)
+ sizeof(lock_chains_in_use)
+ sizeof(chain_hlocks)
#endif
) / 1024
);
#if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_PROVE_LOCKING)
pr_info(" memory used for stack traces: %zu kB\n",
(sizeof(stack_trace) + sizeof(stack_trace_hash)) / 1024
);
#endif
pr_info(" per task-struct memory footprint: %zu bytes\n",
sizeof(((struct task_struct *)NULL)->held_locks));
}void __init lockdep_init(void)이 시점의 lockdep 함수는 잠금 의존성 추적의 한도와 정적 저장 공간 크기를 부팅 로그에 보여 줍니다. 실제 교착 가능성 검사는 이후 잠금 획득·해제 경로에서 수행됩니다.
pr_info("Lock dependency validator: Copyright (c) 2006 Red Hat, Inc., Ingo Molnar\n");잠금 의존성 검증기가 포함되었음을 알리는 배너를 출력합니다. 아래의 추적 한도와 메모리 사용량 보고가 어느 기능의 정보인지 구분하는 시작입니다.
pr_info("... MAX_LOCKDEP_SUBCLASSES: %lu\n", MAX_LOCKDEP_SUBCLASSES);같은 잠금 종류 안에서 중첩 관계를 구별할 subclass의 최대 수입니다. 현재 잠겨 있는 객체 개수가 아니라 구분 가능한 계층 수를 출력합니다.
pr_info("... MAX_LOCK_DEPTH: %lu\n", MAX_LOCK_DEPTH);태스크 하나에서 동시에 보유한 잠금 상태를 기록할 수 있는 최대 깊이입니다. 잠금 함수의 재귀를 이 횟수까지 허용한다는 뜻은 아닙니다.
pr_info("... MAX_LOCKDEP_KEYS: %lu\n", MAX_LOCKDEP_KEYS);lockdep이 서로 다른 잠금 클래스를 식별하여 보관할 수 있는 최대 수입니다. 같은 클래스의 여러 잠금 객체와 클래스 종류 수를 구분해야 합니다.
pr_info("... CLASSHASH_SIZE: %lu\n", CLASSHASH_SIZE);잠금 클래스를 빠르게 찾는 해시 테이블의 버킷 수입니다. 분류된 클래스 전체 개수와 다른 저장 구조의 크기를 보고합니다.
pr_info("... MAX_LOCKDEP_ENTRIES: %lu\n", MAX_LOCKDEP_ENTRIES);먼저 잡은 잠금과 다음에 잡는 잠금 사이의 의존 관계를 기록할 최대 항목 수입니다. 순서 충돌이나 교착 가능성을 찾는 그래프의 용량과 관련됩니다.
pr_info("... MAX_LOCKDEP_CHAINS: %lu\n", MAX_LOCKDEP_CHAINS);추적할 수 있는 서로 다른 잠금 획득 체인의 최대 수입니다. 한 태스크가 현재 보유한 잠금 개수와는 다른 전체 추적 한도입니다.
pr_info("... CHAINHASH_SIZE: %lu\n", CHAINHASH_SIZE);이미 본 잠금 획득 체인을 찾기 위한 해시 테이블의 버킷 수입니다. 중복된 체인을 다시 분석하지 않도록 조회하는 기반입니다.
pr_info(" memory used by lock dependency info: %zu kB\n",lockdep의 정적 클래스·의존 관계·체인 저장소가 차지하는 총량을 출력합니다. 뒤의 sizeof 합계가 이 값이며 지금 동적으로 할당한 객체 수를 세는 출력은 아닙니다.
(sizeof(lock_classes) +자료구조의 크기를 바이트 단위로 구해 lockdep의 정적 저장 공간 사용량을 보고하는 식에 더합니다. sizeof 안의 NULL 포인터 표현은 실제로 그 주소를 읽는 동작이 아닙니다. 대상: (sizeof(lock_classes) +
sizeof(lock_classes_in_use) +자료구조의 크기를 바이트 단위로 구해 lockdep의 정적 저장 공간 사용량을 보고하는 식에 더합니다. sizeof 안의 NULL 포인터 표현은 실제로 그 주소를 읽는 동작이 아닙니다. 대상: sizeof(lock_classes_in_use) +
sizeof(classhash_table) +자료구조의 크기를 바이트 단위로 구해 lockdep의 정적 저장 공간 사용량을 보고하는 식에 더합니다. sizeof 안의 NULL 포인터 표현은 실제로 그 주소를 읽는 동작이 아닙니다. 대상: sizeof(classhash_table) +
sizeof(list_entries) +자료구조의 크기를 바이트 단위로 구해 lockdep의 정적 저장 공간 사용량을 보고하는 식에 더합니다. sizeof 안의 NULL 포인터 표현은 실제로 그 주소를 읽는 동작이 아닙니다. 대상: sizeof(list_entries) +
sizeof(list_entries_in_use) +자료구조의 크기를 바이트 단위로 구해 lockdep의 정적 저장 공간 사용량을 보고하는 식에 더합니다. sizeof 안의 NULL 포인터 표현은 실제로 그 주소를 읽는 동작이 아닙니다. 대상: sizeof(list_entries_in_use) +
sizeof(chainhash_table) +자료구조의 크기를 바이트 단위로 구해 lockdep의 정적 저장 공간 사용량을 보고하는 식에 더합니다. sizeof 안의 NULL 포인터 표현은 실제로 그 주소를 읽는 동작이 아닙니다. 대상: sizeof(chainhash_table) +
sizeof(delayed_free)자료구조의 크기를 바이트 단위로 구해 lockdep의 정적 저장 공간 사용량을 보고하는 식에 더합니다. sizeof 안의 NULL 포인터 표현은 실제로 그 주소를 읽는 동작이 아닙니다. 대상: sizeof(delayed_free)
#ifdef CONFIG_PROVE_LOCKING잠금 획득 순서와 의존 관계를 추적해 교착 가능성을 진단하는 설정입니다. 여기서는 실제 검사 실행이 아니라 이 기능에만 필요한 잠금 체인 자료의 크기를 메모리 사용량 합계에 포함합니다. 이 선택은 전처리 단계에서 이루어지며, CPU가 실행 중 이 줄의 조건을 검사하지 않습니다.
+ sizeof(lock_cq)자료구조의 크기를 바이트 단위로 구해 lockdep의 정적 저장 공간 사용량을 보고하는 식에 더합니다. sizeof 안의 NULL 포인터 표현은 실제로 그 주소를 읽는 동작이 아닙니다. 대상: + sizeof(lock_cq)
+ sizeof(lock_chains)자료구조의 크기를 바이트 단위로 구해 lockdep의 정적 저장 공간 사용량을 보고하는 식에 더합니다. sizeof 안의 NULL 포인터 표현은 실제로 그 주소를 읽는 동작이 아닙니다. 대상: + sizeof(lock_chains)
+ sizeof(lock_chains_in_use)자료구조의 크기를 바이트 단위로 구해 lockdep의 정적 저장 공간 사용량을 보고하는 식에 더합니다. sizeof 안의 NULL 포인터 표현은 실제로 그 주소를 읽는 동작이 아닙니다. 대상: + sizeof(lock_chains_in_use)
+ sizeof(chain_hlocks)자료구조의 크기를 바이트 단위로 구해 lockdep의 정적 저장 공간 사용량을 보고하는 식에 더합니다. sizeof 안의 NULL 포인터 표현은 실제로 그 주소를 읽는 동작이 아닙니다. 대상: + sizeof(chain_hlocks)
#endif잠금 의존성 검증을 사용할 때 필요한 체인 자료의 크기 합산을 마칩니다. 전체 바이트 합계를 KiB로 바꾸는 식은 조건 바깥에서 이어집니다.
) / 1024앞에서 합한 바이트 수를 1024로 나누어 KiB 단위로 표시합니다. 출력 문자열의 kB 표기와 관계없이 실제 나눗셈 기준은 1024입니다. 앞줄에서 시작한 호출이나 식에 이어지는 부분이므로, 이 줄만으로 별도의 함수 호출이 생기지는 않습니다.
);앞줄들에서 계산한 저장 공간 크기를 로그 함수의 인자로 넘겨 해당 보고를 마칩니다. 이 지점에서 추가 메모리를 할당하지 않습니다.
#if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_PROVE_LOCKING)IRQ 허용·차단 지점을 추적하는 TRACE_IRQFLAGS와 잠금 의존성을 검사하는 PROVE_LOCKING을 모두 포함한 경우입니다. 잠금 사용 문맥을 진단할 스택 추적 자료가 존재하므로 그 저장 공간 크기를 별도로 출력합니다. 이 선택은 전처리 단계에서 이루어지며, CPU가 실행 중 이 줄의 조건을 검사하지 않습니다.
pr_info(" memory used for stack traces: %zu kB\n",잠금 사용 경로를 진단하기 위해 저장하는 스택 추적 주소 배열과 조회 테이블의 크기를 별도로 출력합니다. 일반 커널 스택 전체 사용량을 뜻하지 않습니다.
(sizeof(stack_trace) + sizeof(stack_trace_hash)) / 1024자료구조의 크기를 바이트 단위로 구해 lockdep의 정적 저장 공간 사용량을 보고하는 식에 더합니다. sizeof 안의 NULL 포인터 표현은 실제로 그 주소를 읽는 동작이 아닙니다. 대상: (sizeof(stack_trace) + sizeof(stack_trace_hash)) / 1024
);앞줄들에서 계산한 저장 공간 크기를 로그 함수의 인자로 넘겨 해당 보고를 마칩니다. 이 지점에서 추가 메모리를 할당하지 않습니다.
#endifIRQ 상태 추적과 잠금 검증을 함께 쓸 때의 스택 추적 메모리 보고를 마칩니다. 뒤에서는 태스크 하나당 잠금 기록 크기를 출력합니다.
pr_info(" per task-struct memory footprint: %zu bytes\n",태스크 하나의 task_struct 안에 들어가는 held_locks 배열 크기를 출력합니다. 각 태스크가 지금 보유한 잠금을 추적하는 데 드는 고정 비용입니다.
sizeof(((struct task_struct *)NULL)->held_locks));자료구조의 크기를 바이트 단위로 구해 lockdep의 정적 저장 공간 사용량을 보고하는 식에 더합니다. sizeof 안의 NULL 포인터 표현은 실제로 그 주소를 읽는 동작이 아닙니다. 대상: sizeof(((struct task_struct *)NULL)->held_locks));
함께 생각해 볼 질문
이 함수가 모든 교착을 찾아내나요?
아닙니다. 실제 경로에서 관찰된 잠금 관계와 검사 설정에 따라 진단합니다.
출력하는 sizeof는 malloc인가요?
타입이나 객체가 차지하는 크기를 계산할 뿐 새 공간을 할당하지 않습니다.
CONFIG_PROVE_LOCKING이 왜 나오나요?
해당 검증 기능이 있을 때만 관련 배열의 크기를 계산에 포함하기 때문입니다.
출처와 읽은 범위
Linux stable v6.18.37 · kernel/locking/lockdep.c
해당 버전 원본 파일 · 기존 코드 분석 · 설명 원고
