145주차 (2016.05.28) vfs_caches_init()


#1
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(-)