c⌒っ゚д゚)っφ メモメモ...
kzalloc()を見てて気づいたことをメモ程度に残しとこう。
kzalloc()はこんな感じでkmalloc()を呼び出すだけです。
344/** 345 * kzalloc - allocate memory. The memory is set to zero. 346 * @size: how many bytes of memory are required. 347 * @flags: the type of memory to allocate (see kmalloc). 348 */ 349static inline void *kzalloc(size_t size, gfp_t flags) 350{ 351 return kmalloc(size, flags | __GFP_ZERO); 352}
kzalloc()はフラグに__GFP_ZEROを追加してkmalloc()を呼び出すというのはそうですねってだけですが、
では、kmalloc()はというとこうなってます。
128static __always_inline void *kmalloc(size_t size, gfp_t flags) 129{ 130 struct kmem_cache *cachep; 131 void *ret; 132 133 if (__builtin_constant_p(size)) { 134 int i = 0; 135 136 if (!size) 137 return ZERO_SIZE_PTR; 138 139#define CACHE(x) \ 140 if (size <= x) \ 141 goto found; \ 142 else \ 143 i++; 144#include <linux/kmalloc_sizes.h> 145#undef CACHE 146 return NULL; 147found: 148#ifdef CONFIG_ZONE_DMA 149 if (flags & GFP_DMA) 150 cachep = malloc_sizes[i].cs_dmacachep; 151 else 152#endif 153 cachep = malloc_sizes[i].cs_cachep; 154 155 ret = kmem_cache_alloc_trace(size, cachep, flags); 156 157 return ret; 158 } 159 return __kmalloc(size, flags); 160}
__always_inlineがついているから常にinline化されるんですね。さて、kmalloc()で一番最初のif文ですが、__builtin_constant_p()はgccのビルトイン関数でこれは__builtin_constant_p()に渡した引数が定数かどうかをチェックしてます。コンパイル時に取得したいメモリのサイズが分かっているかどうかで条件分けているということですね。
その後はサイズが0だった場合のチェックが136行目にあって、次からは配列malloc_sizesにアクセスするためのインデックスを計算してます。これは144行目でインクルードしているkmalloc_sizes.hで実現してます。これでsizeに応じて最適なキャッシュサイズのインデックスを求めて、kmem_cache_alloc_trace()でメモリの確保って流れですね。
そして、kmem_cache_alloc_trace(これはCONFIG_TRACINGが定義されている場合のほうです)はこのような感じになっています()
3776void * 3777kmem_cache_alloc_trace(size_t size, struct kmem_cache *cachep, gfp_t flags) 3778{ 3779 void *ret; 3780 3781 ret = __cache_alloc(cachep, flags, __builtin_return_address(0)); 3782 3783 trace_kmalloc(_RET_IP_, ret, 3784 size, slab_buffer_size(cachep), flags); 3785 return ret; 3786} 3787EXPORT_SYMBOL(kmem_cache_alloc_trace);
__cache_alloc()でメモリ確保して、trace_kmalloc()でトレースをしておくんですね。trace_kmalloc()はkmemleakで使うためだと思います。
さて、コンパイル時点でsizeが決定できない場合は__kmalloc()が呼ばれます。
これはmm/slab.cにいます。
3886void *__kmalloc(size_t size, gfp_t flags) 3887{ 3888 return __do_kmalloc(size, flags, __builtin_return_address(0)); 3889}
そして、__do_kmalloc()が呼ばれます。
3862static __always_inline void *__do_kmalloc(size_t size, gfp_t flags, 3863 void *caller) 3864{ 3865 struct kmem_cache *cachep; 3866 void *ret; 3867 3868 /* If you want to save a few bytes .text space: replace 3869 * __ with kmem_. 3870 * Then kmalloc uses the uninlined functions instead of the inline 3871 * functions. 3872 */ 3873 cachep = __find_general_cachep(size, flags); 3874 if (unlikely(ZERO_OR_NULL_PTR(cachep))) 3875 return cachep; 3876 ret = __cache_alloc(cachep, flags, caller); 3877 3878 trace_kmalloc((unsigned long) caller, ret, 3879 size, cachep->buffer_size, flags); 3880 3881 return ret; 3882} 3883
これもsizeから適切なキャッシュを探してメモリを確保しています。その後の流れは__cache_alloc()->trace_kmalloc()とkmem_cache_alloc_trace()と同じですね。
ということで、kmalloc()はコンパイル時にメモリ確保する量が分かっている場合は必要なキャッシュのサイズもコンパイル時点でわかるので直接em_cache_alloc_trace()を呼び、コンパイル時点でsizeが未定の場合は、__kmalloc()を呼んでキャッシュの大きさを調べてからメモリ確保するようになっているということですね( ..)φメモメモ