原标题:源码解析容器底层cgroup的实现
在 上一篇文章 里,我们探讨了容器底层 cgroup 的作用与数据结构,本文我们将深入分析 cgroup 的代码实现。
一、cgroup 的初始化和 mount
测试环境版本与第一篇一致:
本篇开始我们将分析 cgroup 的代码实现,与书(《精通 Linux 内核—智能设备开发核心技术》,下同)中的原则一致,我们重点分析核心和难点代码,其他部分在不影响理解的情况下一笔带过。
1.1 cgroup 的初始化
cgroup 的初始化分为两个阶段。
第一阶段:初始化 cgrp_dfl_root 和系统支持的 ss,由cgroup_init_early 函数完成。cgrp_dfl_root,看名字就知道,default cgroup_root,默认的 cgroup 层级结构,它在 cgroup v1 中戏份有限,在 v2 中是 c 位。至于 ss 的初始化,主要是 id 和 name,如果 ss 的 early_init 为真,调用 cgroup_init_subsys 完善它与cgrp_dfl_root 的关系。
cgroup_init_subsys 有助于我们理解 cgroup 和 ss 之间的关系,此处展开讨论,代码如下:
void cgroup_init_subsys( structcgroup_subsys*ss, bool early)
{
ss->root = &cgrp_dfl_root;
css = ss->css_alloc(cgroup_css(&cgrp_dfl_root.cgrp, ss));
init_and_link_css(css, ss, &cgrp_dfl_root.cgrp);
if(early) {
css->id = 1;
} else{
css->id = cgroup_idr_alloc(&ss->css_idr, css, 1, 2, GFP_KERNEL);
}
init_css_set.subsys[ss->id] = css; //***,三个星号哈
BUG_ON(online_css(css));
我们在第一篇中说过,ss 和 cgroup 是多对多的关系,通过 css 实现,cgroup_init_subsys 就是完成这个任务的。cgrp_dfl_root 是一个 cgroup_root,它本身内嵌了一个 cgroup,所以具体点就是申请一个 css,建立它与 cgrp_dfl_root.cgrp 的联系。
它先回调 ss->css_alloc 函数申请 css,css_alloc 的参数表示将要产生的 css 的父css(我们在第一篇讲过,css 的两方面作用),调用 cgroup_init_subsys 的时候,父 css 还不存在,所以最终传递的参数是 NULL。
我们分析的 cgroup 子系统 cpuset 的 css_alloc 回调函数是 cpuset_css_alloc,当它发现传递的参数 parent_css 等于 NULL 的时候,直接返回 &top_cpuset.css,也就是一个全局的 css。全局,意味着牵一发动全身,隐约中找到了第一篇课堂作业第一题的答案。
有了 css 后,调用 init_and_link_css 和 online_css 建立 cgroup 和 ss 的关系就是水到渠成的事情了。online_css 会回调 ss->css_online 函数,对 cpuset 而言,因为 css_alloc 返回的是全局的 css,此处 css_online 并没有实际操作。
init_css_set(三颗星,重点)是 init css_set,是一个全局的 css_set,这里使用申请到的 css 为相应的字段赋值。
第二阶段:绑定 ss 与 cgrp_dfl_root,也就是说系统启动的初期所有的 ss 都与默认的 cgroup 层级结构绑定。由 cgroup_init 函数完成,主要逻辑如下:
int cgroup_init(void)
{
BUG_ON(cgroup_init_cftypes( NULL, cgroup_base_files)); //1
BUG_ON(cgroup_init_cftypes( NULL, cgroup1_base_files));
BUG_ON(cgroup_setup_root(&cgrp_dfl_root, 0)); //2
for_each_subsys(ss, ssid) {
if(ss->early_init) { //3
struct cgroup_subsys_state *css = init_css_set.subsys[ss->id];
css->id = cgroup_idr_alloc(&ss->css_idr, css, 1, 2, GFP_KERNEL);
} else{
cgroup_init_subsys(ss, false);
}
cgrp_dfl_root.subsys_mask |= 1 << ss->id;
if(ss->dfl_cftypes == ss->legacy_cftypes) { //4
WARN_ON(cgroup_add_cftypes(ss, ss->dfl_cftypes));
} else{
WARN_ON(cgroup_add_dfl_cftypes(ss, ss->dfl_cftypes));
WARN_ON(cgroup_add_legacy_cftypes(ss, ss->legacy_cftypes));
}
if(ss->bind) //5
ss->b