2016년 5월 28일 토요일

145주차 (2016.05.28) vfs_caches_init()

Neuromancer : 145 주차
일시 : 2016.05.28 (145주차 스터디 진행)
모임명 : Neuromancer_ARM
장소 : 토즈 서현점
장소지원 : 공개 소프트웨어 개발자 커뮤니티 지원 프로그램
참여인원 : 2명
============

145주차 진도

  • 145차 시작 위치
    • start_kernel 1 ~/init/main.c
    • vfs_caches_init 925 ~/init/main.c
    • chrdev_init 6005 ~/fs/dcache.c

145주차 함수 호출 구조

  • calll: start_kernel()-> vfs_caches_init()
    • kmem_cache_create(): names_cache
    • dcache_init()
    • inode_init()
    • files_init()
    • mnt_init()
    • bdev_cache_init()
    • chrdev_init()

main.c::start_kernel()

  • call: start_kernel()->vfs_caches_init()
asmlinkage void __init start_kernel(void)
{
 char * command_line;
 extern const struct kernel_param __start___param[], __stop___param[];
 // ATAG,DTB 정보로 사용

...

    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);
## dcache.c::vfs_caches_init() * call: start_kernel() - vfs_caches_init() - kmem_cache_create(): names_cache - dcache_init() - inode_init() - files_init() - mnt_init() - bdev_cache_init() - chrdev_init()
// ARM10C 20151003
// totalram_pages: 총 free된 page 수
void __init vfs_caches_init(unsigned long mempages)
{
 unsigned long reserve;

    /* Base hash sizes on available memory, with a reserve equal to
       150% of current kernel size */

// NOTE:
// mempages 값과 nr_free_pages() 의 값을 정확히 알 수 없음
// 계산된 reserve의 값을 XXX 로 함

// mempages: 총 free된 page 수, nr_free_pages(): 현재의 free pages 수
reserve = min((mempages - nr_free_pages()) * 3/2, mempages - 1);
// reserve: XXX

// mempages: 총 free된 page 수, reserve: XXX
mempages -= reserve;
// mempages: 총 free된 page 수 - XXX

// PATH_MAX: 4096
// SLAB_HWCACHE_ALIGN: 0x00002000UL, SLAB_PANIC: 0x00040000UL
// kmem_cache_create("names_cache", 4096, 0, 0x42000, NULL): kmem_cache#6
names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,
  SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
// names_cachep: kmem_cache#6

dcache_init();

inode_init();

// mempages: 총 free된 page 수 - XXX
files_init(mempages);

mnt_init();
...

    bdev_cache_init();
// bdev_cache_init 에서 한일:
// struct bdev_inode를 위한 bdev_cache 용 kmem_cache 를 생성함 bdev_cachep: kmem_cache#n#30

chrdev_init();
}
## char_dev.c::chrdev_init() * call: start_kernel() - vfs_caches_init() - kmem_cache_create(): names_cache - dcache_init() - inode_init() - files_init() - mnt_init() - bdev_cache_init() - chrdev_init()
// ARM10C 20160521
void __init chrdev_init(void)
{
 // kobj_map_init(base_probe, &chrdevs_lock): kmem_cache#26-oX (struct kobj_map)
 cdev_map = kobj_map_init(base_probe, &chrdevs_lock);
 // cdev_map: kmem_cache#26-oX (struct kobj_map)

    // kobj_map_init 에서 한일:
// struct kobj_map 만큼의 메로리를 할당 받음 kmem_cache#26-oX (struct kobj_map)
// struct probe 만큼의 메로리를 할당 받음 kmem_cache#30-oX (struct probe)
//
// (kmem_cache#30-oX (struct probe))->dev: 1
// (kmem_cache#30-oX (struct probe))->range: 0xFFFFFFFF
// (kmem_cache#30-oX (struct probe))->get: base_probe
//
// (kmem_cache#26-oX (struct kobj_map))->probes[0...255]: kmem_cache#30-oX (struct probe)
// (kmem_cache#26-oX (struct kobj_map))->lock: &chrdevs_lock
// 2016/05/21 종료

    if (bdi_init(&directly_mappable_cdev_bdi))
 panic("Failed to init directly mappable cdev bdi");
}
## backing-dev.c::bdi_init() * call: start_kernel() - vfs_caches_init() - kmem_cache_create(): names_cache - dcache_init() - inode_init() - files_init() - mnt_init() - bdev_cache_init() - chrdev_init() * call: chrdev_init() - bdi_init() ## main.c::start_kernel() * call: start_kernel()->vfs_caches_init()
asmlinkage void __init start_kernel(void)
{
 char * command_line;
 extern const struct kernel_param __start___param[], __stop___param[];
 // ATAG,DTB 정보로 사용

...

    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);

signals_init();
## signal.c::signals_init() * call: start_kernel() - vfs_caches_init() - signals_init() * struct sigque
struct sigqueue {
 struct list_head list;
 int flags;
 siginfo_t info;
 struct user_struct *user;
};
* struct siginfo_t
// ARM10C 20150919
typedef struct siginfo {
 int si_signo;
 int si_errno;
 int si_code;

    union {
 int _pad[SI_PAD_SIZE];

 /* kill() */
 struct {
  __kernel_pid_t _pid; /* sender's pid */
  __ARCH_SI_UID_T _uid; /* sender's uid */
 } _kill;

 /* POSIX.1b timers */
 struct {
  __kernel_timer_t _tid; /* timer id */
  int _overrun;  /* overrun count */
  char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)];
  sigval_t _sigval; /* same as below */
  int _sys_private;       /* not to be passed to user */
 } _timer;

 /* POSIX.1b signals */
 struct {
  __kernel_pid_t _pid; /* sender's pid */
  __ARCH_SI_UID_T _uid; /* sender's uid */
  sigval_t _sigval;
 } _rt;

 /* SIGCHLD */
 struct {
  __kernel_pid_t _pid; /* which child */
  __ARCH_SI_UID_T _uid; /* sender's uid */
  int _status;  /* exit code */
  __ARCH_SI_CLOCK_T _utime;
  __ARCH_SI_CLOCK_T _stime;
 } _sigchld;

 /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
 struct {
  void __user *_addr; /* faulting insn/memory ref. */
#ifdef __ARCH_SI_TRAPNO
   int _trapno; /* TRAP # which caused the signal */
#endif
   short _addr_lsb; /* LSB of the reported address */
  } _sigfault;

     /* SIGPOLL */
 struct {
  __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */
  int _fd;
 } _sigpoll;

 /* SIGSYS */
 struct {
  void __user *_call_addr; /* calling user insn */
  int _syscall; /* triggering system call number */
  unsigned int _arch; /* AUDIT_ARCH_* of syscall */
 } _sigsys;
} _sifields;
} __ARCH_SI_ATTRIBUTES siginfo_t;
* code
void __init signals_init(void)
{
 sigqueue_cachep = KMEM_CACHE(sigqueue, SLAB_PANIC);
}
## main.c::start_kernel() * call: start_kernel()
asmlinkage void __init start_kernel(void)
{
 char * command_line;
 extern const struct kernel_param __start___param[], __stop___param[];
 // ATAG,DTB 정보로 사용

...

    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);

signals_init();

page_writeback_init();
## page-writeback.c::page_writeback_init() * call: start_kernel() - vfs_caches_init() - signals_init() - page_writeback_init()
void __init page_writeback_init(void)
{
 writeback_set_ratelimit();
 register_cpu_notifier(&ratelimit_nb);

    fprop_global_init(&writeout_completions);
}
## page-writeback.c::write_set_rate_limit() * call: start_kernel() - vfs_caches_init() - signals_init() - page_writeback_init() * call: page_writeback_init() - write_set_rate_limit()
void writeback_set_ratelimit(void)
{
 unsigned long background_thresh;
 unsigned long dirty_thresh;
 global_dirty_limits(&background_thresh, &dirty_thresh);
 global_dirty_limit = dirty_thresh;
 ratelimit_pages = dirty_thresh / (num_online_cpus() * 32);
 if (ratelimit_pages < 16)
  ratelimit_pages = 16;
}
## page-writeback.c::global_dirty_limits() * call: start_kernel() - vfs_caches_init() - signals_init() - page_writeback_init() * call: page_writeback_init() - write_set_rate_limit() * call: write_set_rate_limit() - global_dirty_limits()
void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty)
{
 unsigned long background;
 unsigned long dirty;
 unsigned long uninitialized_var(available_memory);
 struct task_struct *tsk;

    if (!vm_dirty_bytes || !dirty_background_bytes)
 available_memory = global_dirtyable_memory();

if (vm_dirty_bytes)
 dirty = DIV_ROUND_UP(vm_dirty_bytes, PAGE_SIZE);
else
 dirty = (vm_dirty_ratio * available_memory) / 100;

if (dirty_background_bytes)
 background = DIV_ROUND_UP(dirty_background_bytes, PAGE_SIZE);
else
 background = (dirty_background_ratio * available_memory) / 100;

if (background >= dirty)
 background = dirty / 2;
tsk = current;
if (tsk->flags & PF_LESS_THROTTLE || rt_task(tsk)) {
 background += background / 4;
 dirty += dirty / 4;
}
*pbackground = background;
*pdirty = dirty;
trace_global_dirty_state(background, dirty);
}
## page-writeback.c::global_dirtyable_memory() * call: start_kernel() - vfs_caches_init() - signals_init() - page_writeback_init() * call: page_writeback_init() - write_set_rate_limit() * call: write_set_rate_limit() - global_dirty_limits() * call: global_dirty_limits() - global_dirtyable_memory()
static unsigned long global_dirtyable_memory(void)
{
 unsigned long x;

    x = global_page_state(NR_FREE_PAGES);
x -= min(x, dirty_balance_reserve);

x += global_page_state(NR_INACTIVE_FILE);
x += global_page_state(NR_ACTIVE_FILE);

if (!vm_highmem_is_dirtyable)
 x -= highmem_dirtyable_memory(x);

return x + 1; /* Ensure that we never return 0 */
}
## highmem_dirtyable_memory() * call: start_kernel() - vfs_caches_init() - signals_init() - page_writeback_init() * call: page_writeback_init() - write_set_rate_limit() * call: write_set_rate_limit() - global_dirty_limits() * call: global_dirty_limits() - global_dirtyable_memory() * call: highmem_dirtyable_memory()
static unsigned long highmem_dirtyable_memory(unsigned long total)
{
#ifdef CONFIG_HIGHMEM
 int node;
 unsigned long x = 0;

    for_each_node_state(node, N_HIGH_MEMORY) {
 struct zone *z = &NODE_DATA(node)->node_zones[ZONE_HIGHMEM];

 x += zone_dirtyable_memory(z);
}
/*
 * Unreclaimable memory (kernel memory or anonymous memory
 * without swap) can bring down the dirtyable pages below
 * the zone's dirty balance reserve and the above calculation
 * will underflow.  However we still want to add in nodes
 * which are below threshold (negative values) to get a more
 * accurate calculation but make sure that the total never
 * underflows.
 */
if ((long)x < 0)
 x = 0;

/*
 * Make sure that the number of highmem pages is never larger
 * than the number of the total dirtyable memory. This can only
 * occur in very strange VM situations but we want to make sure
 * that this does not occur.
 */
return min(x, total);
#else
 return 0;
#endif
}
# log
2518303..f8ce6b6  master     -> origin/master
Updating 2518303..f8ce6b6
Fast-forward
fs/char_dev.c                      | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
fs/dcache.c                        | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/backing-dev.h        |  1 +
include/linux/compiler-gcc.h       |  1 +
include/linux/mmzone.h             |  6 ++++++
include/linux/nodemask.h           |  2 ++
include/linux/sched.h              |  1 +
include/linux/signal.h             |  2 ++
include/linux/slab.h               |  4 ++++
include/linux/slub_def.h           |  1 +
include/linux/vmstat.h             |  6 ++++++
include/linux/writeback.h          |  2 ++
include/uapi/asm-generic/siginfo.h | 11 +++++++++++
init/main.c                        |  5 +++++
kernel/signal.c                    | 12 ++++++++++++
mm/backing-dev.c                   |  2 ++
mm/page-writeback.c                | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
mm/page_alloc.c                    |  1 +
mm/slab_common.c                   |  5 +++++
19 files changed, 260 insertions(+), 2 deletions(-)