誰得なめも。バージョンは4.1.15。
__initがついているのは以下の3関数。
- mem_cgroup_init()
- enable_swap_account()
- mem_cgroup_swap_init()
当たり前だけど、__initがあるのでカーネル起動時の初期化で呼ばれる。
mem_cgroup_init()はこのような関数。
5774 static int __init mem_cgroup_init(void)
5775 {
5776 int cpu, node;
5777
5778 hotcpu_notifier(memcg_cpu_hotplug_callback, 0);
5779
5780 for_each_possible_cpu(cpu)
5781 INIT_WORK(&per_cpu_ptr(&memcg_stock, cpu)->work,
5782 drain_local_stock);
5783
5784 for_each_node(node) {
5785 struct mem_cgroup_tree_per_node *rtpn;
5786 int zone;
5787
5788 rtpn = kzalloc_node(sizeof(*rtpn), GFP_KERNEL,
5789 node_online(node) ? node : NUMA_NO_NODE);
5790
5791 for (zone = 0; zone < MAX_NR_ZONES; zone++) {
5792 struct mem_cgroup_tree_per_zone *rtpz;
5793
5794 rtpz = &rtpn->rb_tree_per_zone[zone];
5795 rtpz->rb_root = RB_ROOT;
5796 spin_lock_init(&rtpz->lock);
5797 }
5798 soft_limit_tree.rb_tree_per_node[node] = rtpn;
5799 }
5800
5801 return 0;
5802 }
5803 subsys_initcall(mem_cgroup_init);
hotcpu_notifier()はcpu hotplugの処理なので無視して、最初のfor_each_possible_cpuマクロはper cpuなデータであるstruct memcg_stock_pcpの初期化。memcg_stock_pcp構造体はこのような構造体。現段階では初期化処理しか追っていないので、この構造体の使用目的は未確認。とりあえず、ワークキューがあるのと(struct work_struct)、nr_pagesというどう考えでもページ数の数を保持するであろうメンバ変数があるのでページ関連の操作で使われるのでしょう。
2055 struct memcg_stock_pcp {
2056 struct mem_cgroup *cached;
2057 unsigned int nr_pages;
2058 struct work_struct work;
2059 unsigned long flags;
2060 #define FLUSHING_CACHED_CHARGE 0
2061 };
2062 static DEFINE_PER_CPU(struct memcg_stock_pcp, memcg_stock);
次のfor_each_nodeマクロでメモリノード単位で処理が行われる。ここで出てくるmem_cgroup_tree_per_node構造体はこんな感じなんだけど、mm/memcontrol.cで定義されてるので他では使われない模様。赤黒木なデータ構造なんですね。
172 struct mem_cgroup_tree_per_node {
173 struct mem_cgroup_tree_per_zone rb_tree_per_zone[MAX_NR_ZONES];
174 };
そして、各ゾーン(これはZONE_NORMALとかですね。)毎にrbツリーの初期化をします。
5791 for (zone = 0; zone < MAX_NR_ZONES; zone++) {
5792 struct mem_cgroup_tree_per_zone *rtpz;
5793
5794 rtpz = &rtpn->rb_tree_per_zone[zone];
5795 rtpz->rb_root = RB_ROOT;
5796 spin_lock_init(&rtpz->lock);
5797 }
初期化したものはsoft_limit_treeという変数のrb_tree_per_node配列に突っ込みます。
5798 soft_limit_tree.rb_tree_per_node[node] = rtpn;
soft_limit_treeはこう宣言されていて基本は参照だけみたいです。
180 static struct mem_cgroup_tree soft_limit_tree __read_mostly;
ちなみに、MAX_NR_ZONESはinclude/generated配下のファイルにあるのでビルド時に定義されるようです。
./include/generated/bounds.h:10:#define MAX_NR_ZONES 4 /* __MAX_NR_ZONES # */
2つ目の初期化処理はenable_swap_account()で、これはカーネルの起動時のコマンドラインで渡されたswapaccountの処理ですね。really_do_swap_account変数に値を設定するだけです。
5877 static int __init enable_swap_account(char *s)
5878 {
5879 if (!strcmp(s, "1"))
5880 really_do_swap_account = 1;
5881 else if (!strcmp(s, "0"))
5882 really_do_swap_account = 0;
5883 return 1;
5884 }
5885 __setup("swapaccount=", enable_swap_account);
5886
このコマンドライン引数がなければ呼ばれないですけど。その場合はデフォルト値があるのでそちらが使われます。
5870
5871 #ifdef CONFIG_MEMCG_SWAP_ENABLED
5872 static int really_do_swap_account __initdata = 1;
5873 #else
5874 static int really_do_swap_account __initdata;
5875 #endif
3つ目はmem_cgroup_swap_init()です。memory cgroupがenableで、really_do_swap_accountが1の場合(あえてswapaccount=0を設定しなければ大抵1になってるのでは)に処理があります。
5914 static int __init mem_cgroup_swap_init(void)
5915 {
5916 if (!mem_cgroup_disabled() && really_do_swap_account) {
5917 do_swap_account = 1;
5918 WARN_ON(cgroup_add_legacy_cftypes(&memory_cgrp_subsys,
5919 memsw_cgroup_files));
5920 }
5921 return 0;
5922 }
5923 subsys_initcall(mem_cgroup_swap_init);
do_swap_accountを1に設定しているので、swapもアカウンティングするよというのと、cgroup_add_legacy_cftypes()を呼んでいるのでmemory cgroupのファイル作成処理があります。作成するのは以下のファイルです。/sys/kernel/fs/cgroup/memoryに以下のファイルが作られます。
5887 static struct cftype memsw_cgroup_files[] = {
5888 {
5889 .name = "memsw.usage_in_bytes",
5890 .private = MEMFILE_PRIVATE(_MEMSWAP, RES_USAGE),
5891 .read_u64 = mem_cgroup_read_u64,
5892 },
5893 {
5894 .name = "memsw.max_usage_in_bytes",
5895 .private = MEMFILE_PRIVATE(_MEMSWAP, RES_MAX_USAGE),
5896 .write = mem_cgroup_reset,
5897 .read_u64 = mem_cgroup_read_u64,
5898 },
5899 {
5900 .name = "memsw.limit_in_bytes",
5901 .private = MEMFILE_PRIVATE(_MEMSWAP, RES_LIMIT),
5902 .write = mem_cgroup_write,
5903 .read_u64 = mem_cgroup_read_u64,
5904 },
5905 {
5906 .name = "memsw.failcnt",
5907 .private = MEMFILE_PRIVATE(_MEMSWAP, RES_FAILCNT),
5908 .write = mem_cgroup_reset,
5909 .read_u64 = mem_cgroup_read_u64,
5910 },
5911 { },
5912 };
cgroup_add_legacy_cftypes()に渡しているmemory_cgrp_subsysは以下のようになってます。
75 struct cgroup_subsys memory_cgrp_subsys __read_mostly;
76 EXPORT_SYMBOL(memory_cgrp_subsys);
初期化処理はこんな感じですね。