kmalloc之前编写内核驱动时,经常会用到kmalloc系列函数分配内存,那么它是如何分配内存的?好吧,我们追踪一下源码。
static __always_inline __alloc_size(1) void *kmalloc(size_t size, gfp_t flags)
{
if (__builtin_constant_p(size)) { // 判断size是否是常数
#ifndef CONFIG_SLOB
unsigned int index;
#endif
if (size > KMALLOC_MAX_CACHE_SIZE)
return kmalloc_large(size, flags);
首先看下KMALLOC_MAX_CACHE_SIZE值:
#define KMALLOC_MAX_CACHE_SIZE (1UL << KMALLOC_SHIFT_HIGH) || / #define KMALLOC_SHIFT_HIGH ((MAX_ORDER + PAGE_SHIFT - 1) <= 25 ? (MAX_ORDER + PAGE_SHIFT - 1) : 25) || / #ifndef CONFIG_FORCE_MAX_ZONEORDER #define MAX_ORDER 11 #else #define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER #endif #define MAX_ORDER_NR_PAGES (1 << (MAX_ORDER - 1)) #define PAGE_SHIFT 12 || / KMALLOC_MAX_CACHE_SIZE (1UL << 22)
在x86架构下KMALLOC_MAX_CACHE_SIZE为4MB,:
if (size > KMALLOC_MAX_CACHE_SIZE) // size大于4MB
return kmalloc_large(size, flags);
||
/
static __always_inline __alloc_size(1) void *kmalloc_large(size_t size, gfp_t flags)
{
unsigned int order = get_order(size);
return kmalloc_order_trace(size, flags, order);
}
进入kmalloc_order_trace函数:
static __always_inline __alloc_size(1) void *kmalloc_order_trace(size_t size, gfp_t flags,
unsigned int order)
{
return kmalloc_order(size, flags, order);
}
||
/
void *kmalloc_order(size_t size, gfp_t flags, unsigned int order)
{
void *ret = NULL;
struct page *page;
if (unlikely(flags & GFP_SLAB_BUG_MASK)) // 不使用slab分配器
flags = kmalloc_fix_flags(flags); // 去掉flags中的GFP_SLAB_BUG_MASK,执行dump_stack
flags |= __GFP_COMP;
page = alloc_pages(flags, order); // 分配 2 ^ order - (2 ^ order - 1)数量的物理页面
if (likely(page)) {
ret = page_address(page); // 返回页面的虚拟地址
mod_lruvec_page_state(page, NR_SLAB_UNRECLAIMABLE_B,
PAGE_SIZE << order); // 更新lru状态
}
ret = kasan_kmalloc_large(ret, size, flags); // 填充kasan
kmemleak_alloc(ret, size, 1, flags);
return ret;
}
继续分析kmalloc:
return __kmalloc(size, flags);
}
||
/
void *__kmalloc(size_t size, gfp_t flags)
{
struct kmem_cache *s;
void *ret;
if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) // size大于4MB
return kmalloc_large(size, flags); // 分配的物理页面,更新lru状态等
s = kmalloc_slab(size, flags); // slab分配器分配缓冲内存
if (unlikely(ZERO_OR_NULL_PTR(s)))
return s;
ret = slab_alloc(s, NULL, flags, _RET_IP_, size);
trace_kmalloc(_RET_IP_, ret, size, s->size, flags);
ret = kasan_kmalloc(s, ret, size, flags); // 填充kasan
return ret;
}



