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);
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はgccのalignofによって取得した値が入っている。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()にて設定されている。