태스크 생성 전에 실행되는 부팅 초기화
start_kernel()는 pid_idr_init()을 호출하고, 그 사이에 익명 VMA·스택·credential 준비를 거쳐 fork_init(), 이어 proc_caches_init()을 호출한다. 세 함수는 서로를 직접 호출하는 체인이 아니다(main.c L1080–1095).
start_kernel()의 호출 순서다. ①과 ② 사이에는 anon_vma_init()·thread_stack_cache_init()·cred_init()이 있다. PID IDR 준비, task 수 한도, process 보조 캐시는 서로 다른 작업이다. main.c L1080–1095표시한 코드와 적용 범위
아래 세 발췌는 고정된 Linux v6.18.37의 main.c L1080–1095, fork.c L807–850, fork.c L2977–2997에서 가져온 연속 행이다. PID 할당기 설명은 같은 태그의 pid.c L799–818, max_threads 계산은 fork.c L766–785를 함께 읽었다.
범위: 이 글은 부팅 중 fork_init()을 중심으로 한다. fork/clone syscall, namespace별 PID 배정, 모든 아키텍처와 설정 조합, 실제 보드의 부팅 로그 전체는 검증하지 않았다. 문C의 fork_init 글과 start_kernel 글은 설명 방식에 대한 역사적 참고다. 두 글의 구형 함수 위치를 이 버전의 증거로 쓰지 않았다.
태그 소스: init/main.c · kernel/fork.c · kernel/pid.c. 표시된 두 파일은 원본 SPDX가 GPL-2.0-only다.
세 함수의 실제 연속 코드
1. start_kernel의 직접 호출 순서
init/main.c:1080–1095 · 중간 호출을 생략하지 않은 실제 부팅 순서다.
pid_idr_init();
anon_vma_init();
thread_stack_cache_init();
cred_init();
fork_init();
proc_caches_init();
uts_ns_init();
time_ns_init();
key_init();
security_init();
dbg_late_init();
net_ns_init();
vfs_caches_init();
pagecache_init();
signals_init();
seq_file_init();2. fork_init: task cache와 초기 한도
kernel/fork.c:807–850 · task cache 생성 뒤 set_max_threads와 init_task/user namespace 초기 한도가 이어진다.
void __init fork_init(void)
{
int i;
#ifndef ARCH_MIN_TASKALIGN
#define ARCH_MIN_TASKALIGN 0
#endif
int align = max_t(int, L1_CACHE_BYTES, ARCH_MIN_TASKALIGN);
unsigned long useroffset, usersize;
/* create a slab on which task_structs can be allocated */
task_struct_whitelist(&useroffset, &usersize);
task_struct_cachep = kmem_cache_create_usercopy("task_struct",
arch_task_struct_size, align,
SLAB_PANIC|SLAB_ACCOUNT,
useroffset, usersize, NULL);
/* do the arch specific task caches init */
arch_task_cache_init();
set_max_threads(MAX_THREADS);
init_task.signal->rlim[RLIMIT_NPROC].rlim_cur = max_threads/2;
init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads/2;
init_task.signal->rlim[RLIMIT_SIGPENDING] =
init_task.signal->rlim[RLIMIT_NPROC];
for (i = 0; i < UCOUNT_COUNTS; i++)
init_user_ns.ucount_max[i] = max_threads/2;
set_userns_rlimit_max(&init_user_ns, UCOUNT_RLIMIT_NPROC, RLIM_INFINITY);
set_userns_rlimit_max(&init_user_ns, UCOUNT_RLIMIT_MSGQUEUE, RLIM_INFINITY);
set_userns_rlimit_max(&init_user_ns, UCOUNT_RLIMIT_SIGPENDING, RLIM_INFINITY);
set_userns_rlimit_max(&init_user_ns, UCOUNT_RLIMIT_MEMLOCK, RLIM_INFINITY);
#ifdef CONFIG_VMAP_STACK
cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "fork:vm_stack_cache",
NULL, free_vm_stack_cache);
#endif
scs_init();
lockdep_init_task(&init_task);
uprobes_init();
}3. proc_caches_init: 보조 캐시와 후속 초기화
kernel/fork.c:2977–2997 · 이 함수의 본문에는 PID IDR 생성이 없다.
void __init proc_caches_init(void)
{
sighand_cachep = kmem_cache_create("sighand_cache",
sizeof(struct sighand_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_TYPESAFE_BY_RCU|
SLAB_ACCOUNT, sighand_ctor);
signal_cachep = kmem_cache_create("signal_cache",
sizeof(struct signal_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT,
NULL);
files_cachep = kmem_cache_create("files_cache",
sizeof(struct files_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT,
NULL);
fs_cachep = kmem_cache_create("fs_cache",
sizeof(struct fs_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT,
NULL);
mmap_init();
nsproxy_cache_init();
}각 함수는 다른 준비를 맡는다
pid_idr_init()은 init_pid_ns.idr을 초기화하고 pid cache를 만든다(pid.c L799–818). 뒤에 부르는 fork_init()은 task_struct_cachep를 만들고 아키텍처별 task cache 준비를 호출한 다음, set_max_threads(MAX_THREADS)를 실행한다(fork.c L807–850). 이 값은 부팅 시 가용 페이지 추정과 THREAD_SIZE를 이용해 계산하고 범위에 맞춘다(fork.c L766–785).
fork_init()은 그 결과로 init_task.signal의 RLIMIT_NPROC·RLIMIT_SIGPENDING, 초기 사용자 namespace의 ucount_max[]를 설정한다. init_task.signal의 NPROC cur/max와 SIGPENDING은 max_threads/2로 두지만, 별도 set_userns_rlimit_max()는 init_user_ns의 네 UCOUNT_RLIMIT_* 상한을 RLIM_INFINITY로 지정한다. 여기서 max_threads/2를 전체 시스템의 단일한 런타임 허용량으로 읽으면 안 된다(fork.c L807–850).
| 호출 | 여기서 준비하는 것 | 이 함수의 일이 아닌 것 | 근거 |
|---|---|---|---|
pid_idr_init | 초기 PID IDR·pid cache·pid_max 기초값 | task_struct cache와 max_threads | pid.c L799–818 |
fork_init | task cache·max_threads·초기 rlimit/ucount·후속 내부 초기화 | PID IDR 생성, 실제 자식 태스크 복제 | fork.c L807–850 · fork.c L766–785 |
proc_caches_init | sighand·signal·files·fs cache, mmap/nsproxy 초기화 호출 | PID IDR 생성, max_threads 산정 | fork.c L2977–2997 |
task cache와 보조 cache를 분리하기
task_struct_cachep는 fork_init()에서 kmem_cache_create_usercopy()로 설정되는 cache 포인터다. proc_caches_init()의 네 cache는 별도 객체에 대한 것이다. 둘을 한 cache 또는 하나의 구조체 필드 묶음으로 그리면 할당 대상을 잘못 읽게 된다(fork.c L807–850 · fork.c L2977–2997).
task_struct_cachep → task_struct용 cache. 같은 함수가 arch_task_cache_init()과 초기 한도 설정을 잇는다.fork.c L816–839sighand_cachep / signal_cachep / files_cachep / fs_cachep; 마지막에 mmap_init()과 nsproxy_cache_init().fork.c L2977–2997pid_idr_init()이 준비한다. pid.c L799–818초기화 단계와 태스크 생성 단계를 구분하기
부팅 초기에 start_kernel()이 초기화 함수를 순서대로 실행한 뒤에도 부팅은 이어진다. 이어지는 rest_init()에서 init·kthreadd 태스크 생성이 시작되므로, 이 초기화 단계와 새 태스크를 만드는 단계는 구분해야 한다(main.c L1109–1110 · main.c L711–735). copy_process()의 NPROC와 max_threads 검사 위치는 fork.c L2053–2068다. 그 함수의 전체 생성·해제 경로는 copy_process 글에서 읽는다.
코드에서 확인되는 조건만 남기기
두 초기화 함수는 void __init이고, 표시된 cache 생성은 SLAB_PANIC을 사용한다. 이 본문에 일반적인 오류 레이블·역순 rollback 경로가 있다고 서술할 근거는 없다(fork.c L807–850 · fork.c L2977–2997). CONFIG_VMAP_STACK에 따른 CPU hotplug 등록은 조건부이며, cache 생성과 별도로 읽어야 한다(fork.c L841–849).
해석상 중요한 세 구분은 PID 번호 관리와 task 수 제한, task_struct cache와 주변 객체 cache, 부팅 준비와 실제 태스크 생성이다. 각 구분은 위 소스 위치를 다시 확인할 수 있게 표기했다.
무엇을 확인할 수 있나
| 방법 | 알 수 있는 것 | 알 수 없는 것 | 근거 |
|---|---|---|---|
| 태그 소스 순서 읽기 | start_kernel()의 직접 호출 순서 | 특정 보드에서 각 단계가 끝난 시간 | main.c L1080–1095 |
cat /proc/sys/kernel/threads-max | 부팅 후 노출된 현재 thread 상한 값 | 부팅 중 어느 함수에서 멈췄는지, 초기 계산식의 모든 입력 | fork.c L766–785 · fork.c L3230–3269 |
| 초기 부팅 로그·명시적 계측 | 계측한 지점의 실제 도달 여부 | 로그만으로 cache와 limit의 모든 내부 상태 | fork.c L807–850 · fork.c L2977–2997 |
initcall_debug는 initcall 경로를 보는 설정이다. 여기의 fork_init()·proc_caches_init()은 start_kernel()에서 직접 호출되므로 그 설정 하나를 두 함수의 단계별 추적법으로 제시하지 않는다(main.c L1080–1095).
이어서 읽기
set_max_threads()의 가용 페이지 추정치와MIN_THREADS/MAX_THREADSclamp는 보드 메모리 조건에 따라 어떤 값이 되는가? fork.c L766–785pid_max와max_threads가 서로 다른 제한이라는 점을 생성 경로에서 어떻게 확인하는가? pid.c L191–245 · fork.c L2053–2068- task_struct를 실제 할당하고 자원을 복제하는 과정은 copy_process에서 어디서 시작되는가?