この記事はLinux Advent Calendar 2014の6日目の記事です。
今回は前回の続きではなくて(といっても流れ的には続きになるんですが)slab objectの作成部分です。
slab objectの作成はnew_slab_objects()にて行います。この関数の呼び出し元は__slab_alloc()からになります。
objectの作成と言ってもこの関数はそこまでの処理はなくてメインなのはnew_slab()の方です。自分が主に知りたいのは処理の流れではなくてデータ構造がどうなってるかというところなのでその辺を意識して読んでいきたいという心意気です。なので読み方が処理の流れに沿わないかも。
まず呼び出し元がどのように呼んでいるかというと↓で、freelistという名前の変数に戻り値を入れているので何かしらのリストが欲しいとわかります。
2260 static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, 2261 unsigned long addr, struct kmem_cache_cpu *c) 〜略〜 2262 { 2263 void *freelist; 2339 freelist = new_slab_objects(s, gfpflags, node, &c);
上記のfreelistがどこに使われかというとkmem_cache_cpu構造体のfreelistに設定されます。
40 struct kmem_cache_cpu { 41 void **freelist; /* Pointer to next available object */ 42 unsigned long tid; /* Globally unique transaction id */ 43 struct page *page; /* The slab from which we are allocating */ 44 struct page *partial; /* Partially allocated frozen slabs */ 45 #ifdef CONFIG_SLUB_STATS 46 unsigned stat[NR_SLUB_STAT_ITEMS]; 47 #endif 48 };
そしてkmem_cache_cpu構造体はkmem_cache構造体のメンバです。
62 struct kmem_cache { 63 struct kmem_cache_cpu __percpu *cpu_slab; 64 /* Used for retriving partial slabs etc */ 65 unsigned long flags;
これはこのような形で取り出されます。
2398 c = this_cpu_ptr(s->cpu_slab);
というわけで、new_slab_objects()はslubはslab objectsを今動いているcpu向けに作っているとわかります。
さて、freelistがわかったところでnew_slab_objects()を読んでいきます。ここはそんなに処理がないので全体を先に読んでしまいます。
2168 static inline void *new_slab_objects(struct kmem_cache *s, gfp_t flags, 2169 int node, struct kmem_cache_cpu **pc) 2170 { 2171 void *freelist; 2172 struct kmem_cache_cpu *c = *pc; 2173 struct page *page; 2174
最初にget_partial()でfreelistがあるか調べて、見つかればそのまま見つかったリストを返します。
2175 freelist = get_partial(s, flags, node, c); 2176 2177 if (freelist) 2178 return freelist; 2179
ここでpartialとは何かという話になってくるわけですが、これはkmem_cache_node構造体のメンバです。これはslabもしくはslubで構造が変わるのでslubかつデバッグ系のものを無視するとこのようになります。先頭のlist_lockはslab/slubどちらの場合も使っています。そして、partialですが、これは一部使用中のslab objectがあるlistのことです。
268 struct kmem_cache_node { 269 spinlock_t list_lock; 〜略〜 285 unsigned long nr_partial; 286 struct list_head partial; 〜略〜 293 294 };
kmem_cache_node構造体が出てきましたが、これはkmem_cache構造体の最後のメンバ変数です。
101 struct kmem_cache_node *node[MAX_NUMNODES]; 102 };
もしget_partial()でlistが見つからなければnew_slab()でstruct pageの確保を行います。ここではfreelistではなくてpageの確保ですね。
2180 page = new_slab(s, flags, node);
pageを確保出来た場合。最初にkmem_cache構造体から今動いているcpuのkmem_cache_cpu構造体を取得し、もし、このkmem_cache_cpu構造体のpage変数が設定されているならflush_slab()を呼ぶ。flush_slab()はざっくりというと作成済みのobjectとかを削除する処理です。
2181 if (page) { 2182 c = raw_cpu_ptr(s->cpu_slab); 2183 if (c->page) 2184 flush_slab(s, c); 2185
flush_slab()で色々初期化されたので新たに確保したpageを使って再度設定します。ここは見たままですね。
2186 /* 2187 * No other reference to the page yet so we can 2188 * muck around with it freely without cmpxchg 2189 */ 2190 freelist = page->freelist; 2191 page->freelist = NULL; 2192 2193 stat(s, ALLOC_SLAB); 2194 c->page = page; 2195 *pc = c; 2196 } else 2197 freelist = NULL; 2198 2199 return freelist; 2200 }
今日のまとめ。 new_slab_objects()はget_partial()でfreelistが見つからなかった場合はnew_slab()でpageの確保を行い、kmem_cache_cpu構造体にそのpageのデータを設定する。slab objectについてはnew_slab()で処理する。 freelistはkmem_cache_node構造体から取得する場合と、kmem_cache_cpu構造体から取得の2パターンがある。この辺の使い分けというかデータ構造が重要ですね。もうちょい調べないと。
これ一冊で完全理解 Linuxカーネル超入門 (日経BPパソコンベストムック)
- 作者: 日経Linux
- 出版社/メーカー: 日経BP社
- 発売日: 2014/10/16
- メディア: 単行本
- この商品を含むブログ (1件) を見る