<kernel v4.14>
fork_init()
kernel/fork.c
void __init fork_init(void) { int i; #ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR #ifndef ARCH_MIN_TASKALIGN #define ARCH_MIN_TASKALIGN 0 #endif int align = max_t(int, L1_CACHE_BYTES, ARCH_MIN_TASKALIGN); /* create a slab on which task_structs can be allocated */ task_struct_cachep = kmem_cache_create("task_struct", arch_task_struct_size, align, SLAB_PANIC|SLAB_NOTRACK|SLAB_ACCOUNT, NULL); #endif /* 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; } #ifdef CONFIG_VMAP_STACK cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "fork:vm_stack_cache", NULL, free_vm_stack_cache); #endif lockdep_init_task(&init_task); }
- 코드 라인 4에서 ia64 아키텍처에서는 다른 아키텍처처럼 slab을 사용한 kmem 캐시를 사용하지 않고 별도의 task_struct 구조체를 위한 할당자를 사용한다.
- CONFIG_ARCH_TASK_STRUCT_ALLOCATOR 옵션은 현재 ia64 아키텍처만 사용한다.
- 코드 라인 5~8에서 task_struct 구조체 할당 시 아키텍처가 지정한 사이즈만큼 align하여 할당하여 ww_mutex가 기잘 동작하기 위한 fixup이다. 만일 지정되지 않은 경우 0으로 하여 디폴트로 L1 캐시 라인 사이즈만큼 align 하도록한다.
- 코드 라인 11~13에서 task_struct 구조체를 위해 디폴트 할당자인 슬랩을 사용한 kmem 캐시를 준비한다.
- 코드 라인 17에서 아키텍처 고유의 task 캐시 초기화 함수가 있는 경우 호출한다.
- arm, arm64는 사용하지 않는다.
- 코드 라인 19에서 사용가능한 메모리 크기에 맞춰 최대 스레드 수를 산출하여 max_threads 전역 변수에 설정한다.
- 코드 라인 21~22에서 최대 프로세스 수 제한에대한 cur, max 값으로 위에서 산출한 최대 스레드 수의 절반으로 지정한다.
- 코드 라인 23~24에서 최대 펜딩 시그널 수로 위에서 설정한 최대 프로세스 수로 지정한다.
- 코드 라인 26~28에서 ucount 항목들의 최대 제한 수를 모두 최대 스레드 수의 절반 값으로 지정한다.
- 코드 라인 30~33에서 보안성 향상을 위해 특정 아키텍처들은 커널 스택을 vmalloc 영역에 가상 매핑하여 사용할 수 있다. cpu offline 시 해당 cpu에서 사용되고 있는 두 개의 캐시된 vm 스택 영역 정보를 삭제하는 역할을 수행하기 위해 호출될 콜백함수 free_vm_stack_cache()를 지정한다.
- 이 옵션은 스택을 쉐도우 매핑해야 하는 KASAN(Kernel Address Sanitizer)와 같이 사용할 수 없다.
- 이 옵션은 현재 x86과 arm64 아키텍처에서 사용할 수 있다.
- 참고: fork: free vmapped stacks in cache when cpus are offline
- 코드 라인 35에서 디버그 lockdep을 위해 초기화를 한다.
set_max_threads()
kernel/fork.c
/* * set_max_threads */ static void set_max_threads(unsigned int max_threads_suggested) { u64 threads; /* * The number of threads shall be limited such that the thread * structures may only consume a small part of the available memory. */ if (fls64(totalram_pages) + fls64(PAGE_SIZE) > 64) threads = MAX_THREADS; else threads = div64_u64((u64) totalram_pages * (u64) PAGE_SIZE, (u64) THREAD_SIZE * 8UL); if (threads > max_threads_suggested) threads = max_threads_suggested; max_threads = clamp_t(u64, threads, MIN_THREADS, MAX_THREADS); }
사용 가능한 최대 스레드 수를 설정한다. 내부 메모리를 판단하여 최소 20개 ~ 인자로 제안한 스레드 수 범위내에서 지정한다. 결정된 값은 max_threads 전역 변수에 지정된다.
- 참고로 “/proc/sys/kernel/threads-max” 를 수정하여 설정할 수 있다.
- 예) totalram_pages=0x8_0000 (2GB, 4K 페이지)
- 2GB / 스레드 크기(arm64 디폴트=16K)의 8배 = 16K (16,384)
ucounts
유저별 namespace 제한 값을 설정하는 기능은 커널 v4.9에 추가되었다.
- “/proc/ucounts” 파일을 통해 ucount 항목들의 cur값과 max값을 볼 수 있다.
- user
- 최대 user namespace 제한
- pid
- 최대 pid namespace 제한
- uts
- 최대 uts namespace 제한
- ipc
- 최대 ipc namespace 제한
- net
- 최대 net namespace 제한
- mnt
- 최대 mount namespace 제한
- cgroup
- 최대 cgroup namespace 제한
- 기타
- inotify_instances
- “/proc/sys/fs/inotify/max_user_instances”파일로 설정
- inotify_watches
- “/proc/sys/fs/inotify/max_user_watches”파일로 설정
- inotify_instances
- user