fork_init()

<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()를 지정한다.
  • 코드 라인 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”파일로 설정

 

댓글 남기기