2016년 10월 29일 토요일

[Linux Kernel] 161주차(2016.10.29) rest_init()

Neuromancer : 161 주차

일시 : 2016.10.29 (161 주차 스터디 진행)

모임명 : neuromancer.kr

장소 : 토즈 서현점

참여인원 : 2명

============

161주차 진도

  • 161차 시작 위치
    • start_kernel 1 ~/init/main.c
    • rest_init 968 ~/init/main.c
    • kernel_thread 453 ~/init/main.c
    • do_fork 2067 ~/kernel/fork.c
    • copy_process 2020 ~/kernel/fork.c
    • sched_fork 1734 ~/kernel/fork.c

161주차 함수 호출 구조

  • call: start_kernel()
    • lockdep_init()
    • smp_setup_processor_id()
    • debug_objects_early_init()
    • boot_init_stack_canary()
    • cgroup_init_early()
    • local_irq_disable()
    • boot_cpu_init()
    • page_address_init()
    • pr_notice()
    • setup_arch()
    • mm_init_owner()
    • mm_init_cpumask()
    • setup_command_line
    • build_all_zonelists()
    • page_alloc_init()
    • pr_notice()
    • parse_early_param()
    • parse_args()
    • jump_label_init()
    • setup_log_buf()
    • pidhash_init()
    • vfs_caches_init_early()
    • sort_main_extable()
    • trap_init()
    • mm_init()
    • sched_init()
    • preempt_disable()
    • irqs_disabled()
    • local_irq_disabled()
    • idr_init_cache()
    • rcu_init()
    • tick_nohz_init()
    • contect_tracking_init()
    • radix_tree_init()
    • early_irq_init()
    • init_IRQ()
    • tick_init()
    • init_timers()
    • hrtimers_init()
    • softirq_init()
    • timekeeping_init()
    • time_init()
    • sched_clock_postinit()
    • pref_event_init()
    • profile_init()
    • call_function_init()
    • irqs_disabled()
    • local_irq_enabled()
    • kmem_cache_init_late()
    • console_init()
    • lockdep_init()
    • lockdep_info()
    • locking_selftest()
    • virt_to_page()
    • page_to_pfn()
    • page_cgroup_init()
    • debug_objects_mem_init()
    • kmemleak_init()
    • setup_per_cpu_pageset()
    • numa_policy_init()
    • sched_clock_init()
    • calibrate_delay()
    • pidmap_init()
    • anon_vma_init()
    • thread_info_cache_init()
    • cred_init()
    • fork_init()
    • proc_caches_init()
    • buffer_init()
    • key_init()
    • security_init()
    • dbg_late_init()
    • vfs_caches_init()
    • signals_init()
    • page_writeback_init()
    • proc_root_init()
    • cgroup_init()
    • cpuset_init()
    • taskstats_init_early()
    • delayacct_init()
    • check_bugs()
    • acpi_early_init()
    • sfi_init_late()
    • efi_enabled(EFI_RUNTIME_SERVICES)
    • ftrace_init()
    • rest_init()
  • call: rest_init()
    • rcu_scheduler_starting()
    • kernel_thread()
  • call: kernel_thread()
    • do_fork()
  • call: do_fork()
    • copy_process()
  • call: copy_process()
    • security_task_create()
    • dup_task_struct()
    • ftrace_graph_init_task(p); // null function
    • get_seccomp_filter(p); // null function
    • rt_mutex_init_task(p);
    • copy_creds(p, clone_flags);
    • try_module_get()
    • delayacct_tsk_init(p)
    • copy_flags()
    • INIT_LIST_HEAD(&p->children);
    • INIT_LIST_HEAD(&p->sibling);
    • rcu_copy_process(p);
    • spin_lock_init(&p->alloc_lock);
    • init_sigpending(&p->pending);
    • memset(&p->rss_stat, 0, sizeof(p->rss_stat));
    • task_io_accounting_init(&p->ioac); // null function
    • acct_clear_integrals(p); // null function
    • posix_cpu_timers_init(p);
    • do_posix_clock_monotonic_gettime(&p->start_time);
    • monotonic_to_bootbased(&p->real_start_time);
    • cgroup_fork(p);
    • sched_fork(clone_flags, p);
  • call: sched_fork(clone_flags, p);
    • get_cpu();
    • _schedfork(clone_flags, p);
    • rt_prio(p->prio)

start_kernel()

  • call: start_kernel()
    • lockdep_init()
    • smp_setup_processor_id()
    • debug_objects_early_init()
    • boot_init_stack_canary()
    • cgroup_init_early()
    • local_irq_disable()
    • boot_cpu_init()
    • page_address_init()
    • pr_notice()
    • setup_arch()
    • mm_init_owner()
    • mm_init_cpumask()
    • setup_command_line
    • build_all_zonelists()
    • page_alloc_init()
    • pr_notice()
    • parse_early_param()
    • parse_args()
    • jump_label_init()
    • setup_log_buf()
    • pidhash_init()
    • vfs_caches_init_early()
    • sort_main_extable()
    • trap_init()
    • mm_init()
    • sched_init()
    • preempt_disable()
    • irqs_disabled()
    • local_irq_disabled()
    • idr_init_cache()
    • rcu_init()
    • tick_nohz_init()
    • contect_tracking_init()
    • radix_tree_init()
    • early_irq_init()
    • init_IRQ()
    • tick_init()
    • init_timers()
    • hrtimers_init()
    • softirq_init()
    • timekeeping_init()
    • time_init()
    • sched_clock_postinit()
    • pref_event_init()
    • profile_init()
    • call_function_init()
    • irqs_disabled()
    • local_irq_enabled()
    • kmem_cache_init_late()
    • console_init()
    • lockdep_init()
    • lockdep_info()
    • locking_selftest()
    • virt_to_page()
    • page_to_pfn()
    • page_cgroup_init()
    • debug_objects_mem_init()
    • kmemleak_init()
    • setup_per_cpu_pageset()
    • numa_policy_init()
    • sched_clock_init()
    • calibrate_delay()
    • pidmap_init()
    • anon_vma_init()
    • thread_info_cache_init()
    • cred_init()
    • fork_init()
    • proc_caches_init()
    • buffer_init()
    • key_init()
    • security_init()
    • dbg_late_init()
    • vfs_caches_init()
    • signals_init()
    • page_writeback_init()
    • proc_root_init()
    • cgroup_init()
    • cpuset_init()
    • taskstats_init_early()
    • delayacct_init()
    • check_bugs()
    • acpi_early_init()
    • sfi_init_late()
    • efi_enabled()
    • efi_late_init()
    • efi_free_boot_services()
    • ftrace_init()
    • rest_init()
// ARM10C 20130824
asmlinkage void __init start_kernel(void)
{
 char * command_line;
 extern const struct kernel_param __start___param[], __stop___param[];
 // ATAG,DTB 정보로 사용

 /*
  * Need to run as early as possible, to initialize the
  * lockdep hash:
  */
 lockdep_init();
 smp_setup_processor_id();
 debug_objects_early_init();

 /*
  * Set up the the initial canary ASAP:
  */
 boot_init_stack_canary();

 cgroup_init_early();
 // cgroup 를 사용하기 위한 cgroup_dummy_root, cgroup_subsys 의 구조체 초기화 수행

 local_irq_disable();
 // IRQ를 disable 함

 early_boot_irqs_disabled = true;
 // early_boot_irqs_disabled: true

/*
 * Interrupts are still disabled. Do necessary setups, then
 * enable them
 */
 boot_cpu_init();
 // 현재 cpu(core id)를 얻어서 cpu_XXX_bits[] 의 cpu를 셋한다.
 
 page_address_init();
 // 128개의 page_address_htable 배열을 초기화

 pr_notice("%s", linux_banner);
 // 배너:
 // Linux version 2.6.37_DM385_IPNC_3.50.00
 //  (a0875405@bangvideoapps01) (gcc version 4.5.3 20110311
 //  (prerelease) (GCC) ) #1 Fri Dec 21 17:27:08 IST 2012

 setup_arch(&command_line);

 mm_init_owner(&init_mm, &init_task); // null function
 mm_init_cpumask(&init_mm); // null function

 // command_line: exynos5420-smdk5420.dts 파일의 chosen node 의 bootarg 값
 // "console=ttySAC2,115200 init=/linuxrc"
 setup_command_line(command_line);
 // saved_command_line 및 static_command_line 할당

 setup_nr_cpu_ids();
 setup_per_cpu_areas();
 // pcpu 구조체를 만들어 줌 (mm/percpu.c)

 smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
 // boot cpu 0의 pcpu 영역의 base주소를 core register에 설정해줌

 build_all_zonelists(NULL, NULL);

 page_alloc_init();
 // cpu_chain에 page_alloc_cpu_notify를 연결함 (mutex lock/unlock 사용)

 // boot_command_line: "console=ttySAC2,115200 init=/linuxrc"
 pr_notice("Kernel command line: %s\n", boot_command_line);
 // "Kernel command line: console=ttySAC2,115200 init=/linuxrc"

 parse_early_param();
 // setup_arch에서 수행했던 작업 다시 수행
 // command arg에서 각 요소들을 파싱하여 early init section으로 설정된 디바이스 초기화.
 // 우리는 serial device가 검색이 되지만 config설정은 없어서 아무것도 안함.

 // static_command_line: "console=ttySAC2,115200 init=/linuxrc"
 parse_args("Booting kernel", static_command_line, __start___param,
     __stop___param - __start___param,
     -1, -1, &unknown_bootoption);
 // DTB에서 넘어온 bootargs를 파싱하여 param, val을 뽑아내고 그에 대응되는
 // kernel_param 구조체에 값을 등록함.

 jump_label_init();
 // HAVE_JUMP_LABEL 이 undefined 이므로 NULL 함수

 /*
  * These use large bootmem allocations and must precede
  * kmem_cache_init()
  */
 setup_log_buf(0);
 // defalut log_buf의 크기는 __LOG_BUF_LEN: 0x20000 (128KB) 임
 // early_param 에서 호출했던 log_buf_len 값이 있다면 log_buf의 크기를 넘어온 크기로 만듬

 pidhash_init();
 // pidhash의 크기를 16kB만큼 할당 받고 4096개의 hash list를 만듬

 vfs_caches_init_early();
 // Dentry cache, Inode-cache용 hash를 위한 메모리 공간을 각각 512kB, 256kB만큼 할당 받고,
 // 131072, 65536개 만큼 hash table을 각각 만듬

 sort_main_extable();
 // extable 을 cmp_ex를 이용하여 sort수행

 trap_init(); // null function

 mm_init();
 // buddy와 slab 을 활성화 하고 기존 할당 받은 bootmem 은 buddy,
 // pcpu 메모리, vmlist 는 slab으로 이관

 /*
  * Set up the scheduler prior starting any interrupts (such as the
  * timer interrupt). Full topology setup happens at smp_init()
  * time - but meanwhile we still have a functioning scheduler.
  */
 sched_init();
 // scheduler가 사용하는 자료 구조 초기화, idle_threads를 init_task로 세팅

 /*
  * Disable preemption - early bootup scheduling is extremely
  * fragile until we cpu_idle() for the first time.
  */
 preempt_disable();
 // preempt count를 증가시켜 preemption 못하도록 막음

 // irqs_disabled(): 1
 if (WARN(!irqs_disabled(), "Interrupts were enabled *very* early, fixing it\n"))
  local_irq_disable();

 idr_init_cache();
 // integer ID management로 사용하는 idr_layer_cache에 kmem_cache#21 을 생성 및 초기화 후 할당

 rcu_init();
 // rcu 자료구조 bh, sched, preempt 를 각각 초기화 수행함

 tick_nohz_init(); // null function
 context_tracking_init(); // null function

 radix_tree_init();
 // radix tree로 사용하는 radix_tree_node_cachep에 kmem_cache#20을 생성 및 초기화 후 할당하고
 // height_to_maxindex을 초기화 수행

 /* init some links before init_ISA_irqs() */
 early_irq_init();
 // irq_desc 0 ~ 15 까지의 object을 할당 받고 초기화를 수행
 // allocated_irqs에 bit를 1로 세팅하고 radix tree에 각 irq_desc를 노트로 추가

 init_IRQ();
 // gic, combiner이 사용할 메모리 할당과 자료 구조 설정,
 // gic irq (0~15), combiner irq (32~63) interrupt 를 enable 시킴

 tick_init();
 // tick 관련 mask 변수를 0으로 초기화 수행

 init_timers();
 // boot_tvec_bases의 맴버 값을 초기화하고 timers_nb를 cpu_notifier 에 등록,
 // softirq_vec[1] 에 run_timer_softirq 등록하여 초기화 수행

 hrtimers_init();
 // hrtimer_bases의 맴버 값을 초기화하고 hrtimers_nb를 cpu_notifier 에 등록,
 // softirq_vec[8] 에 run_hrtimer_softirq 등록하여 초기화 수행

 softirq_init();
 // tasklet_vec, tasklet_hi_vec 맴버 값을 초기화하고,
 // softirq_vec[6]에 tasklet_action, softirq_vec[0]에 tasklet_hi_action 등록하여 초기화 수행

 timekeeping_init();
 // ntp 관련 전역변수 초기화, timekeeper, shadow_timekeeper의 맴버값 초기화 수행

 time_init();
 // timer 를 사용하기 위한 clk source, clk_table 메모리 할당 및 초기화,
 // timer event를 위한 timer irq (MCT) 초기화 수행

 sched_clock_postinit();
 // sched_clock_timer을 초기화 수행

 perf_event_init(); // null function
 profile_init(); // null function
 call_function_init();
 // 각 cpu core에서 사용할 call_single_queue를 맴버값 초기화
 // cfd_data 맴버값을 초기화하고 pcp에서 사용할 메모리 공간 할당
 // cpu_chain에 hotplug_cfd_notifier 를 등록함

 // irqs_disabled(): 1
 WARN(!irqs_disabled(), "Interrupts were enabled early\n");

 // early_boot_irqs_disabled: true
 early_boot_irqs_disabled = false;
 // early_boot_irqs_disabled: false

 local_irq_enable();
 // IRQ를 enable 함

 kmem_cache_init_late(); // null function

 /*
  * HACK ALERT! This is early. We're enabling the console before
  * we've done PCI setups etc, and console_init() must be aware of
  * this. But we do want output early, in case something goes wrong.
  */
 console_init();

 // panic_later: NULL
 if (panic_later)
  panic(panic_later, panic_param);

 lockdep_info(); // null function

 /*
  * Need to run this when irqs are enabled, because it wants
  * to self-test [hard/soft]-irqs on/off lock inversion bugs
  * too:
  */
 locking_selftest(); // null function

#ifdef CONFIG_BLK_DEV_INITRD // CONFIG_BLK_DEV_INITRD=y
 // initrd_start: NULL, initrd_below_start_ok: 0
 if (initrd_start && !initrd_below_start_ok &&
     page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
  pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n",
      page_to_pfn(virt_to_page((void *)initrd_start)),
      min_low_pfn);
  initrd_start = 0;
 }
#endif

 page_cgroup_init(); // null function
 debug_objects_mem_init(); // null function
 kmemleak_init(); // null function

 setup_per_cpu_pageset();
 // per cpu가 사용하는 pageset의 각각의 zone 맴버값 초기화 수행

 numa_policy_init(); // null function

 // late_time_init: NULL
 if (late_time_init)
  late_time_init();

 sched_clock_init();
 // sched_clock_running 값을 1 로 초기화 수행

 calibrate_delay();
 // BogoMIPS값을 결정하기위한 계산을 수행하고 결과를 출력함

 pidmap_init();
 // pidmap 을 사용하기 위한 초기화 수행

 anon_vma_init();
 // anon vma 를 사용하기 위한 kmem_cache 할당자 초기화 수행

#ifdef CONFIG_X86 // CONFIG_X86=n
 if (efi_enabled(EFI_RUNTIME_SERVICES))
  efi_enter_virtual_mode();
#endif
 thread_info_cache_init(); // null function
 cred_init();
 // credentials 를 사용하기 위한 kmem_cache 할당자 초기화 수행

 // totalram_pages: 총 free된 page 수
 fork_init(totalram_pages);
 // task_struct 를 사용하기 위한 kmem_cache 할당자 초기화 수행
 // max_threads값을 계산하여 init_task에 threads값의 limit 값 설정함

 proc_caches_init();
 // sighand_struct, signal_struct, files_struct, fs_struct, mm_struct, vm_area_struct, nsproxy
 // 를 사용하기 위한 kmem_cache 할당자 및 percpu list 초기화 수행

 buffer_init();
 // buffer_head 를 사용하기 위한 kmem_cache 할당자 및 max_buffer_heads 값 초기화 수행

 key_init(); // null funtion
 security_init(); // null funtion
 dbg_late_init(); // null funtion

 // totalram_pages: 총 free된 page 수
 vfs_caches_init(totalram_pages);
 // virtual file system을 위한 names, dentry, inode, filp, mount cache 생성 후
 // file system 을 위한 초기화 수행 및 mount 수행, block, char dev 사용을 위한 초기화 수행

 signals_init();
 // signal을 사용하기 위한 kmem_cache 를 생성

 /* rootfs populating might need page-writeback */
 page_writeback_init();
 // page writeback을 위한 global_dirty_limit, ratelimit_pages 값을 초기화 수행

#ifdef CONFIG_PROC_FS // CONFIG_PROC_FS=y
 proc_root_init();
 // proc filesystem을 등록 하고 proc을 사용하기 위한 dentry, inode 생성 후
 // sysctl_base_table 에 등록된 kernel, vm, fs, debug, dev의 dir, files 를 recursive 하게 RB Tree 를 구성함
#endif
 cgroup_init();
 // cgroup에서 사용하는 sub system 인 debug_subsys, cpu_cgroup_subsys, cpuacct_subsys, freezer_subsys 를 등록 하고
 // init_css_set.subsys 를 이용하여 hash key 값 생성, cgroup 을 위한 kobject 를 생성, cgroup용 fils system type을 추가 하여
 // filesystem 에 등록함, cgroup 을 위한 proc 생성.

 cpuset_init(); // null function
 taskstats_init_early(); // null function
 delayacct_init(); // null function

 check_bugs();
 // page 2개를 할당 받고 할당 받은 메모리에값을 쓰고 비교하여
 // 메모리 동작을 테스트 수행한 이후 다시 메모리를 반환함

 acpi_early_init(); /* before LAPIC and SMP init */  // null function
 sfi_init_late(); // null function

 // efi_enabled(EFI_RUNTIME_SERVICES): 1
 if (efi_enabled(EFI_RUNTIME_SERVICES)) {
  efi_late_init(); // null function
  efi_free_boot_services(); // null function
 }

 ftrace_init(); // null function

 /* Do the rest non-__init'ed, we're now alive */
 rest_init();
}

rest_init()

  • start_kernel()
    • rest_init()
  • call: rest_init()
// ARM10C 20160827
static noinline void __init_refok rest_init(void)
{
 int pid;

 rcu_scheduler_starting(); // null function
 /*
  * We need to spawn init first so that it obtains pid 1, however
  * the init task will end up wanting to create kthreads, which, if
  * we schedule it before we create kthreadd, will OOPS.
  */
 // CLONE_FS: 0x00000200, CLONE_SIGHAND: 0x00000800
 kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);

kernel_thread()

  • start_kernel()
    • rest_init()
  • call: rest_init()
    • rcu_scheduler_starting()
    • kernel_thread()
// ARM10C 20160827
// kernel_init, NULL, 0x00000A00
pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
 // flags: 0x00000A00, CLONE_VM: 0x00000100, CLONE_UNTRACED: 0x00800000,
 // fn: kernel_init, arg: NULL
 return do_fork(flags|CLONE_VM|CLONE_UNTRACED, (unsigned long)fn,
  (unsigned long)arg, NULL, NULL);
}

do_fork()

  • start_kernel()
    • rest_init()
  • call: rest_init()
    • rcu_scheduler_starring()
    • kernel_thread()
  • call: kernel_thread()
    • do_fork()
  • call: do_fork()
// ARM10C 20160827
// flags: 0x00800B00, fn: kernel_init, arg: NULL, NULL, NULL
long do_fork(unsigned long clone_flags,
       unsigned long stack_start,
       unsigned long stack_size,
       int __user *parent_tidptr,
       int __user *child_tidptr)
{
 struct task_struct *p;
 int trace = 0;
 // trace: 0

 long nr;

 /*
  * Determine whether and which event to report to ptracer.  When
  * called from kernel_thread or CLONE_UNTRACED is explicitly
  * requested, no event is reported; otherwise, report if the event
  * for the type of forking is enabled.
  */
 // clone_flags: 0x00800B00, CLONE_UNTRACED: 0x00800000
 if (!(clone_flags & CLONE_UNTRACED)) {
  if (clone_flags & CLONE_VFORK)
   trace = PTRACE_EVENT_VFORK;
  else if ((clone_flags & CSIGNAL) != SIGCHLD)
   trace = PTRACE_EVENT_CLONE;
  else
   trace = PTRACE_EVENT_FORK;

  if (likely(!ptrace_event_enabled(current, trace)))
   trace = 0;
 }

 // clone_flags: 0x00800B00, stack_start: kernel_init, stack_size: 0, child_tidptr: 0, trace: 0
 p = copy_process(clone_flags, stack_start, stack_size,
    child_tidptr, NULL, trace);

do_fork()

  • start_kernel()
    • rest_init()
  • call: rest_init()
    • rcu_scheduler_starring()
    • kernel_thread()
  • call: kernel_thread()
    • do_fork()
  • call: do_fork()
    • copy_process()
  • call: copy_process()
// ARM10C 20160827
// clone_flags: 0x00800B00, stack_start: kernel_init, stack_size: 0, child_tidptr: 0, NULL, trace: 0
static struct task_struct *copy_process(unsigned long clone_flags,
  unsigned long stack_start,
  unsigned long stack_size,
  int __user *child_tidptr,
  struct pid *pid,
  int trace)
{
 int retval;
 struct task_struct *p;

 // clone_flags: 0x00800B00, CLONE_NEWNS: 0x00020000, CLONE_FS: 0x00000200
 if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))
  return ERR_PTR(-EINVAL);

 // clone_flags: 0x00800B00, CLONE_NEWUSER: 0x10000000, CLONE_FS: 0x00000200
 if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS))
  return ERR_PTR(-EINVAL);

 /*
  * Thread groups must share signals as well, and detached threads
  * can only be started up within the thread group.
  */
 // clone_flags: 0x00800B00, CLONE_THREAD: 0x00010000, CLONE_SIGHAND: 0x00000800
 if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND))
  return ERR_PTR(-EINVAL);

 /*
  * Shared signal handlers imply shared VM. By way of the above,
  * thread groups also imply shared VM. Blocking this case allows
  * for various simplifications in other code.
  */
 // clone_flags: 0x00800B00, CLONE_SIGHAND: 0x00000800, CLONE_VM: 0x00000100
 if ((clone_flags & CLONE_SIGHAND) && !(clone_flags & CLONE_VM))
  return ERR_PTR(-EINVAL);

// 2016/08/27 종료
// 2016/09/03 시작

 /*
  * Siblings of global init remain as zombies on exit since they are
  * not reaped by their parent (swapper). To solve this and to avoid
  * multi-rooted process trees, prevent global and container-inits
  * from creating siblings.
  */
 // clone_flags: 0x00800B00, CLONE_PARENT: 0x00008000, SIGNAL_UNKILLABLE: 0x00000040
 // current: &init_task, current->signal: &init_signals
 // current->signal->flags: (&init_signals)->flags: 0
 if ((clone_flags & CLONE_PARENT) &&
   current->signal->flags & SIGNAL_UNKILLABLE)
  return ERR_PTR(-EINVAL);

 /*
  * If the new process will be in a different pid or user namespace
  * do not allow it to share a thread group or signal handlers or
  * parent with the forking task.
  */
 // clone_flags: 0x00800B00, CLONE_SIGHAND: 0x00000800
 if (clone_flags & CLONE_SIGHAND) {
  // clone_flags: 0x00800B00, CLONE_NEWUSER: 0x10000000, CLONE_NEWPID: 0x20000000
  // current: &init_task, task_active_pid_ns(&init_task): &init_pid_ns,
  // current->nsproxy: (&init_task)->nsproxy: &init_nsproxy,
  // current->nsproxy->pid_ns_for_children: (&init_nsproxy)->pid_ns_for_children: &init_pid_ns
  if ((clone_flags & (CLONE_NEWUSER | CLONE_NEWPID)) ||
    (task_active_pid_ns(current) !=
     current->nsproxy->pid_ns_for_children))
   return ERR_PTR(-EINVAL);
 }

 // clone_flags: 0x00800B00, security_task_create(0x00800B00): 0
 retval = security_task_create(clone_flags);
 // retval: 0

 // retval: 0
 if (retval)
  goto fork_out;

 // ENOMEM: 12
 retval = -ENOMEM;
 // retval: -12

 // current: &init_task
 // dup_task_struct(&init_task): kmem_cache#15-oX (struct task_struct)
 p = dup_task_struct(current);
 // p: kmem_cache#15-oX (struct task_struct)

 // dup_task_struct 에서 한일:
 // struct task_struct 만큼의 메모리를 할당 받음
 // kmem_cache#15-oX (struct task_struct)
 //
 // struct thread_info 를 구성 하기 위한 메모리를 할당 받음 (8K)
 // 할당 받은 page 2개의 메로리의 가상 주소
 //
 // 할당 받은 kmem_cache#15-oX (struct task_struct) 메모리에 init_task 값을 전부 할당함
 //
 // (kmem_cache#15-oX (struct task_struct))->stack: 할당 받은 page 2개의 메로리의 가상 주소
 //
 // 할당 받은 kmem_cache#15-oX (struct task_struct) 의 stack의 값을 init_task 의 stack 값에서 전부 복사함
 // 복사된 struct thread_info 의 task 주소값을 할당 받은 kmem_cache#15-oX (struct task_struct)로 변경함
 // *(할당 받은 page 2개의 메로리의 가상 주소): init_thread_info
 // ((struct thread_info *) 할당 받은 page 2개의 메로리의 가상 주소)->task: kmem_cache#15-oX (struct task_struct)
 //
 // (((struct thread_info *)(할당 받은 page 2개의 메로리의 가상 주소))->flags 의 1 bit 값을 clear 수행
 //
 // *((unsigned long *)(할당 받은 page 2개의 메로리의 가상 주소 + 1)): 0x57AC6E9D
 //
 // (&(kmem_cache#15-oX (struct task_struct))->usage)->counter: 2
 // (kmem_cache#15-oX (struct task_struct))->splice_pipe: NULL
 // (kmem_cache#15-oX (struct task_struct))->task_frag.page: NULL
 //
 // (&contig_page_data)->node_zones[0].vm_stat[16]: 1 을 더함
 // vmstat.c의 vm_stat[16] 전역 변수에도 1을 더함

 // p: kmem_cache#15-oX (struct task_struct)
 if (!p)
  goto fork_out;

 // p: kmem_cache#15-oX (struct task_struct)
 ftrace_graph_init_task(p); // null function

 // p: kmem_cache#15-oX (struct task_struct)
 get_seccomp_filter(p); // null function

 // p: kmem_cache#15-oX (struct task_struct)
 rt_mutex_init_task(p);

 // rt_mutex_init_task 한일:
 // &(kmem_cache#15-oX (struct task_struct))->pi_lock을 사용한 spinlock 초기화
 // &(kmem_cache#15-oX (struct task_struct))->pi_waiters 리스트 초기화
 // (kmem_cache#15-oX (struct task_struct))->pi_blocked_on: NULL

#ifdef CONFIG_PROVE_LOCKING // CONFIG_PROVE_LOCKING=n
 DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled);
 DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
#endif
 // EAGAIN: 11
 retval = -EAGAIN;
 // retval: -11

 // p: kmem_cache#15-oX (struct task_struct)
 // p->real_cred: (kmem_cache#15-oX (struct task_struct))->real_cred: &init_cred,
 // p->real_cred->user: (&init_cred)->user: &root_user,
 // &p->real_cred->user->processes: &(&root_user)->processes, atomic_read(&(&root_user)->processes): 1
 // RLIMIT_NPROC: 6, task_rlimit(kmem_cache#15-oX (struct task_struct), 6): 0
 if (atomic_read(&p->real_cred->user->processes) >=
   task_rlimit(p, RLIMIT_NPROC)) {
  // p->real_cred->user: (&init_cred)->user: &root_user, INIT_USER: (&root_user)
  // CAP_SYS_RESOURCE: 24, capable(24): true, CAP_SYS_ADMIN: 21, capable(21): true
  if (p->real_cred->user != INIT_USER &&
      !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN))
   goto bad_fork_free;

  // capable 에서 한일:
  // (&init_task)->flags: 0x00200100
 }

 // current->flags: (&init_task)->flags: 0x00200100, PF_NPROC_EXCEEDED: 0x00001000
 current->flags &= ~PF_NPROC_EXCEEDED;
 // current->flags: (&init_task)->flags: 0x00200100

 // retval: -11, p: kmem_cache#15-oX (struct task_struct), clone_flags: 0x00800B00
 // copy_creds(kmem_cache#15-oX (struct task_struct), 0x00800B00): 0
 retval = copy_creds(p, clone_flags);
 // retval: 0

 // copy_creds 에서 한일:
 // struct cred 만큼의 메모리를 할당 받음
 // kmem_cache#16-oX (struct cred)
 //
 // kmem_cache#16-oX (struct cred) 에 init_cred 에 있는 맴버값 전부를 복사함
 // (&(kmem_cache#16-oX (struct cred))->usage)->counter: 1
 // (&(&init_groups)->usage)->counter: 3
 // (&(&root_user)->__count)->counter: 2
 // (&(&root_user)->processes)->counter: 2
 //
 // (&(kmem_cache#16-oX (struct cred))->usage)->counter: 2
 //
 // (kmem_cache#15-oX (struct task_struct))->cred: kmem_cache#16-oX (struct cred)
 // (kmem_cache#15-oX (struct task_struct))->real_cred: kmem_cache#16-oX (struct cred)

 // retval: 0
 if (retval < 0)
  goto bad_fork_free;

 /*
  * If multiple threads are within copy_process(), then this check
  * triggers too late. This doesn't hurt, the check is only there
  * to stop root fork bombs.
  */
 // EAGAIN: 11
 retval = -EAGAIN;
 // retval: -11

 // nr_threads: 0, max_threads: 총 free된 page 수 / 16
 if (nr_threads >= max_threads)
  goto bad_fork_cleanup_count;

 // p: kmem_cache#15-oX (struct task_struct),
 // task_thread_info(kmem_cache#15-oX (struct task_struct)):
 // (kmem_cache#15-oX (struct task_struct))->stack: 할당 받은 page 2개의 메로리의 가상 주소,
 // task_thread_info(kmem_cache#15-oX (struct task_struct)->exec_domain:
 // ((struct thread_info *) 할당 받은 page 2개의 메로리의 가상 주소)->exec_domain: &default_exec_domain,
 // task_thread_info(kmem_cache#15-oX (struct task_struct)->exec_domain->module:
 // (&default_exec_domain)->module: NULL,
 // try_module_get(NULL): true
 if (!try_module_get(task_thread_info(p)->exec_domain->module))
  goto bad_fork_cleanup_count;

 // p->did_exec: (kmem_cache#15-oX (struct task_struct))->did_exec
 p->did_exec = 0;
 // p->did_exec: (kmem_cache#15-oX (struct task_struct))->did_exec: 0

 // p: kmem_cache#15-oX (struct task_struct)
 delayacct_tsk_init(p); /* Must remain after dup_task_struct() */ // null function

 // clone_flags: 0x00800B00, p: kmem_cache#15-oX (struct task_struct)
 copy_flags(clone_flags, p);

 // copy_flags 에서 한일:
 // (kmem_cache#15-oX (struct task_struct))->flags: 0x00200040

 // &p->children: &(kmem_cache#15-oX (struct task_struct))->children
 INIT_LIST_HEAD(&p->children);

 // INIT_LIST_HEAD 에서 한일:
 // (&(kmem_cache#15-oX (struct task_struct))->children)->next: &(kmem_cache#15-oX (struct task_struct))->children
 // (&(kmem_cache#15-oX (struct task_struct))->children)->prev: &(kmem_cache#15-oX (struct task_struct))->children

 // &p->sibling: &(kmem_cache#15-oX (struct task_struct))->sibling
 INIT_LIST_HEAD(&p->sibling);

 // INIT_LIST_HEAD 에서 한일:
 // (&(kmem_cache#15-oX (struct task_struct))->sibling)->next: &(kmem_cache#15-oX (struct task_struct))->sibling
 // (&(kmem_cache#15-oX (struct task_struct))->sibling)->prev: &(kmem_cache#15-oX (struct task_struct))->sibling

 // p: kmem_cache#15-oX (struct task_struct)
 rcu_copy_process(p);

 // rcu_copy_process 에서 한일:
 // (kmem_cache#15-oX (struct task_struct))->rcu_read_lock_nesting: 0
 // (kmem_cache#15-oX (struct task_struct))->rcu_read_unlock_special: 0
 // (kmem_cache#15-oX (struct task_struct))->rcu_blocked_node: NULL
 // (&(kmem_cache#15-oX (struct task_struct))->rcu_node_entry)->next: &(kmem_cache#15-oX (struct task_struct))->rcu_node_entry
 // (&(kmem_cache#15-oX (struct task_struct))->rcu_node_entry)->prev: &(kmem_cache#15-oX (struct task_struct))->rcu_node_entry

 // p->vfork_done: (kmem_cache#15-oX (struct task_struct))->vfork_done
 p->vfork_done = NULL;
 // p->vfork_done: (kmem_cache#15-oX (struct task_struct))->vfork_done: NULL

 // &p->alloc_lock: &(kmem_cache#15-oX (struct task_struct))->alloc_lock
 spin_lock_init(&p->alloc_lock);

 // spin_lock_init에서 한일:
 // (&(kmem_cache#15-oX (struct task_struct))->alloc_lock)->raw_lock: { { 0 } }
 // (&(kmem_cache#15-oX (struct task_struct))->alloc_lock)->magic: 0xdead4ead
 // (&(kmem_cache#15-oX (struct task_struct))->alloc_lock)->owner: 0xffffffff
 // (&(kmem_cache#15-oX (struct task_struct))->alloc_lock)->owner_cpu: 0xffffffff

 // &p->pending: &(kmem_cache#15-oX (struct task_struct))->pending
 init_sigpending(&p->pending);

 // init_sigpending 에서 한일:
 // (&(&(kmem_cache#15-oX (struct task_struct))->pending)->signal)->sig[0]: 0
 // (&(&(kmem_cache#15-oX (struct task_struct))->pending)->signal)->sig[1]: 0
 // (&(&(kmem_cache#15-oX (struct task_struct))->pending)->list)->next: &(&(kmem_cache#15-oX (struct task_struct))->pending)->list
 // (&(&(kmem_cache#15-oX (struct task_struct))->pending)->list)->prev: &(&(kmem_cache#15-oX (struct task_struct))->pending)->list

 // p->utime: (kmem_cache#15-oX (struct task_struct))->utime,
 // p->stime: (kmem_cache#15-oX (struct task_struct))->stime,
 // p->gtime: (kmem_cache#15-oX (struct task_struct))->gtime
 p->utime = p->stime = p->gtime = 0;
 // p->utime: (kmem_cache#15-oX (struct task_struct))->utime: 0
 // p->stime: (kmem_cache#15-oX (struct task_struct))->stime: 0
 // p->gtime: (kmem_cache#15-oX (struct task_struct))->gtime: 0

 // p->utimescaled: (kmem_cache#15-oX (struct task_struct))->utimescaled,
 // p->stimescaled: (kmem_cache#15-oX (struct task_struct))->stimescaled
 p->utimescaled = p->stimescaled = 0;
 // p->utimescaled: (kmem_cache#15-oX (struct task_struct))->utimescaled: 0
 // p->stimescaled: (kmem_cache#15-oX (struct task_struct))->stimescaled: 0

#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE // CONFIG_VIRT_CPU_ACCOUNTING_NATIVE=n
 p->prev_cputime.utime = p->prev_cputime.stime = 0;
#endif
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN // CONFIG_VIRT_CPU_ACCOUNTING_GEN=n
 seqlock_init(&p->vtime_seqlock);
 p->vtime_snap = 0;
 p->vtime_snap_whence = VTIME_SLEEPING;
#endif

#if defined(SPLIT_RSS_COUNTING)
 // &p->rss_stat: &(kmem_cache#15-oX (struct task_struct))->rss_stat
 memset(&p->rss_stat, 0, sizeof(p->rss_stat));

 // memset 에서 한일:
 // &(kmem_cache#15-oX (struct task_struct))->rss_stat 값을 0 으로 초기화 수행
#endif

 // p->default_timer_slack_ns: (kmem_cache#15-oX (struct task_struct))->default_timer_slack_ns,
 // current->timer_slack_ns: (&init_task)->timer_slack_ns: 50000
 p->default_timer_slack_ns = current->timer_slack_ns;
 // p->default_timer_slack_ns: (kmem_cache#15-oX (struct task_struct))->default_timer_slack_ns: 50000

 // p->ioac: (kmem_cache#15-oX (struct task_struct))->ioac
 task_io_accounting_init(&p->ioac); // null function

 // p: kmem_cache#15-oX (struct task_struct)
 acct_clear_integrals(p); // null function

 // p: kmem_cache#15-oX (struct task_struct)
 posix_cpu_timers_init(p);

 // posix_cpu_timers_init 에서 한일:
 // (kmem_cache#15-oX (struct task_struct))->cputime_expires.prof_exp: 0
 // (kmem_cache#15-oX (struct task_struct))->cputime_expires.virt_exp: 0
 // (kmem_cache#15-oX (struct task_struct))->cputime_expires.sched_exp: 0
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[0])->next: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[0]
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[0])->prev: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[0]
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[1])->next: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[1]
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[1])->prev: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[1]
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[2])->next: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[2]
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[2])->prev: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[2]

 // &p->start_time: &(kmem_cache#15-oX (struct task_struct))->start_time
 do_posix_clock_monotonic_gettime(&p->start_time);

 // do_posix_clock_monotonic_gettime 에서 한일:
 // (kmem_cache#15-oX (struct task_struct))->start_time 에 현재 시간 값을 가져옴
 //
 // (&(kmem_cache#15-oX (struct task_struct))->start_time)->tv_sec: 현재의 sec 값 + 현재의 nsec 값 / 1000000000L
 // (&(kmem_cache#15-oX (struct task_struct))->start_time)->tv_nsec: 현재의 nsec 값 % 1000000000L

 // p->real_start_time: (kmem_cache#15-oX (struct task_struct))->real_start_time,
 // p->start_time: (kmem_cache#15-oX (struct task_struct))->start_time
 p->real_start_time = p->start_time;
 // (&(kmem_cache#15-oX (struct task_struct))->real_start_time)->tv_sec: 현재의 sec 값 + 현재의 nsec 값 / 1000000000L
 // (&(kmem_cache#15-oX (struct task_struct))->real_start_time)->tv_nsec: 현재의 nsec 값 % 1000000000L

 // &p->real_start_time: &(kmem_cache#15-oX (struct task_struct))->real_start_time
 monotonic_to_bootbased(&p->real_start_time);

 // monotonic_to_bootbased 에서 한일:
 // (kmem_cache#15-oX (struct task_struct))->real_start_time.tv_sec: normalized 된 sec 값
 // (kmem_cache#15-oX (struct task_struct))->real_start_time.tv_nsec: normalized 된 nsec 값

 // p->io_context: (kmem_cache#15-oX (struct task_struct))->io_context
 p->io_context = NULL;
 // p->io_context: (kmem_cache#15-oX (struct task_struct))->io_context: NULL

 // p->audit_context: (kmem_cache#15-oX (struct task_struct))->audit_context
 p->audit_context = NULL;
 // p->audit_context: (kmem_cache#15-oX (struct task_struct))->audit_context: NULL

 if (clone_flags & CLONE_THREAD)
  threadgroup_change_begin(current);
 cgroup_fork(p);

copy_process()

  • start_kernel()
    • rest_init()
  • call: rest_init()
    • rcu_scheduler_starting()
    • kernel_thread()
  • call: kernel_thread()
    • do_fork()
  • call: do_fork()
    • copy_process()
// ARM10C 20160827
// clone_flags: 0x00800B00, stack_start: kernel_init, stack_size: 0, child_tidptr: 0, NULL, trace: 0
static struct task_struct *copy_process(unsigned long clone_flags,
  unsigned long stack_start,
  unsigned long stack_size,
  int __user *child_tidptr,
  struct pid *pid,
  int trace)
{

 int retval;
 struct task_struct *p;

 // clone_flags: 0x00800B00, CLONE_NEWNS: 0x00020000, CLONE_FS: 0x00000200
 if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))
  return ERR_PTR(-EINVAL);

 // clone_flags: 0x00800B00, CLONE_NEWUSER: 0x10000000, CLONE_FS: 0x00000200
 if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS))
  return ERR_PTR(-EINVAL);

 /*
  * Thread groups must share signals as well, and detached threads
  * can only be started up within the thread group.
  */
 // clone_flags: 0x00800B00, CLONE_THREAD: 0x00010000, CLONE_SIGHAND: 0x00000800
 if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND))
  return ERR_PTR(-EINVAL);

 /*
  * Shared signal handlers imply shared VM. By way of the above,
  * thread groups also imply shared VM. Blocking this case allows
  * for various simplifications in other code.
  */
 // clone_flags: 0x00800B00, CLONE_SIGHAND: 0x00000800, CLONE_VM: 0x00000100
 if ((clone_flags & CLONE_SIGHAND) && !(clone_flags & CLONE_VM))
  return ERR_PTR(-EINVAL);

// 2016/08/27 종료
// 2016/09/03 시작

 /*
  * Siblings of global init remain as zombies on exit since they are
  * not reaped by their parent (swapper). To solve this and to avoid
  * multi-rooted process trees, prevent global and container-inits
  * from creating siblings.
  */
 // clone_flags: 0x00800B00, CLONE_PARENT: 0x00008000, SIGNAL_UNKILLABLE: 0x00000040
 // current: &init_task, current->signal: &init_signals
 // current->signal->flags: (&init_signals)->flags: 0
 if ((clone_flags & CLONE_PARENT) &&
   current->signal->flags & SIGNAL_UNKILLABLE)
  return ERR_PTR(-EINVAL);

 /*
  * If the new process will be in a different pid or user namespace
  * do not allow it to share a thread group or signal handlers or
  * parent with the forking task.
  */
 // clone_flags: 0x00800B00, CLONE_SIGHAND: 0x00000800
 if (clone_flags & CLONE_SIGHAND) {
  // clone_flags: 0x00800B00, CLONE_NEWUSER: 0x10000000, CLONE_NEWPID: 0x20000000
  // current: &init_task, task_active_pid_ns(&init_task): &init_pid_ns,
  // current->nsproxy: (&init_task)->nsproxy: &init_nsproxy,
  // current->nsproxy->pid_ns_for_children: (&init_nsproxy)->pid_ns_for_children: &init_pid_ns
  if ((clone_flags & (CLONE_NEWUSER | CLONE_NEWPID)) ||
    (task_active_pid_ns(current) !=
     current->nsproxy->pid_ns_for_children))
   return ERR_PTR(-EINVAL);
 }

 // clone_flags: 0x00800B00, security_task_create(0x00800B00): 0
 retval = security_task_create(clone_flags);
 // retval: 0

 // retval: 0
 if (retval)
  goto fork_out;

 // ENOMEM: 12
 retval = -ENOMEM;
 // retval: -12

 // current: &init_task
 // dup_task_struct(&init_task): kmem_cache#15-oX (struct task_struct)
 p = dup_task_struct(current);
 // p: kmem_cache#15-oX (struct task_struct)

 // dup_task_struct 에서 한일:
 // struct task_struct 만큼의 메모리를 할당 받음
 // kmem_cache#15-oX (struct task_struct)
 //
 // struct thread_info 를 구성 하기 위한 메모리를 할당 받음 (8K)
 // 할당 받은 page 2개의 메로리의 가상 주소
 //
 // 할당 받은 kmem_cache#15-oX (struct task_struct) 메모리에 init_task 값을 전부 할당함
 //
 // (kmem_cache#15-oX (struct task_struct))->stack: 할당 받은 page 2개의 메로리의 가상 주소
 //
 // 할당 받은 kmem_cache#15-oX (struct task_struct) 의 stack의 값을 init_task 의 stack 값에서 전부 복사함
 // 복사된 struct thread_info 의 task 주소값을 할당 받은 kmem_cache#15-oX (struct task_struct)로 변경함
 // *(할당 받은 page 2개의 메로리의 가상 주소): init_thread_info
 // ((struct thread_info *) 할당 받은 page 2개의 메로리의 가상 주소)->task: kmem_cache#15-oX (struct task_struct)
 //
 // (((struct thread_info *)(할당 받은 page 2개의 메로리의 가상 주소))->flags 의 1 bit 값을 clear 수행
 //
 // *((unsigned long *)(할당 받은 page 2개의 메로리의 가상 주소 + 1)): 0x57AC6E9D
 //
 // (&(kmem_cache#15-oX (struct task_struct))->usage)->counter: 2
 // (kmem_cache#15-oX (struct task_struct))->splice_pipe: NULL
 // (kmem_cache#15-oX (struct task_struct))->task_frag.page: NULL
 //
 // (&contig_page_data)->node_zones[0].vm_stat[16]: 1 을 더함
 // vmstat.c의 vm_stat[16] 전역 변수에도 1을 더함

 // p: kmem_cache#15-oX (struct task_struct)
 if (!p)
  goto fork_out;

 // p: kmem_cache#15-oX (struct task_struct)
 ftrace_graph_init_task(p); // null function

 // p: kmem_cache#15-oX (struct task_struct)
 get_seccomp_filter(p); // null function

 // p: kmem_cache#15-oX (struct task_struct)
 rt_mutex_init_task(p);

 // rt_mutex_init_task 한일:
 // &(kmem_cache#15-oX (struct task_struct))->pi_lock을 사용한 spinlock 초기화
 // &(kmem_cache#15-oX (struct task_struct))->pi_waiters 리스트 초기화
 // (kmem_cache#15-oX (struct task_struct))->pi_blocked_on: NULL

#ifdef CONFIG_PROVE_LOCKING // CONFIG_PROVE_LOCKING=n
 DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled);
 DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
#endif
 // EAGAIN: 11
 retval = -EAGAIN;
 // retval: -11

 // p: kmem_cache#15-oX (struct task_struct)
 // p->real_cred: (kmem_cache#15-oX (struct task_struct))->real_cred: &init_cred,
 // p->real_cred->user: (&init_cred)->user: &root_user,
 // &p->real_cred->user->processes: &(&root_user)->processes, atomic_read(&(&root_user)->processes): 1
 // RLIMIT_NPROC: 6, task_rlimit(kmem_cache#15-oX (struct task_struct), 6): 0
 if (atomic_read(&p->real_cred->user->processes) >=
   task_rlimit(p, RLIMIT_NPROC)) {
  // p->real_cred->user: (&init_cred)->user: &root_user, INIT_USER: (&root_user)
  // CAP_SYS_RESOURCE: 24, capable(24): true, CAP_SYS_ADMIN: 21, capable(21): true
  if (p->real_cred->user != INIT_USER &&
      !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN))
   goto bad_fork_free;

  // capable 에서 한일:
  // (&init_task)->flags: 0x00200100
 }

 // current->flags: (&init_task)->flags: 0x00200100, PF_NPROC_EXCEEDED: 0x00001000
 current->flags &= ~PF_NPROC_EXCEEDED;
 // current->flags: (&init_task)->flags: 0x00200100

 // retval: -11, p: kmem_cache#15-oX (struct task_struct), clone_flags: 0x00800B00
 // copy_creds(kmem_cache#15-oX (struct task_struct), 0x00800B00): 0
 retval = copy_creds(p, clone_flags);
 // retval: 0

 // copy_creds 에서 한일:
 // struct cred 만큼의 메모리를 할당 받음
 // kmem_cache#16-oX (struct cred)
 //
 // kmem_cache#16-oX (struct cred) 에 init_cred 에 있는 맴버값 전부를 복사함
 // (&(kmem_cache#16-oX (struct cred))->usage)->counter: 1
 // (&(&init_groups)->usage)->counter: 3
 // (&(&root_user)->__count)->counter: 2
 // (&(&root_user)->processes)->counter: 2
 //
 // (&(kmem_cache#16-oX (struct cred))->usage)->counter: 2
 //
 // (kmem_cache#15-oX (struct task_struct))->cred: kmem_cache#16-oX (struct cred)
 // (kmem_cache#15-oX (struct task_struct))->real_cred: kmem_cache#16-oX (struct cred)

 // retval: 0
 if (retval < 0)
  goto bad_fork_free;

 /*
  * If multiple threads are within copy_process(), then this check
  * triggers too late. This doesn't hurt, the check is only there
  * to stop root fork bombs.
  */
 // EAGAIN: 11
 retval = -EAGAIN;
 // retval: -11

 // nr_threads: 0, max_threads: 총 free된 page 수 / 16
 if (nr_threads >= max_threads)
  goto bad_fork_cleanup_count;

 // p: kmem_cache#15-oX (struct task_struct),
 // task_thread_info(kmem_cache#15-oX (struct task_struct)):
 // (kmem_cache#15-oX (struct task_struct))->stack: 할당 받은 page 2개의 메로리의 가상 주소,
 // task_thread_info(kmem_cache#15-oX (struct task_struct)->exec_domain:
 // ((struct thread_info *) 할당 받은 page 2개의 메로리의 가상 주소)->exec_domain: &default_exec_domain,
 // task_thread_info(kmem_cache#15-oX (struct task_struct)->exec_domain->module:
 // (&default_exec_domain)->module: NULL,
 // try_module_get(NULL): true
 if (!try_module_get(task_thread_info(p)->exec_domain->module))
  goto bad_fork_cleanup_count;

 // p->did_exec: (kmem_cache#15-oX (struct task_struct))->did_exec
 p->did_exec = 0;
 // p->did_exec: (kmem_cache#15-oX (struct task_struct))->did_exec: 0

 // p: kmem_cache#15-oX (struct task_struct)
 delayacct_tsk_init(p); /* Must remain after dup_task_struct() */ // null function

 // clone_flags: 0x00800B00, p: kmem_cache#15-oX (struct task_struct)
 copy_flags(clone_flags, p);

 // copy_flags 에서 한일:
 // (kmem_cache#15-oX (struct task_struct))->flags: 0x00200040

 // &p->children: &(kmem_cache#15-oX (struct task_struct))->children
 INIT_LIST_HEAD(&p->children);

 // INIT_LIST_HEAD 에서 한일:
 // (&(kmem_cache#15-oX (struct task_struct))->children)->next: &(kmem_cache#15-oX (struct task_struct))->children
 // (&(kmem_cache#15-oX (struct task_struct))->children)->prev: &(kmem_cache#15-oX (struct task_struct))->children

 // &p->sibling: &(kmem_cache#15-oX (struct task_struct))->sibling
 INIT_LIST_HEAD(&p->sibling);

 // INIT_LIST_HEAD 에서 한일:
 // (&(kmem_cache#15-oX (struct task_struct))->sibling)->next: &(kmem_cache#15-oX (struct task_struct))->sibling
 // (&(kmem_cache#15-oX (struct task_struct))->sibling)->prev: &(kmem_cache#15-oX (struct task_struct))->sibling

 // p: kmem_cache#15-oX (struct task_struct)
 rcu_copy_process(p);

 // rcu_copy_process 에서 한일:
 // (kmem_cache#15-oX (struct task_struct))->rcu_read_lock_nesting: 0
 // (kmem_cache#15-oX (struct task_struct))->rcu_read_unlock_special: 0
 // (kmem_cache#15-oX (struct task_struct))->rcu_blocked_node: NULL
 // (&(kmem_cache#15-oX (struct task_struct))->rcu_node_entry)->next: &(kmem_cache#15-oX (struct task_struct))->rcu_node_entry
 // (&(kmem_cache#15-oX (struct task_struct))->rcu_node_entry)->prev: &(kmem_cache#15-oX (struct task_struct))->rcu_node_entry

 // p->vfork_done: (kmem_cache#15-oX (struct task_struct))->vfork_done
 p->vfork_done = NULL;
 // p->vfork_done: (kmem_cache#15-oX (struct task_struct))->vfork_done: NULL

 // &p->alloc_lock: &(kmem_cache#15-oX (struct task_struct))->alloc_lock
 spin_lock_init(&p->alloc_lock);

 // spin_lock_init에서 한일:
 // (&(kmem_cache#15-oX (struct task_struct))->alloc_lock)->raw_lock: { { 0 } }
 // (&(kmem_cache#15-oX (struct task_struct))->alloc_lock)->magic: 0xdead4ead
 // (&(kmem_cache#15-oX (struct task_struct))->alloc_lock)->owner: 0xffffffff
 // (&(kmem_cache#15-oX (struct task_struct))->alloc_lock)->owner_cpu: 0xffffffff

 // &p->pending: &(kmem_cache#15-oX (struct task_struct))->pending
 init_sigpending(&p->pending);

 // init_sigpending 에서 한일:
 // (&(&(kmem_cache#15-oX (struct task_struct))->pending)->signal)->sig[0]: 0
 // (&(&(kmem_cache#15-oX (struct task_struct))->pending)->signal)->sig[1]: 0
 // (&(&(kmem_cache#15-oX (struct task_struct))->pending)->list)->next: &(&(kmem_cache#15-oX (struct task_struct))->pending)->list
 // (&(&(kmem_cache#15-oX (struct task_struct))->pending)->list)->prev: &(&(kmem_cache#15-oX (struct task_struct))->pending)->list

 // p->utime: (kmem_cache#15-oX (struct task_struct))->utime,
 // p->stime: (kmem_cache#15-oX (struct task_struct))->stime,
 // p->gtime: (kmem_cache#15-oX (struct task_struct))->gtime
 p->utime = p->stime = p->gtime = 0;
 // p->utime: (kmem_cache#15-oX (struct task_struct))->utime: 0
 // p->stime: (kmem_cache#15-oX (struct task_struct))->stime: 0
 // p->gtime: (kmem_cache#15-oX (struct task_struct))->gtime: 0

 // p->utimescaled: (kmem_cache#15-oX (struct task_struct))->utimescaled,
 // p->stimescaled: (kmem_cache#15-oX (struct task_struct))->stimescaled
 p->utimescaled = p->stimescaled = 0;
 // p->utimescaled: (kmem_cache#15-oX (struct task_struct))->utimescaled: 0
 // p->stimescaled: (kmem_cache#15-oX (struct task_struct))->stimescaled: 0

#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE // CONFIG_VIRT_CPU_ACCOUNTING_NATIVE=n
 p->prev_cputime.utime = p->prev_cputime.stime = 0;
#endif
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN // CONFIG_VIRT_CPU_ACCOUNTING_GEN=n
 seqlock_init(&p->vtime_seqlock);
 p->vtime_snap = 0;
 p->vtime_snap_whence = VTIME_SLEEPING;
#endif

#if defined(SPLIT_RSS_COUNTING)
 // &p->rss_stat: &(kmem_cache#15-oX (struct task_struct))->rss_stat
 memset(&p->rss_stat, 0, sizeof(p->rss_stat));

 // memset 에서 한일:
 // &(kmem_cache#15-oX (struct task_struct))->rss_stat 값을 0 으로 초기화 수행
#endif

 // p->default_timer_slack_ns: (kmem_cache#15-oX (struct task_struct))->default_timer_slack_ns,
 // current->timer_slack_ns: (&init_task)->timer_slack_ns: 50000
 p->default_timer_slack_ns = current->timer_slack_ns;
 // p->default_timer_slack_ns: (kmem_cache#15-oX (struct task_struct))->default_timer_slack_ns: 50000

 // p->ioac: (kmem_cache#15-oX (struct task_struct))->ioac
 task_io_accounting_init(&p->ioac); // null function

 // p: kmem_cache#15-oX (struct task_struct)
 acct_clear_integrals(p); // null function

 // p: kmem_cache#15-oX (struct task_struct)
 posix_cpu_timers_init(p);

 // posix_cpu_timers_init 에서 한일:
 // (kmem_cache#15-oX (struct task_struct))->cputime_expires.prof_exp: 0
 // (kmem_cache#15-oX (struct task_struct))->cputime_expires.virt_exp: 0
 // (kmem_cache#15-oX (struct task_struct))->cputime_expires.sched_exp: 0
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[0])->next: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[0]
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[0])->prev: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[0]
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[1])->next: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[1]
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[1])->prev: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[1]
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[2])->next: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[2]
 // (&(kmem_cache#15-oX (struct task_struct))->cpu_timers[2])->prev: &(kmem_cache#15-oX (struct task_struct))->cpu_timers[2]

 // &p->start_time: &(kmem_cache#15-oX (struct task_struct))->start_time
 do_posix_clock_monotonic_gettime(&p->start_time);

 // do_posix_clock_monotonic_gettime 에서 한일:
 // (kmem_cache#15-oX (struct task_struct))->start_time 에 현재 시간 값을 가져옴
 //
 // (&(kmem_cache#15-oX (struct task_struct))->start_time)->tv_sec: 현재의 sec 값 + 현재의 nsec 값 / 1000000000L
 // (&(kmem_cache#15-oX (struct task_struct))->start_time)->tv_nsec: 현재의 nsec 값 % 1000000000L

 // p->real_start_time: (kmem_cache#15-oX (struct task_struct))->real_start_time,
 // p->start_time: (kmem_cache#15-oX (struct task_struct))->start_time
 p->real_start_time = p->start_time;
 // (&(kmem_cache#15-oX (struct task_struct))->real_start_time)->tv_sec: 현재의 sec 값 + 현재의 nsec 값 / 1000000000L
 // (&(kmem_cache#15-oX (struct task_struct))->real_start_time)->tv_nsec: 현재의 nsec 값 % 1000000000L

 // &p->real_start_time: &(kmem_cache#15-oX (struct task_struct))->real_start_time
 monotonic_to_bootbased(&p->real_start_time);

 // monotonic_to_bootbased 에서 한일:
 // (kmem_cache#15-oX (struct task_struct))->real_start_time.tv_sec: normalized 된 sec 값
 // (kmem_cache#15-oX (struct task_struct))->real_start_time.tv_nsec: normalized 된 nsec 값

 // p->io_context: (kmem_cache#15-oX (struct task_struct))->io_context
 p->io_context = NULL;
 // p->io_context: (kmem_cache#15-oX (struct task_struct))->io_context: NULL

 // p->audit_context: (kmem_cache#15-oX (struct task_struct))->audit_context
 p->audit_context = NULL;
 // p->audit_context: (kmem_cache#15-oX (struct task_struct))->audit_context: NULL

// 2016/09/10 종료
// 2016/10/08 시작

 // clone_flags: 0x00800B00, CLONE_THREAD: 0x00010000
 if (clone_flags & CLONE_THREAD)
  threadgroup_change_begin(current);

 // p: kmem_cache#15-oX (struct task_struct)
 cgroup_fork(p);

 // cgroup_fork 에서 한일:
 // rcu reference의 값 (&init_task)->cgroups 이 유요한지 체크하고 그 값을 리턴함
 // ((&init_task)->cgroups)->refcount: 1
 // (kmem_cache#15-oX (struct task_struct))->cgroups: (&init_task)->cgroups
 //
 // (&(kmem_cache#15-oX (struct task_struct))->cg_list)->next: &(kmem_cache#15-oX (struct task_struct))->cg_list
 // (&(kmem_cache#15-oX (struct task_struct))->cg_list)->prev: &(kmem_cache#15-oX (struct task_struct))->cg_list

#ifdef CONFIG_NUMA // CONFIG_NUMA=n
 p->mempolicy = mpol_dup(p->mempolicy);
 if (IS_ERR(p->mempolicy)) {
  retval = PTR_ERR(p->mempolicy);
  p->mempolicy = NULL;
  goto bad_fork_cleanup_cgroup;
 }
 mpol_fix_fork_child_flag(p);
#endif
#ifdef CONFIG_CPUSETS // CONFIG_CPUSETS=n
 p->cpuset_mem_spread_rotor = NUMA_NO_NODE;
 p->cpuset_slab_spread_rotor = NUMA_NO_NODE;
 seqcount_init(&p->mems_allowed_seq);
#endif
#ifdef CONFIG_TRACE_IRQFLAGS // CONFIG_TRACE_IRQFLAGS=n
 p->irq_events = 0;
 p->hardirqs_enabled = 0;
 p->hardirq_enable_ip = 0;
 p->hardirq_enable_event = 0;
 p->hardirq_disable_ip = _THIS_IP_;
 p->hardirq_disable_event = 0;
 p->softirqs_enabled = 1;
 p->softirq_enable_ip = _THIS_IP_;
 p->softirq_enable_event = 0;
 p->softirq_disable_ip = 0;
 p->softirq_disable_event = 0;
 p->hardirq_context = 0;
 p->softirq_context = 0;
#endif
#ifdef CONFIG_LOCKDEP // CONFIG_LOCKDEP=n
 p->lockdep_depth = 0; /* no locks held yet */
 p->curr_chain_key = 0;
 p->lockdep_recursion = 0;
#endif

#ifdef CONFIG_DEBUG_MUTEXES // CONFIG_DEBUG_MUTEXES=y
 // p->blocked_on: (kmem_cache#15-oX (struct task_struct))->blocked_on
 p->blocked_on = NULL; /* not blocked yet */
 // p->blocked_on: (kmem_cache#15-oX (struct task_struct))->blocked_on: NULL
#endif
#ifdef CONFIG_MEMCG // CONFIG_MEMCG=n
 p->memcg_batch.do_batch = 0;
 p->memcg_batch.memcg = NULL;
#endif
#ifdef CONFIG_BCACHE // CONFIG_BCACHE=n
 p->sequential_io = 0;
 p->sequential_io_avg = 0;
#endif

 /* Perform scheduler related setup. Assign this task to a CPU. */
 // clone_flags: 0x00800B00, p: kmem_cache#15-oX (struct task_struct)
 sched_fork(clone_flags, p);

sched_fork()

  • start_kernel()
    • rest_init()
  • call: rest_init()
    • rcu_scheduler_starting()
    • kernel_thread()
  • call: kernel_thread()
    • do_fork()
  • call: do_fork()
    • copy_process()
  • call: copy_process()
    • security_task_create()
    • dup_task_struct()
    • ftrace_graph_init_task(p); // null function
    • get_seccomp_filter(p); // null function
    • rt_mutex_init_task(p);
    • copy_creds(p, clone_flags);
    • try_module_get()
    • delayacct_tsk_init(p)
    • copy_flags()
    • INIT_LIST_HEAD(&p->children);
    • INIT_LIST_HEAD(&p->sibling);
    • rcu_copy_process(p);
    • spin_lock_init(&p->alloc_lock);
    • init_sigpending(&p->pending);
    • memset(&p->rss_stat, 0, sizeof(p->rss_stat));
    • task_io_accounting_init(&p->ioac); // null function
    • acct_clear_integrals(p); // null function
    • posix_cpu_timers_init(p);
    • do_posix_clock_monotonic_gettime(&p->start_time);
    • monotonic_to_bootbased(&p->real_start_time);
    • cgroup_fork(p);
    • sched_fork(clone_flags, p);
// ARM10C 20161008
// clone_flags: 0x00800B00, p: kmem_cache#15-oX (struct task_struct)
void sched_fork(unsigned long clone_flags, struct task_struct *p)
{
 unsigned long flags;

 // get_cpu(): 0
 int cpu = get_cpu();
 // cpu: 0

 // clone_flags: 0x00800B00, p: kmem_cache#15-oX (struct task_struct)
 __sched_fork(clone_flags, p);

 // __sched_fork에서 한일:
 // (&kmem_cache#15-oX (struct task_struct))->on_rq: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.on_rq: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.exec_start: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.sum_exec_runtime: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.prev_sum_exec_runtime: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.nr_migrations: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.vruntime: 0
 // &(&kmem_cache#15-oX (struct task_struct))->se.group_node의 리스트 초기화
 // &(&kmem_cache#15-oX (struct task_struct))->rt.run_list의 리스트 초기화

 /*
  * We mark the process as running here. This guarantees that
  * nobody will actually run it, and a signal or other external
  * event cannot wake it up and insert it on the runqueue either.
  */

 // p->state: (kmem_cache#15-oX (struct task_struct))->state, TASK_RUNNING: 0
 p->state = TASK_RUNNING;
 // p->state: (kmem_cache#15-oX (struct task_struct))->state: 0

 /*
  * Make sure we do not leak PI boosting priority to the child.
  */
 // p->prio: (kmem_cache#15-oX (struct task_struct))->prio,
 // current: &init_task, current->normal_prio: (&init_task)->normal_prio: 120
 p->prio = current->normal_prio;
 // p->prio: (kmem_cache#15-oX (struct task_struct))->prio: 120

 /*
  * Revert to default priority/policy on fork if requested.
  */
 // p->>sched_reset_on_fork: (kmem_cache#15-oX (struct task_struct))->sched_reset_on_fork: 0
 if (unlikely(p->sched_reset_on_fork)) {
  if (task_has_rt_policy(p)) {
   p->policy = SCHED_NORMAL;
   p->static_prio = NICE_TO_PRIO(0);
   p->rt_priority = 0;
  } else if (PRIO_TO_NICE(p->static_prio) < 0)
   p->static_prio = NICE_TO_PRIO(0);

  p->prio = p->normal_prio = __normal_prio(p);
  set_load_weight(p);

  /*
   * We don't need the reset flag anymore after the fork. It has
   * fulfilled its duty:
   */
  p->sched_reset_on_fork = 0;
 }

 // p->prio: (kmem_cache#15-oX (struct task_struct))->prio: 120, rt_prio(120): 0
 if (!rt_prio(p->prio))
  // p->sched_class: (kmem_cache#15-oX (struct task_struct))->sched_class
  p->sched_class = &fair_sched_class;
  // p->sched_class: (kmem_cache#15-oX (struct task_struct))->sched_class: &fair_sched_class

// 2016/10/15 종료

 // p->sched_class: (kmem_cache#15-oX (struct task_struct))->sched_class: &fair_sched_class,
 // p->sched_class->task_fork: (&fair_sched_class)->task_fork: task_fork_fair
 if (p->sched_class->task_fork)
  // p->sched_class->task_fork: (&fair_sched_class)->task_fork: task_fork_fair,
  // p: kmem_cache#15-oX (struct task_struct),
  // task_fork_fair(kmem_cache#15-oX (struct task_struct))
  p->sched_class->task_fork(p);

  // task_fork_fair 에서 한일:

 /*
  * The child is not yet in the pid-hash so no cgroup attach races,
  * and the cgroup is pinned to this child due to cgroup_fork()
  * is ran before sched_fork().
  *
  * Silence PROVE_RCU.
  */
 raw_spin_lock_irqsave(&p->pi_lock, flags);
 set_task_cpu(p, cpu);

set_task_cpu()

void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
{
#ifdef CONFIG_SCHED_DEBUG
 /*
  * We should never call set_task_cpu() on a blocked task,
  * ttwu() will sort out the placement.
  */
 WARN_ON_ONCE(p->state != TASK_RUNNING && p->state != TASK_WAKING &&
   !(task_preempt_count(p) & PREEMPT_ACTIVE));

#ifdef CONFIG_LOCKDEP
 /*
  * The caller should hold either p->pi_lock or rq->lock, when changing
  * a task's CPU. ->pi_lock for waking tasks, rq->lock for runnable tasks.
  *
  * sched_move_task() holds both and thus holding either pins the cgroup,
  * see task_group().
  *
  * Furthermore, all task_rq users should acquire both locks, see
  * task_rq_lock().
  */
 WARN_ON_ONCE(debug_locks && !(lockdep_is_held(&p->pi_lock) ||
          lockdep_is_held(&task_rq(p)->lock)));
#endif
#endif

 trace_sched_migrate_task(p, new_cpu);

 if (task_cpu(p) != new_cpu) {
  if (p->sched_class->migrate_task_rq)
   p->sched_class->migrate_task_rq(p, new_cpu);
  p->se.nr_migrations++;
  perf_sw_event(PERF_COUNT_SW_CPU_MIGRATIONS, 1, NULL, 0);
 }

 __set_task_cpu(p, new_cpu);
}

_settask_cpu()

// ARM10C 20140913
// idle: &init_task, cpu: 0
// ARM10C 20161015
// p: kmem_cache#15-oX (struct task_struct), this_cpu: 0
static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu)
{
 // p: &init_task, cpu: 0
 set_task_rq(p, cpu);

 // set_task_rq 에서 한일:
 // (&init_task)->se.cfs_rq: [pcp0] &(&runqueues)->cfs
 // (&init_task)->se.parent: NULL
 // (&init_task)->rt.rt_rq: [pcp0] &(&runqueues)->rt
 // (&init_task)->rt.parent: NULL

#ifdef CONFIG_SMP // CONFIG_SMP=y
 /*
  * After ->cpu is set up to a new value, task_rq_lock(p, ...) can be
  * successfuly executed on another CPU. We must ensure that updates of
  * per-task data have been completed by this moment.
  */
 smp_wmb();
 // memory barrier 수행

 // p: &init_task, cpu: 0
 // (&init_task)->stack: &init_thread_info
 // task_thread_info(&init_task)->cpu: ((struct thread_info *)(&init_task)->stack)->cpu
 task_thread_info(p)->cpu = cpu;
 // task_thread_info(&init_task)->cpu: ((struct thread_info *)(&init_task)->stack)->cpu: 0

 // p->wake_cpu: (&init_task)->wake_cpu, cpu: 0
 p->wake_cpu = cpu;
 // p->wake_cpu: (&init_task)->wake_cpu: 0
#endif
}

sched_fork()

// ARM10C 20161008
// clone_flags: 0x00800B00, p: kmem_cache#15-oX (struct task_struct)
void sched_fork(unsigned long clone_flags, struct task_struct *p)
{
 unsigned long flags;

 // get_cpu(): 0
 int cpu = get_cpu();
 // cpu: 0

 // clone_flags: 0x00800B00, p: kmem_cache#15-oX (struct task_struct)
 __sched_fork(clone_flags, p);

 // __sched_fork에서 한일:
 // (&kmem_cache#15-oX (struct task_struct))->on_rq: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.on_rq: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.exec_start: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.sum_exec_runtime: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.prev_sum_exec_runtime: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.nr_migrations: 0
 // (&kmem_cache#15-oX (struct task_struct))->se.vruntime: 0
 // &(&kmem_cache#15-oX (struct task_struct))->se.group_node의 리스트 초기화
 // &(&kmem_cache#15-oX (struct task_struct))->rt.run_list의 리스트 초기화

 /*
  * We mark the process as running here. This guarantees that
  * nobody will actually run it, and a signal or other external
  * event cannot wake it up and insert it on the runqueue either.
  */

 // p->state: (kmem_cache#15-oX (struct task_struct))->state, TASK_RUNNING: 0
 p->state = TASK_RUNNING;
 // p->state: (kmem_cache#15-oX (struct task_struct))->state: 0

 /*
  * Make sure we do not leak PI boosting priority to the child.
  */
 // p->prio: (kmem_cache#15-oX (struct task_struct))->prio,
 // current: &init_task, current->normal_prio: (&init_task)->normal_prio: 120
 p->prio = current->normal_prio;
 // p->prio: (kmem_cache#15-oX (struct task_struct))->prio: 120

 /*
  * Revert to default priority/policy on fork if requested.
  */
 // p->>sched_reset_on_fork: (kmem_cache#15-oX (struct task_struct))->sched_reset_on_fork: 0
 if (unlikely(p->sched_reset_on_fork)) {
  if (task_has_rt_policy(p)) {
   p->policy = SCHED_NORMAL;
   p->static_prio = NICE_TO_PRIO(0);
   p->rt_priority = 0;
  } else if (PRIO_TO_NICE(p->static_prio) < 0)
   p->static_prio = NICE_TO_PRIO(0);

  p->prio = p->normal_prio = __normal_prio(p);
  set_load_weight(p);

  /*
   * We don't need the reset flag anymore after the fork. It has
   * fulfilled its duty:
   */
  p->sched_reset_on_fork = 0;
 }

 // p->prio: (kmem_cache#15-oX (struct task_struct))->prio: 120, rt_prio(120): 0
 if (!rt_prio(p->prio))
  // p->sched_class: (kmem_cache#15-oX (struct task_struct))->sched_class
  p->sched_class = &fair_sched_class;
  // p->sched_class: (kmem_cache#15-oX (struct task_struct))->sched_class: &fair_sched_class

// 2016/10/15 종료

 // p->sched_class: (kmem_cache#15-oX (struct task_struct))->sched_class: &fair_sched_class,
 // p->sched_class->task_fork: (&fair_sched_class)->task_fork: task_fork_fair
 if (p->sched_class->task_fork)
  // p->sched_class->task_fork: (&fair_sched_class)->task_fork: task_fork_fair,
  // p: kmem_cache#15-oX (struct task_struct),
  // task_fork_fair(kmem_cache#15-oX (struct task_struct))
  p->sched_class->task_fork(p);

  // task_fork_fair 에서 한일:

 /*
  * The child is not yet in the pid-hash so no cgroup attach races,
  * and the cgroup is pinned to this child due to cgroup_fork()
  * is ran before sched_fork().
  *
  * Silence PROVE_RCU.
  */
 raw_spin_lock_irqsave(&p->pi_lock, flags);
 set_task_cpu(p, cpu);
 raw_spin_unlock_irqrestore(&p->pi_lock, flags);

#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
 if (likely(sched_info_on()))
  memset(&p->sched_info, 0, sizeof(p->sched_info));
#endif
#if defined(CONFIG_SMP)
 p->on_cpu = 0;
#endif
 init_task_preempt_count(p);
#ifdef CONFIG_SMP
 plist_node_init(&p->pushable_tasks, MAX_PRIO);
#endif

 put_cpu();
}

log

  • 1st log
bcc0aa2..af56134  master     -> origin/master
Updating bcc0aa2..af56134
Fast-forward
arch/arm/include/asm/atomic.h           |   4 +
arch/arm/include/asm/thread_info.h      |   1 +
fs/file.c                               | 135 +++++++++++++++++++++++++++
include/asm-generic/bitops/non-atomic.h |   2 +
include/asm-generic/bitsperlong.h       |   1 +
include/asm-generic/current.h           |   1 +
include/asm-generic/preempt.h           |  13 +++
include/linux/audit.h                   |   4 +-
include/linux/compiler-gcc.h            |   1 +
include/linux/fdtable.h                 |   8 ++
include/linux/fs.h                      |   1 +
include/linux/gfp.h                     |   1 +
include/linux/list.h                    |   4 +
include/linux/lockdep.h                 |   2 +
include/linux/perf_event.h              |   2 +
include/linux/plist.h                   |  16 ++++
include/linux/preempt.h                 |   4 +
include/linux/preempt_mask.h            |  15 +++
include/linux/rcupdate.h                |  29 +++++-
include/linux/sched.h                   |  17 +++-
include/linux/sched/rt.h                |   1 +
include/linux/sem.h                     |   2 +
include/linux/smp.h                     |   1 +
include/linux/spinlock.h                |   8 ++
include/linux/thread_info.h             |   3 +
include/trace/events/sched.h            |   2 +
include/uapi/asm-generic/errno-base.h   |   1 +
include/uapi/linux/sched.h              |   4 +
ipc/sem.c                               |   7 ++
kernel/fork.c                           | 159 +++++++++++++++++++++++++++++++-
kernel/locking/lockdep.c                |   2 +
kernel/rcu/update.c                     |   2 +-
kernel/sched/core.c                     |  79 ++++++++++++++--
kernel/sched/fair.c                     |   2 +-
kernel/sched/sched.h                    |   2 +
mm/slub.c                               |   2 +
36 files changed, 524 insertions(+), 14 deletions(-)