slabを作る時とallocするときで似たようなパスを通ってちょっと混乱してしまったのでその辺のメモです。
slabを作るときはkmem_cache_create()が呼ばれて、そこから呼ばれるdo_kmem_cache_create()がメイン処理。
まずslabキャッシュの作り方の復習。slabキャッシュ用の適当な構造体とそれを管理するkmem_cache構造体のオブジェクトを準備。
struct slub_test { int n; char s[16]; }; static struct kmem_cache *slub_test_cachep;
slub_test_cachepのインスタンスを作る。
slub_test_cachep = KMEM_CACHE(slub_test, SLAB_PANIC);
キャッシュを取得
struct slub_test *ptr = kmem_cache_alloc(slub_test_cachep, GFP_KERNEL);
使い方はこんな感じ。
で、本題に戻る。
do_kmem_cache_create()の最初にあるkmem_cache_zalloc()は作ろうとしているslabを管理するkmem_cache構造体のオブジェクトを作成する。
144 err = -ENOMEM; 145 s = kmem_cache_zalloc(kmem_cache, GFP_KERNEL); 146 if (!s) 147 goto out;
kmem_cache_zalloc()に渡しているkmem_cacheはkmem_cache構造体。これはkmem_cache構造体を管理するためのkmem_cache構造体。ようは、スラブキャッシュを管理するオブジェクトを管理するためにslabを使っている。そして、返ってきたsが先の例だとslub_test_cachepになる。ここまでの時点ではslab objectに関してはまだ何も設定されていない。
次にslabに関するデータを設定していく。sizeとobject_sizeに関しては前回のslub: objectのsize設定 - φ(・・*)ゞ ウーン カーネルとか弄ったりのメモを参照。
149 s->name = name; 150 s->object_size = object_size; 151 s->size = size; 152 s->align = align; 153 s->ctor = ctor;
その後、__kmem_cache_create() => kmem_cache_open() => calculate_sizes()ときてs->object_sizeが設定されるというのも前回見たところ。
kmem_cache_alloc()の実際の処理になるのはslab_alloc_node()。
その中で、slab objectの設定をするのはobject(freelist)がNULLの場合。kmem_cache_alloc()を最初に読んだ時とか。
2409 object = c->freelist; 2410 page = c->page; 2411 if (unlikely(!object || !node_match(page, node))) { 2412 object = __slab_alloc(s, gfpflags, node, addr, c); 2413 stat(s, ALLOC_SLOWPATH); 2414 } else {
そして__slab_alloc() => new_slab_objects() => new_slab()ときて、object用のpageを取得し、objectを設定していく。
new_slab()を見ていくと、最初はpageの確保。何page確保するかはkmem_cache構造体にあるkmem_cache_order_objects構造体からオーダーを取得している。
1382 static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node) 1383 { 1384 struct page *page; 1385 void *start; 1386 void *p; 1387 int order; 1388 int idx; 1389 1390 BUG_ON(flags & GFP_SLAB_BUG_MASK); 1391 1392 page = allocate_slab(s, 1393 flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node); 1394 if (!page) 1395 goto out; 1396
pageを確保したらstruct pageからkmem_cacheを参照できるようにしたり等を行う。
1397 order = compound_order(page); 1398 inc_slabs_node(s, page_to_nid(page), page->objects); 1399 page->slab_cache = s; 1400 __SetPageSlab(page); 1401 if (page->pfmemalloc) 1402 SetPageSlabPfmemalloc(page); 1403
ここは単にpageの先頭アドレスを取得。
1404 start = page_address(page); 1405
SLAB_POISONが立っていたらダミーデータの書き込みを行う。
1406 if (unlikely(s->flags & SLAB_POISON)) 1407 memset(start, POISON_INUSE, PAGE_SIZE << order); 1408
ここがslab objectを設定するところ。ここは後で見る。
1409 for_each_object_idx(p, idx, s, start, page->objects) { 1410 setup_object(s, page, p); 1411 if (likely(idx < page->objects)) 1412 set_freepointer(s, p, p + s->size); 1413 else 1414 set_freepointer(s, p, NULL); 1415 } 1416
最後にstruct pageにあるslub用の構造体の変数に値をセット。
1417 page->freelist = start; 1418 page->inuse = page->objects; 1419 page->frozen = 1; 1420 out: 1421 return page; 1422 }
先ほど飛ばしたobjectの設定部分。
このループは
1409 for_each_object_idx(p, idx, s, start, page->objects) { 1415 } 1416
このように展開される。
286 #define for_each_object_idx(__p, __idx, __s, __addr, __objects) \ 287 for (__p = (__addr), __idx = 1; __idx <= __objects;\ 288 __p += (__s)->size, __idx++)
なので、pageの開始アドレスを起点にobject数分のループする感じ。
setup_object()はほぼデバッグ用途。ここでやるのはsetup_object_debug()の呼び出しと、コンストラクタが設定されていたらそれの呼び出し。
1374 static void setup_object(struct kmem_cache *s, struct page *page, 1375 void *object) 1376 { 1377 setup_object_debug(s, page, object); 1378 if (unlikely(s->ctor)) 1379 s->ctor(object); 1380 }
setup_object_debug()は最初にフラグをチェックして、デバッグ系の機能を使わないなら何もせず終了。
1005 static void setup_object_debug(struct kmem_cache *s, struct page *page, 1006 void *object) 1007 { 1008 if (!(s->flags & (SLAB_STORE_USER|SLAB_RED_ZONE|__OBJECT_POISON))) 1009 return; 1010 1011 init_object(s, object, SLUB_RED_INACTIVE); 1012 init_tracking(s, object); 1013 }
init_object()はこのような処理。__OBJECT_POISONが経っている場合はobjectのサイズ分の領域をダミーデータで埋める。SLAB_RED_ZONEはobject_sizeを超えた箇所への書き込みを検知するために使用する。なので、データを設定する位置がオブジェクトの後ろになっている。
663 static void init_object(struct kmem_cache *s, void *object, u8 val) 664 { 665 u8 *p = object; 666 667 if (s->flags & __OBJECT_POISON) { 668 memset(p, POISON_FREE, s->object_size - 1); 669 p[s->object_size - 1] = POISON_END; 670 } 671 672 if (s->flags & SLAB_RED_ZONE) 673 memset(p + s->object_size, val, s->inuse - s->object_size); 674 }
init_tracking()はこのような処理。SLAB_STORE_USERが立っている場合、オブジェクトのアドレス、cpu、pidなどをデバッグ用に記録する。ここではそれの初期化。
534 static void init_tracking(struct kmem_cache *s, void *object) 535 { 536 if (!(s->flags & SLAB_STORE_USER)) 537 return; 538 539 set_track(s, object, TRACK_FREE, 0UL); 540 set_track(s, object, TRACK_ALLOC, 0UL); 541 }
そんなわけでsetup_object()はデバッグのための初期化なので実は読み飛ばしてもOKな部分。 元のループに戻って次はここ。set_freepointer()がオブジェクトを設定する部分。
1411 if (likely(idx < page->objects)) 1412 set_freepointer(s, p, p + s->size); 1413 else 1414 set_freepointer(s, p, NULL);
set_freepointer()はこのような処理。
276 static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp) 277 { 278 *(void **)(object + s->offset) = fp; 279 }
ちなみにget_freepointer()は当然のようにset_freepointer()と逆の操作。
254 static inline void *get_freepointer(struct kmem_cache *s, void *object) 255 { 256 return *(void **)(object + s->offset); 257 }
offsetはどのように決めているかというと、slub.cの中ではcalculate_sizes()でのこれと、
2988 if (((flags & (SLAB_DESTROY_BY_RCU | SLAB_POISON)) || 2989 s->ctor)) { 2990 /* 2991 * Relocate free pointer after the object if it is not 2992 * permitted to overwrite the first word of the object on 2993 * kmem_cache_free. 2994 * 2995 * This is the case if we do RCU, have a constructor or 2996 * destructor or are poisoning the objects. 2997 */ 2998 s->offset = size; 2999 size += sizeof(void *); 3000 }
3072 if (get_order(s->size) > get_order(s->object_size)) { 3073 s->flags &= ~DEBUG_METADATA_FLAGS; 3074 s->offset = 0; 3075 if (!calculate_sizes(s, -1)) 3076 goto error; 3077 }
どうもoffsetが0以外になるのはdebug用の機能を使う場合時の模様。
今日見たnew_slab()はkmem_cache_create()からも呼ばれるし、kmem_cache_alloc()からも呼ばれる。自分がわけわからなくなってたのはこの辺で、kmem_cache_create()のときはkmem_cache構造体をスラブキャッシュから確保、kmem_cache_alloc()はあるobject専用のkmem_cache構造体を使ってキャッシュから取得するというところを忘れてたせい。