TenForward

技術ブログ。はてなダイアリーから移転しました

cgroup のデフォルトルート cgrp_dfl_root

このエントリはほぼ個人的なメモで、色々唐突です。

cgroupのコアは kernel/cgroup.c に色々処理があります。

その中に「デフォルトヒエラルキ(のルート)」という変数があります。

4.1 kernel のコードです。

/*
 * The default hierarchy, reserved for the subsystems that are otherwise
 * unattached - it never has more than a single cgroup, and all tasks are
 * part of that cgroup.
 */
struct cgroup_root cgrp_dfl_root;

cgroup の初期化処理は start_kernel から呼び出される cgroup_init_early と cgroup_init で行われますが、cgrp_dfl_root は cgroup_init で初期化されているようです。

int __init cgroup_init(void)
{
	struct cgroup_subsys *ss;
	unsigned long key;
	int ssid, err;

	BUG_ON(cgroup_init_cftypes(NULL, cgroup_dfl_base_files));
	BUG_ON(cgroup_init_cftypes(NULL, cgroup_legacy_base_files));

	mutex_lock(&cgroup_mutex);

	/* Add init_css_set to the hash table */
	key = css_set_hash(init_css_set.subsys);
	hash_add(css_set_table, &init_css_set.hlist, key);

	BUG_ON(cgroup_setup_root(&cgrp_dfl_root, 0));

ここで cgroup_setup_root に cgrp_dfl_root が渡されます。この中で渡された root (つまり cgrp_dfl_root) の初期化処理がなされていきます。

ここで root = cgrp_dfl_root の場合は cgroup_dfl_base_files

static int cgroup_setup_root(struct cgroup_root *root, unsigned int ss_mask)
{

    : (snip)

	if (root == &cgrp_dfl_root)
		base_files = cgroup_dfl_base_files;
	else
		base_files = cgroup_legacy_base_files;

    : (snip)

	ret = cgroup_addrm_files(root_cgrp, base_files, true);

ここで設定した base_files を cgroup_addrm_files に渡して、cgroup コアが各 cgroup (つまり cgroup を表す各ディレクトリ) に作成するファイルを設定します。

cgroup_dfl_base_files ってのは

/* cgroup core interface files for the default hierarchy */
static struct cftype cgroup_dfl_base_files[] = {
	{
		.name = "cgroup.procs",
		.seq_start = cgroup_pidlist_start,
		.seq_next = cgroup_pidlist_next,
		.seq_stop = cgroup_pidlist_stop,
		.seq_show = cgroup_pidlist_show,
		.private = CGROUP_FILE_PROCS,
		.write = cgroup_procs_write,
		.mode = S_IRUGO | S_IWUSR,
	},
	{
		.name = "cgroup.controllers",
		.flags = CFTYPE_ONLY_ON_ROOT,
		.seq_show = cgroup_root_controllers_show,
	},
	{
		.name = "cgroup.controllers",
		.flags = CFTYPE_NOT_ON_ROOT,
		.seq_show = cgroup_controllers_show,
	},
	{
		.name = "cgroup.subtree_control",
		.seq_show = cgroup_subtree_control_show,
		.write = cgroup_subtree_control_write,
	},
	{
		.name = "cgroup.populated",
		.flags = CFTYPE_NOT_ON_ROOT,
		.seq_show = cgroup_populated_show,
	},
	{ }	/* terminate */
};

という内容ですが、ここで .name で指定されているファイルって cgroup-v2 の各 cgroup (ディレクトリ) に作成されるファイルです。

つまり start_kernel -> cgroup_init で起動時に設定される「デフォルトのヒエラルキ(のルート)」は v2 ?

確かに v2 は単一階層構造なのでここで初期化しておけば、あとはそれを利用すれば良いのに対して、v1 はいくつでもマウントできるので後で設定してもいいのかな? と思えますが、もしかして今後は v2 をデフォルトにしたいという考えの現れ?

3.15 kernel では

ちなみに v2 のコードがまだそれほど入っていないころの 3.15 だと、cgroup_init 内で cgroup_setup_root が呼ばれているのは同じですが、cgroup_setup_root は

static int cgroup_setup_root(struct cgroup_root *root, unsigned long ss_mask)
{

    :(snip)

	ret = cgroup_addrm_files(root_cgrp, cgroup_base_files, true);

と条件文はなくて直接 cgroup_base_files が渡されており、cgroup_base_files は

static struct cftype cgroup_base_files[] = {
	{
		.name = "cgroup.procs",
    : (snip)

	},
	{
		.name = "cgroup.clone_children",
		.flags = CFTYPE_INSANE,
    : (snip0)
	},
	{
		.name = "cgroup.sane_behavior",
		.flags = CFTYPE_ONLY_ON_ROOT,
    : (snip)
	},

	/*
	 * Historical crazy stuff.  These don't have "cgroup."  prefix and
	 * don't exist if sane_behavior.  If you're depending on these, be
	 * prepared to be burned.
	 */
	{
		.name = "tasks",
		.flags = CFTYPE_INSANE,		/* use "procs" instead */
    : (snip)

	},
	{
		.name = "notify_on_release",
		.flags = CFTYPE_INSANE,
    : (snip)

	},
	{
		.name = "release_agent",
		.flags = CFTYPE_INSANE | CFTYPE_ONLY_ON_ROOT,

    : (snip)

	},
	{ }	/* terminate */
};

というふうに v1 のファイルは flags に CFTYPE_INSANE ってのが指定されています。追加の際に v1, v2 を判定して追加するかどうかを決めています。

static int cgroup_addrm_files(struct cgroup *cgrp, struct cftype cfts[],
			      bool is_add)
{

    : (snip)

	for (cft = cfts; cft->name[0] != '\0'; cft++) {
		/* does cft->flags tell us to skip this file on @cgrp? */
		if ((cft->flags & CFTYPE_ONLY_ON_DFL) && !cgroup_on_dfl(cgrp))
			continue;
		if ((cft->flags & CFTYPE_INSANE) && cgroup_sane_behavior(cgrp))
			continue;
		if ((cft->flags & CFTYPE_NOT_ON_ROOT) && !cgrp->parent)
			continue;
		if ((cft->flags & CFTYPE_ONLY_ON_ROOT) && cgrp->parent)
			continue;

		if (is_add) {
			ret = cgroup_add_file(cgrp, cft);
    : (snip)
}

という風に v1, v2 混在したようなコードになってます。