146주차 (2016.06.04) page_witeback_init()


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

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

146주차 진도

  • 146차 시작 위치
  • start_kernel 1 ~/init/main.c
  • page_writeback_init 933 ~/init/main.c
  • writeback_set_ratelimit 1899 writeback_set_ratelimit();
  • global_dirty_limits 1851 global_dirty_limits(&background_thresh, &dirty_thresh);

146주차 함수 호출 구조

  • calll: start_kernel()
  • page_writeback_init()
  • call: page_write_back_init()
  • wirteback_set_ratelimit()
  • call: wirteback_set_ratelimit()
  • global_dirty_limits()

main.c::start_kernel()

  • calll: start_kernel()
  • page_writeback_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);
	// 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.c::page_writeback_init()

  • calll: start_kernel()
  • page_writeback_init()
// ARM10C 20160528
void __init page_writeback_init(void)
{
	writeback_set_ratelimit();

page-writeback.c::writeback_set_ratelimit()

  • calll: start_kernel()
  • page_writeback_init()
  • call: page_write_back_init()
  • wirteback_set_ratelimit()
// ARM10C 20160528
void writeback_set_ratelimit(void)
{
	unsigned long background_thresh;
	unsigned long dirty_thresh;
	global_dirty_limits(&background_thresh, &dirty_thresh);

page-writeback.c::global_dirty_limits()

  • calll: start_kernel()
  • page_writeback_init()
  • call: page_write_back_init()
  • wirteback_set_ratelimit()
  • call: writeback_set_ratelimit()
  • global_dirty_limits()
// ARM10C 20160528
// &background_thresh, &dirty_thresh
void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty)
{
	unsigned long background;
	unsigned long dirty;
	
	// uninitialized_var(available_memory):
	// available_memory = available_memory
	unsigned long uninitialized_var(available_memory);
	struct task_struct *tsk;

	// vm_dirty_bytes: 0, dirty_background_bytes: 0
	if (!vm_dirty_bytes || !dirty_background_bytes)
		// global_dirtyable_memory(): 1
		available_memory = global_dirtyable_memory();
		// available_memory: 1

// 2016/05/28 종료

	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::writeback_set_ratelimit()

  • calll: start_kernel()
  • page_writeback_init()
  • call: page_write_back_init()
  • wirteback_set_ratelimit()
// ARM10C 20160528
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);

cpumask.h::num_online_cpus()

  • calll: start_kernel()
  • page_writeback_init()
  • call: page_write_back_init()
  • wirteback_set_ratelimit()
  • call: writeback_set_ratelimit()
  • global_dirty_limits()
  • num_online_cpus()
#define num_online_cpus()	cpumask_weight(cpu_online_mask)

cpumask.h::num_online_cpus()

  • calll: start_kernel()
  • page_writeback_init()
  • call: page_write_back_init()
  • wirteback_set_ratelimit()
  • call: writeback_set_ratelimit()
  • global_dirty_limits()
  • num_online_cpus()
#if NR_CPUS > 1
#define num_online_cpus()	cpumask_weight(cpu_online_mask)

page-writeback.c::writeback_set_ratelimit()

  • calll: start_kernel()
  • page_writeback_init()
  • call: page_write_back_init()
  • wirteback_set_ratelimit()
// ARM10C 20160528
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::page_writeback_init()

  • calll: start_kernel()
  • page_writeback_init()
// ARM10C 20160528
void __init page_writeback_init(void)
{
	writeback_set_ratelimit();
	register_cpu_notifier(&ratelimit_nb);
  • page_writeback_init() 이 한일 .

main.c::start_kernel()

  • calll: start_kernel()
  • page_writeback_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);
	// 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();
#ifdef CONFIG_PROC_FS CONFIG_PROC_FS=y
	proc_root_init();
#endif

root.c::proc_root_init()

  • calll: start_kernel()
  • page_writeback_init()
  • proc_root_init()
void __init proc_root_init(void)
{
	int err;

	proc_init_inodecache();

inode.c::proc_init_inodecache()

  • calll: start_kernel()
  • page_writeback_init()
  • proc_root_init()
  • proc_root_init()
  • proc_init_inodecache()
  • struct proc_inode()
struct proc_inode {
	struct pid *pid;
	int fd;
	union proc_op op;
	struct proc_dir_entry *pde;
	struct ctl_table_header *sysctl;
	struct ctl_table *sysctl_entry;
	struct proc_ns ns;
	struct inode vfs_inode;
};
  • SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD | SLAB_PANIC
#define SLAB_RECLAIM_ACCOUNT	0x00020000UL		/* Objects are reclaimable */
#define SLAB_MEM_SPREAD		0x00100000UL	/* Spread some memory over cpuset */
#define SLAB_PANIC		0x00040000UL	/* Panic if kmem_cache_create() fails */
void __init proc_init_inodecache(void)
{
	proc_inode_cachep = kmem_cache_create("proc_inode_cache",
					     sizeof(struct proc_inode),
					     0, (SLAB_RECLAIM_ACCOUNT|
						SLAB_MEM_SPREAD|SLAB_PANIC),
					     init_once);
}
  • proc_init_inodecache() 가 한일

root.c::proc_root_init()

  • calll: start_kernel()
  • page_writeback_init()
  • proc_root_init()
  • proc_root_init()
  • proc_init_inodecache()
void __init proc_root_init(void)
{
	int err;

	proc_init_inodecache();
	err = register_filesystem(&proc_fs_type);

filesystem.c::register_filesystem()

  • calll: start_kernel()
  • page_writeback_init()
  • proc_root_init()
  • proc_root_init()
  • proc_init_inodecache()
  • register_filesystem()
static struct file_system_type proc_fs_type = {
	.name		= "proc",
	.mount		= proc_mount,
	.kill_sb	= proc_kill_sb,
	.fs_flags	= FS_USERNS_MOUNT,
};
// ARM10C 20160521
// &bd_type
int register_filesystem(struct file_system_type * fs)
{
	int res = 0;
	// res: 0

	struct file_system_type ** p;

	// fs->name: (&proc_fs_type)->name: "proc", strchr("proc", '.'): NULL
	BUG_ON(strchr(fs->name, '.'));

	// fs->next: (&proc_fs_type)->next: NULL
	if (fs->next)
		return -EBUSY;

	write_lock(&file_systems_lock);
	// write_lock에서 한일:
	// &file_systems_lock 을 사용한 write lock 수행

	// fs->name: (&proc_fs_type)->name: "proc", strlen("proc"): 4
	// find_filesystem("proc", 4): &(&bd-type)->next
	p = find_filesystem(fs->name, strlen(fs->name));
	// p: &file_systems
	// p: &(&sysfs_fs_type)->next
	// p: &(&rootfs_fs_type)->next
	// p: &(&shmem_fs_type)->next
	// p: &(&bd_type)->next
    
	// *p: file_systems: NULL
	// *p: (&sysfs_fs_type)->next: NULL
	// *p: (&rootfs_fs_type)->next: NULL
	// *p: (&shmem_fs_type)->next: NULL
	// *p: (&bd_type)->next: NULL
	if (*p)
		res = -EBUSY;
	else
		// *p: file_systems: NULL, fs: &sysfs_fs_type
		// *p: (&sysfs_fs_type)->next: NULL, fs: &rootfs_fs_type
		// *p: (&rootfs_fs_type)->next: NULL, fs: &shmem_fs_type
		// *p: (&shmem_fs_type)->next: NULL, fs: &bd_type
		// *p: (&bd_type)->next: NULL, fs: &proc_fs_type
		*p = fs;
		// *p: file_systems: &sysfs_fs_type
		// *p: (&sysfs_fs_type)->next: &rootfs_fs_type
		// *p: (&rootfs_fs_type)->next: &shmem_fs_type
		// *p: (&shmem_fs_type)->next: &bd_type
		// *p: (&bd_type)->next: &proc_fs_type
        
	write_unlock(&file_systems_lock);

	// write_unlock에서 한일:
	// &file_systems_lock 을 사용한 write lock 수행

	// res: 0
	return res;
	// return 0
}
  • register_filesystem()이 한일

root.c::proc_root_init()

  • calll: start_kernel()
  • page_writeback_init()
  • proc_root_init()
  • proc_root_init()
  • proc_init_inodecache()
  • register_filesystem()
void __init proc_root_init(void)
{
	int err;

	proc_init_inodecache();
	err = register_filesystem(&proc_fs_type);

	if (err)
		return;

	proc_self_init();

self.c::proc_self_init()

  • calll: start_kernel()
  • page_writeback_init()
  • proc_root_init()
  • call: proc_root_init()
  • proc_init_inodecache()
  • register_filesystem()
  • proc_self_init()
  • call: proc_self_init()
void __init proc_self_init(void)
{
	proc_alloc_inum(&self_inum);
}

self.c::proc_self_init()

  • calll: start_kernel()
  • page_writeback_init()
  • proc_root_init()
  • call: proc_root_init()
  • proc_init_inodecache()
  • register_filesystem()
  • proc_self_init()
  • call: proc_self_init()
// ARM10C 20160514
// &new_ns->proc_inum: &(kmem_cache#30-oX (struct mnt_namespace))->proc_inum
int proc_alloc_inum(unsigned int *inum)
{
	unsigned int i;
	int error;

retry:
	// GFP_KERNEL: 0xD0, ida_pre_get(&proc_inum_ida, 0xD0): 1
	if (!ida_pre_get(&proc_inum_ida, GFP_KERNEL))
		return -ENOMEM;

	// ida_pre_get 에서 한일:
	// idr_layer_cache를 사용하여 struct idr_layer 의 메모리 kmem_cache#21-o0...7를 8 개를 할당 받음
	//
	// (&(&proc_inum_ida)->idr)->id_free 이 idr object 8 번을 가르킴
	// |
	// |-> ---------------------------------------------------------------------------------------------------------------------------
	//     | idr object 8         | idr object 7         | idr object 6         | idr object 5         | .... | idr object 0         |
	//     ---------------------------------------------------------------------------------------------------------------------------
	//     | ary[0]: idr object 7 | ary[0]: idr object 6 | ary[0]: idr object 5 | ary[0]: idr object 4 | .... | ary[0]: NULL         |
	//     ---------------------------------------------------------------------------------------------------------------------------
	//
	// (&(&proc_inum_ida)->idr)->id_free: kmem_cache#21-oX (idr object 8)
	// (&(&proc_inum_ida)->idr)->id_free_cnt: 8

	spin_lock_irq(&proc_inum_lock);

	// spin_lock_irq 에서 한일:
	// &proc_inum_lock 을 사용하여 spin lock을 수행

	// ida_get_newa(&proc_inum_ida, &i): 0
	error = ida_get_new(&proc_inum_ida, &i);
	// error: 0

	// ida_get_new 에서 한일:
	// (&(&proc_inum_ida)->idr)->id_free: kmem_cache#21-oX (idr object 6)
	// (&(&proc_inum_ida)->idr)->id_free_cnt: 6
	// (&(&proc_inum_ida)->idr)->layers: 1
	// ((&(&proc_inum_ida)->idr)->top): kmem_cache#21-oX (idr object 8)
	//
	// (kmem_cache#21-oX (idr object 8))->layer: 0
	// kmem_cache#21-oX (struct idr_layer) (idr object 8)
	// ((kmem_cache#21-oX (struct idr_layer) (idr object 8))->ary[0]): (typeof(*kmem_cache#27-oX (struct ida_bitmap)) __force space *)(kmem_cache#27-oX (struct ida_bitmap))
	// (kmem_cache#21-oX (struct idr_layer) (idr object 8))->count: 1
	//
	// (&proc_inum_ida)->free_bitmap: NULL
	// kmem_cache#27-oX (struct ida_bitmap) 메모리을 0으로 초기화
	// (kmem_cache#27-oX (struct ida_bitmap))->nr_busy: 1
	// (kmem_cache#27-oX (struct ida_bitmap))->bitmap 의 0 bit를 1로 set 수행
	//
	// i: 0
	//
	// kmem_cache인 kmem_cache#21 에서 할당한 object인 kmem_cache#21-oX (idr object 7) 의 memory 공간을 반환함

	spin_unlock_irq(&proc_inum_lock);

	// spin_unlock_irq 에서 한일:
	// &proc_inum_lock 을 사용하여 spin lock을 수행

	// error: 0
	if (error == -EAGAIN)
		goto retry;
	else if (error)
		return error;

	// i: 0, UINT_MAX: 0xFFFFFFFF, PROC_DYNAMIC_FIRST: 0xF0000000
	if (i > UINT_MAX - PROC_DYNAMIC_FIRST) {
		spin_lock_irq(&proc_inum_lock);
		ida_remove(&proc_inum_ida, i);
		spin_unlock_irq(&proc_inum_lock);
		return -ENOSPC;
	}

	// *inum: (kmem_cache#30-oX (struct mnt_namespace))->proc_inum,
	// PROC_DYNAMIC_FIRST: 0xF0000000, i: 0
	*inum = PROC_DYNAMIC_FIRST + i;
	// *inum: (kmem_cache#30-oX (struct mnt_namespace))->proc_inum: 0xF0000000

	return 0;
	// return 0
}

root.c::proc_root_init()

  • calll: start_kernel()
  • page_writeback_init()
  • proc_root_init()
  • proc_root_init()
  • proc_init_inodecache()
  • register_filesystem()
  • proc_self_init()
void __init proc_root_init(void)
{
	int err;

	proc_init_inodecache();
	err = register_filesystem(&proc_fs_type);
	if (err)
		return;

	proc_self_init();
	proc_symlink("mounts", NULL, "self/mounts");

generic.c::proc_symlink()

  • calll: start_kernel()
  • page_writeback_init()
  • proc_root_init()
  • proc_root_init()
  • proc_init_inodecache()
  • register_filesystem()
  • proc_self_init()
  • proc_symlink()
struct proc_dir_entry *proc_symlink(const char *name,
		struct proc_dir_entry *parent, const char *dest)
{
	struct proc_dir_entry *ent;

	ent = __proc_create(&parent, name,
			  (S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO),1);

generic.c::__proc_create()

  • calll: start_kernel()
  • page_writeback_init()
  • proc_root_init()
  • proc_root_init()
  • proc_init_inodecache()
  • register_filesystem()
  • proc_self_init()
  • proc_symlink()
  • call: proc_symlink()
static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
					  const char *name,
					  umode_t mode,
					  nlink_t nlink)
{
	struct proc_dir_entry *ent = NULL;
	const char *fn = name;
	unsigned int len;

	/* make sure name is valid */
	if (!name || !strlen(name))
		goto out;

	if (xlate_proc_name(name, parent, &fn) != 0)
		goto out;

	/* At this point there must not be any '/' characters beyond *fn */
	if (strchr(fn, '/'))
		goto out;

	len = strlen(fn);

	ent = kzalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL);
	if (!ent)
		goto out;

	memcpy(ent->name, fn, len + 1);
	ent->namelen = len;
	ent->mode = mode;
	ent->nlink = nlink;
	atomic_set(&ent->count, 1);
	spin_lock_init(&ent->pde_unload_lock);
	INIT_LIST_HEAD(&ent->pde_openers);
out:
	return ent;
}