読者です 読者をやめる 読者になる 読者になる

slub:slab objectの作成処理を見ていく

kernel linux

この記事は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パターンがある。この辺の使い分けというかデータ構造が重要ですね。もうちょい調べないと。