cgroup 初期化のメモ。間違っている可能性大なので信用しないでください。何度も同じところを繰り返し見てるので忘れないようにメモです。
サブシステム (cgroup_subsys
) と各グループのサブシステムの状態 (cgroup_subsys_state
) とそれらのセット (css_set
) の関係とかわかってないと以下を見てもわけわからんかも。自分用のメモで、間違いあるかもしれません。
start_kernel
からまず cgroup_init_early
が呼び出された後、cgroup_init
が呼び出される。
492 asmlinkage __visible void __init start_kernel(void) :(snip) 511 cgroup_init_early(); :(snip) 661 cgroup_init();
cgroup_init_early
4960 RCU_INIT_POINTER(init_task.cgroups, &init_css_set);
init_task
の css_set
型のメンバ cgroups
を init_css_set
で初期化します。init_css_set
は cgroup.c で定義されています。
4962 for_each_subsys(ss, i) {
これは静的に定義されているサブシステム分要素を持つ cgroup_subsys
型の cgroup_subsys[]
変数 (配列) 分ループをまわすものでした (cgroup の SUBSYS マクロ 参照)。ss
には i
番目のサブシステムが入ります。
4963 WARN(!ss->css_alloc || !ss->css_free || ss->name || ss->id, 4964 "invalid cgroup_subsys %d:%s css_alloc=%p css_free=%p name:id=%d:%s\n", 4965 i, cgroup_subsys_name[i], ss->css_alloc, ss->css_free, 4966 ss->id, ss->name);
まずは
- サブシステムに必須のメソッドである
css_alloc/free
が存在しているかのチェック - サブシステム名とIDがまだ構造体のメンバに設定されていないチェック
を行います。
4967 WARN(strlen(cgroup_subsys_name[i]) > MAX_CGROUP_TYPE_NAMELEN, 4968 "cgroup_subsys_name %s too long\n", cgroup_subsys_name[i]);
次にサブシステム名 (cgroup_subsys_name[i]
に入ってます) の名前が長すぎないかチェックしています。
4969 4970 ss->id = i; 4971 ss->name = cgroup_subsys_name[i];
サブシステム (変数の各メンバ) に、ID と名前を設定します。(各サブシステムで cgroup_subsys
を定義する際には定義されていないメンバ)
4973 if (ss->early_init) 4974 cgroup_init_subsys(ss, true);
そしてサブシステムの early_init
を行うように 1
が設定されている時は cgroup_init_subsys
を呼び出します。
cgroup_init_subsys
を見てみると、
4895 static void __init cgroup_init_subsys(struct cgroup_subsys *ss, bool early) 4896 { :(snip) 4906 /* Create the root cgroup state for this subsystem */ 4907 ss->root = &cgrp_dfl_root; 4908 css = ss->css_alloc(cgroup_css(&cgrp_dfl_root.cgrp, ss));
と ss->root
には v2 の root が放り込まれます。つまり cgroup_init_subsys
は v2 の処理を行うだけです。
cgroup_init
cgroup_init
はちょっと長いのですが、これも v2 の処理を無視するとやっていることはシンプルです。
4992 BUG_ON(cgroup_init_cftypes(NULL, cgroup_legacy_base_files));
まずはこれ。cgroup を操作するために各グループに現れるファイルがあります。このファイルを cftype
という構造体で定義します。
このファイルのうち、サブシステムの処理とは直接関係ない、cgroup 自体の操作に関連する cgroup コアで扱うファイル群があり、その定義が cftype
の配列として静的に定義されています。それが cgroup_legacy_base_files
変数です。これを cgroup_init_cftypes
関数に渡して、ファイル操作の定義を行います (多分)。
4996 /* Add init_css_set to the hash table */ 4997 key = css_set_hash(init_css_set.subsys); 4998 hash_add(css_set_table, &init_css_set.hlist, key);
システム上の css_set
はすべて css_set_table
というハッシュテーブルで管理されますので、それに init_css_set
を登録します。css_set
内のサブシステムから計算される値を使ってハッシュのキー (key
) を生成し、使用します。とは言っても init_css_set
って v2 用じゃ…
そしてまたサブシステム分ループ。ループの最初に以下のような処理がありますが、
5005 if (ss->early_init) { 5006 struct cgroup_subsys_state *css = 5007 init_css_set.subsys[ss->id]; 5008 5009 css->id = cgroup_idr_alloc(&ss->css_idr, css, 1, 2, 5010 GFP_KERNEL); 5011 BUG_ON(css->id < 0); 5012 } else { 5013 cgroup_init_subsys(ss, false); 5014 }
ここですが、cgroup_init_early
で初期化したサブシステムは ID を確保、されなかったサブシステムは cgroup_init_subsys
で初期化します。とは言っても、いずれも v2 処理。
その後の条件分岐、
5035 if (ss->dfl_cftypes == ss->legacy_cftypes) { 5036 WARN_ON(cgroup_add_cftypes(ss, ss->dfl_cftypes)); 5037 } else { 5038 WARN_ON(cgroup_add_dfl_cftypes(ss, ss->dfl_cftypes)); 5039 WARN_ON(cgroup_add_legacy_cftypes(ss, ss->legacy_cftypes)); 5040 }
if 文 true の条件は特別な起動オプションを付けないと満たさない開発目的の条件なので無視。通常は false になるので、v2 の設定を行った (cgroup_add_dfl_cftypes
呼び出し) 後の 5039 行目だけが v1 の処理でしょう、と思えますが、実は通常はここは何もしません。この理由は後で。
5042 if (ss->bind) 5043 ss->bind(init_css_set.subsys[ssid]); 5044 }
その後、サブシステムに bind
関数が設定されている場合はそれを実行。
5046 err = sysfs_create_mount_point(fs_kobj, "cgroup");
sysfs にマウントポイントとなるディレクトリを作成 (/sys/fs/cgroup
)。
5050 err = register_filesystem(&cgroup_fs_type);
cgroup というファイルシステムを登録。
5056 proc_create("cgroups", 0, NULL, &proc_cgroupstats_operations);
proc に “cgroups” というファイルを作成。で終わりです。
cgroup_add_legacy_cftypes で何もしない理由
cgroup_add_legacy_cftypes
で v1 っぽい処理を呼び出しているにも関わらず「通常は何もしません」と書いた理由を追ってみます。
cgroup_add_legacy_cftypes
cgroup_add_legacy_cftypes
にサブシステムと cgroup_subsys
構造体型の各サブシステムの変数で定義されている legacy_cftypes
を渡します。legacy_cftypes
は各サブシステムで v1 のグループに出現させるファイルが各サブシステムごとに定義されています。
cgroup_add_legacy_cftypes
関数を見てみます。
3313 int cgroup_add_legacy_cftypes(struct cgroup_subsys *ss, struct cftype *cfts) 3314 { :(snip) 3322 if (!cgroup_legacy_files_on_dfl || 3323 ss->dfl_cftypes != ss->legacy_cftypes) { 3324 for (cft = cfts; cft && cft->name[0] != '\0'; cft++) 3325 cft->flags |= __CFTYPE_NOT_ON_DFL; 3326 } 3327 3328 return cgroup_add_cftypes(ss, cfts); 3329 }
通常は (開発目的のフラグがオン、またはデフォルトの cftypes
が v1 の場合 (これも通常はない) でなければ)、各 cftype
型の変数のメンバ flags
に “v2 階層には表示させない” というフラグを設定したのち、cgroup_add_cftypes
を呼び出します。
cgroup_add_cftypes
cgroup_add_cftypes
関数
3263 static int cgroup_add_cftypes(struct cgroup_subsys *ss, struct cftype *cfts) 3264 { :(snip) 3273 ret = cgroup_init_cftypes(ss, cfts); :(snip) 3280 ret = cgroup_apply_cftypes(cfts, true);
cgroup_init_cftypes
で cft->ss = ss
という cftype
構造体の ss
にサブシステムを入れている部分があります。そして cgroup_apply_cftypes
関数を呼びます。
cgroup_apply_cftypes
3138 static int cgroup_apply_cftypes(struct cftype *cfts, bool is_add) 3139 { 3141 struct cgroup_subsys *ss = cfts[0].ss; 3142 struct cgroup *root = &ss->root->cgrp;
ss
には cfts[0].ss
を入れてますが、これは cgroup_init_cftypes
でサブシステムそのものを入れました。root
変数にはサブシステムの root
が入りますが、これは cgroup_init_subsys
で v2 の root が入っていたはず。
3155 ret = cgroup_addrm_files(cgrp, cfts, is_add);
cgroup_addrm_files
そして cgroup_addrm_files
呼び出し。
3105 static int cgroup_addrm_files(struct cgroup *cgrp, struct cftype cfts[], 3106 bool is_add) 3107 { :(snip) 3113 for (cft = cfts; cft->name[0] != '\0'; cft++) { 3114 /* does cft->flags tell us to skip this file on @cgrp? */ 3115 if ((cft->flags & __CFTYPE_ONLY_ON_DFL) && !cgroup_on_dfl(cgrp)) 3116 continue; 3117 if ((cft->flags & __CFTYPE_NOT_ON_DFL) && cgroup_on_dfl(cgrp)) 3118 continue; :(snip)
というループがあり、
- 現在の
cgrp
は v2 の root の cgroup が入っているはず (cgroup_apply_cftypes
の処理参照) cft->flags
には__CFTYPE_NOT_ON_DFL
が放り込まれていたはず (cgroup_add_legacy_cftypes
の処理参照)
というわけで、ここはずっと continue
で何もしないままループを抜けます。ループを抜けなければ cgroup_add_file
で cgroup 用のファイルを追加するのですが、何もしないということです。
関連
- cgroupのv1とv2の切り分け的なところ (φ(・・*)ゞ ウーン カーネルとか弄ったりのメモ)