slub: objectのsize設定

slubでオブジェクト管理する上で使うサイズ等の管理のメモ。見ているカーネルはv3.17です。今回はcalculate_sizes()を見るのがメインかな。

struct kmem_cacheの中でサイズに関連するのはこの辺り。

 62 struct kmem_cache {
〜略〜
 67         int size;               /* The size of an object including meta data */
 68         int object_size;        /* The size of an object without meta data */
 69         int offset;             /* Free pointer offset. */

サイズとしてはメタデータを含めたサイズ含んだsizeと純粋にオブジェクトのサイズのみのobject_sizeがある。

まずは最初にsize関連を設定しているのはdo_kmem_cache_create()。これを呼ぶのはkmem_cache_create()。do_kmem_cache_create()の2番目のsizeがstruct kmem_cacheのobject_size、3番目がsizeになる。

235         s = do_kmem_cache_create(cache_name, size, size,
236                                  calculate_alignment(flags, align, size),
237                                  flags, ctor, NULL, NULL);

do_kmem_cache_create()

137 do_kmem_cache_create(char *name, size_t object_size, size_t size, size_t align,
138                      unsigned long flags, void (*ctor)(void *),
139                      struct mem_cgroup *memcg, struct kmem_cache *root_cache)

その中で値を設定しているのはこの辺。

149         s->name = name;
150         s->object_size = object_size;
151         s->size = size;
152         s->align = align;
153         s->ctor = ctor;

この時点ではs->object_size == s->size。

その後、do_kmem_cache_create()から以下の流れでcalculate_sizes()が呼ばれて、ここでs->sizeが再設定される。

__kmem_cache_create()
  --> kmem_cache_open()
    --> calculate_sizes()

calculate_sizes()の冒頭でローカル変数のsizeにオブジェクトのサイズを設定。

2949         unsigned long flags = s->flags;
2950         unsigned long size = s->object_size;

最初にオブジェクトのサイズ(size)をsizeof(void *)でアライメントするようにサイズを切り上げる。

2953         /*
2954          * Round up object size to the next word boundary. We can only
2955          * place the free pointer at word boundaries and this determines
2956          * the possible location of the free pointer.
2957          */
2958         size = ALIGN(size, sizeof(void *));

SLAB_RED_ZONEフラグはオブジェクトの後ろにレッドゾーンというメモリ破壊検出用の領域を置く場合に設定される。これはデバッグ用の機能。ここはSLAB_RED_ZONEが有効な場合の処理なので飛ばしましょ。

2978         if ((flags & SLAB_RED_ZONE) && size == s->object_size)
2979                 size += sizeof(void *);

次にキャッシュの使用量(byte)を設定しておく。ここはアライメント分を含んだサイズが使われる。

2982         /*
2983          * With that we have determined the number of bytes in actual use
2984          * by the object. This is the potential offset to the free pointer.
2985          */
2986         s->inuse = size;

次の処理、SLAB_DESTROY_BY_RCUはスラブキャッシュをfreeするときRCUを使う場合にセット。SLAB_POISONはスラブのオブジェクトに特定のデータを書いておいて未初期化のポインタを読んだ場合にエラー検出するときのデバッグ用。s->ctorはコンストラクタでオブジェクトによっては使っているかも。KMEM_CACHEマクロでSLABを作る場合はNULLになっている。いづれかの条件に該当する場合はs->offsetが設定されるのと、sizeにポインタのサイズが足される。

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         }

次のif文2個はCONFIG_SLUB_DEBUGがセットされている場合の処理なので飛ばす。

ここまでで設定したsizeでアライメント分を切り上げたサイズを設定して、s->sizeにサイズを設定する。

3022          * SLUB stores one object immediately after another beginning from
3023          * offset 0. In order to align the objects we have to simply size
3024          * each object to conform to the alignment.
3025          */
3026         size = ALIGN(size, s->align);
3027         s->size = size;

s->alignはgccalignofによって取得した値が入っている。KMEM_CACHEマクロではこのように。

135 #define KMEM_CACHE(__struct, __flags) kmem_cache_create(#__struct,\
136                 sizeof(struct __struct), __alignof__(struct __struct),\
137                 (__flags), NULL)
138

そんなわけでメタデータを含んだサイズはcalculate_sizes()にて設定されている。

[改訂新版] シェルスクリプト基本リファレンス  ??#!/bin/shで、ここまでできる (WEB+DB PRESS plus)