"criu dump命令流程分析"

  "criu checkpoint三"

Posted by Xu on June 6, 2017

CRIU-dump命令流程分析

根据上一章节的CRIU命令参数分析我们可以找到各命令指定执行函数,当我们执行criu dump命令时,我们经过参数分析知道dump的执行函数为cr_dump_tasks(),由于criu dump命令和我们的眼睛课题中对Docker容器的checkpoint的实现具有直接的关系,所以我们将在这一小节来具体研究dump备份过程即cr_dump_tasks()的实现

cr_dump_tasks的源码非常复杂,但步骤清晰,我们以局部分析的方式来了解dump备份过程:

首先看该函数在开头的准备工作:

 int cr_dump_tasks(pid_t pid)
{
	InventoryEntry he = INVENTORY_ENTRY__INIT;
	struct pstree_item *item;//定义进程树节点结构体
	int pre_dump_ret = 0;
	int ret = -1;
	pr_info("========================================\n");
	pr_info("Dumping processes (pid: %d)\n", pid);
	pr_info("========================================\n");
	root_item = alloc_pstree_item();//首先分配进程树根节点内存空间
	if (!root_item)
		goto err;
	root_item->pid->real = pid;
	pre_dump_ret = run_scripts(ACT_PRE_DUMP);//进行pre-dump
	if (pre_dump_ret != 0) {
		pr_err("Pre dump script failed with %d!\n", pre_dump_ret);
		goto err;
	}
	...
	}

该函数在相关生命后进入dump备份的具体流程:

1.init_stats(DUMP_STATS)//初始化备份dump状态信息,分配内存空间存放dump_stats结构体信息:

struct dump_stats {
	struct timing	timings[DUMP_TIME_NR_STATS];//保存了备份各个步骤的开始时间和花费时间信息
	unsigned long	counts[DUMP_CNT_NR_STATS];
};

2.cr_plugins_init(cr_plugins_stage_dump)

初始化链表头->设置函数库目录opts.libdir->循环读取库目录readdir()函数读取目录的下一入口,循环读取并cr_lib_load()加载库函数(加载步骤:dlopen()打开动态链接库返回句柄h,dlsym(h,”CR_PLUGINS_DESC”)通过调用句柄可以找到函数库中指定函数名称的函数指针并返回调用)

3.kerndat_init()

  • 加载缓存cache,读取内核缓存文件criu.kdat
  • 预加载socket_module
  • 预加载网络过滤器模块
  • 读取proc目录下内存页面并检查pread(fd,&pfn,sizeof(pfn),offset)读取文件带有偏移量的指定大小的数据
  • kerndat_get_shmemdev()获取共享内存:首先mmap将文件映射到内存,返回映射内存地址,根据内存地址将内存写入maps对象,通过stat(maps,&buf)函数获取maps对象信息写至buf对象,设置dev=buf.st_dev,最后mumap(start,length)关闭内存映射
  • kerndat_get_dirty_track():将文件映射到内存->do_task_reset_dirty_track(pid)重置脏bit标示位->打开proc配置文件,读取相关内容->取消内存映射。
  • init_zero_page_pfn()初始化零页面帧号
  • get_last_cap():定义了一个系统调用请求结构体req,根据req相关信息进行系统调用sysctl_op
  • kerndat_fdinfo_has_lock():打开proc目录下locks文件,在根据pid获取指定proc下锁文件内容
  • get_task_size():获取任务大小
  • get_ipv6():进入/proc/sys/net/ipv6目录获取ipv6地址
  • kerndat_loginuid():登录uid?
  • kerndat_iptables_has_xlocaks():调用cr_system()对userns进行C/R?
  • kerndat_tcp_repair():修复内核tcp连接
  • kerndat_compat_restore():内核兼容性恢复
  • kerndat_has_memfd_create():创建内存文件描述符。
  • kerndat_lsm():内核安全模块
  • kerndat_mmap_min_addr():内存映射最小地址?
  • kerndat_save_cache():内核缓存保存至缓存文件

4.irmap_load_cache():这个步骤不能理解

5.cpu_init():初始化cpu信息

6.vdso_init():vdso全称:Virtual Dynamically-linked Shared Object用于将内核态的调用映射到用户态,便于Linux新特性的加入来兼容glibc各不同版本。

7.cgp_init():cgroup初始化

8.parse_cg_info():解析CGroup信息

9.prepare_inventory():准备镜像工程?

10.cpu_dump_cpuinfo():备份cpu信息

11.connect_to_page_server():连接到Page_Server

12.setup_alarm_handler():安装警报处理器

13.collect_pstree():收集进程树信息

14.collect_pstree_ids():收集进程树id

15.network_lock():冻结网络操作

16.collect_namespaces():收集命名空间信息

17.cr_glob_imgset_open():不能够理解

18.collect_seccomp_filters():收集安全计算过滤器信息


数据信息收集完毕,后面对收集的信息进行备份处理

19.for_each_pstree_item(item) :dump_one_task(item):对每个树单节点进行备份

20.dead_pid_conflict():检查死pid故障:当一个进程已经完成的时候,但它在/proc/PID下的文件被其它的进程打开,然后该pid被给到新的线程,出现这样的情况是无法备份的。

21.dump_mnt_namespaces:备份mnt_namespaces()命名空间

22.dump_file_locks():备份文件锁

23.dump_verify_tty_sids():备份验证终端ttySID设备

24.dump_zombies():备份僵尸进程

25.dump_pstree(root_item):根据根节点备份进程树

26.dump_cgroups():备份CGROUP信息

27.cr_dump_shmem():备份共享内存

28.fix_external_unix_sockets():修复外部unix sockets

29.tty_post_actions():终端post操作?

30.write_img_inventory(&he):写入镜像工厂