分类:
2011-06-28 10:32:12
原文地址:Vi Linux内存 之 Slub分配器(二) 作者:palals
本节介绍如何创建一个slub分配器的slab块
new_slab
创建一个slab块。在slub分配器中,已经舍弃了struct slab结构,而是把一些必要的结构放入slab首页struct page中,这样首页struct page就可以表示一个slab,不再需要struct slab结构了。
static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
{
struct page *page;
void *start;
void *last;
void *p;
BUG_ON(flags & GFP_SLAB_BUG_MASK);
/* 分配slab页面 */
page = allocate_slab(s,
flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node);
if (!page)
goto out;
/* slab数加一 */
inc_slabs_node(s, page_to_nid(page), page->objects);
/* slab指针指向cache */
page->slab = s;
/* 表示此页块加入到slub分配器中 */
page->flags |= 1 << PG_slab;
/* 获得首页面的虚拟地址 */
start = page_address(page);
/* 调试相关,用POISON_INUSE填充slab */
if (unlikely(s->flags & SLAB_POISON))
memset(start, POISON_INUSE, PAGE_SIZE << compound_order(page));
last = start;
/* 遍历slab中的每个对象 */
for_each_object(p, s, start, page->objects) {
/* 初始化对象 */
setup_object(s, page, last);
/* 设置下一个对象指针,将对象一个一个串联起来。这里对象指针直接放在对象后面,不再需要slab管理对象了。*/
set_freepointer(s, last, p);
last = p;
}
setup_object(s, page, last);
/* 最后一个对象的下一个对象指针指向空 */
set_freepointer(s, last, NULL);
/* slab的feelist指针指向第一个空闲对象 */
page->freelist = start;
/* 已分配对象数为0 */
page->inuse = 0;
out:
return page;
}
allocate_slab
分配slab占用的页块。
static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
{
struct page *page;
struct kmem_cache_order_objects oo = s->oo;
gfp_t alloc_gfp;
flags |= s->allocflags;
/*
* Let the initial higher-order allocation fail under memory pressure
* so we fall-back to the minimum order allocation.
*/
alloc_gfp = (flags | __GFP_NOWARN | __GFP_NORETRY) & ~__GFP_NOFAIL;
/* 分配slab占用的页面 */
page = alloc_slab_page(alloc_gfp, node, oo);
/* 分配失败,调小order重试 */
if (unlikely(!page)) {
oo = s->min;
/*
* Allocation may have failed due to fragmentation.
* Try a lower order alloc if possible
*/
page = alloc_slab_page(flags, node, oo);
if (!page)
return NULL;
stat(s, ORDER_FALLBACK);
}
/* CONFIG_KMEMCHECK相关,内存检查相关,不去深究 */
if (kmemcheck_enabled
&& !(s->flags & (SLAB_NOTRACK | DEBUG_DEFAULT_FLAGS))) {
int pages = 1 << oo_order(oo);
kmemcheck_alloc_shadow(page, oo_order(oo), flags, node);
/*
* Objects from caches that have a constructor don't get
* cleared when they're allocated, so we need to do it here.
*/
if (s->ctor)
kmemcheck_mark_uninitialized_pages(page, pages);
else
kmemcheck_mark_unallocated_pages(page, pages);
}
/* 保存对象大小 */
page->objects = oo_objects(oo);
/* 更新页面统计 */
mod_zone_page_state(page_zone(page),
(s->flags & SLAB_RECLAIM_ACCOUNT) ?
NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE,
1 << oo_order(oo));
return page;
}
setup_object
初始化对象。
static void setup_object(struct kmem_cache *s, struct page *page,
void *object)
{
/* 为每个对象的存储区赋值,调试用 */
setup_object_debug(s, page, object);
/* 调用构造函数 */
if (unlikely(s->ctor))
s->ctor(object);
}
set_freepointer
static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)
{
/* 对象后面offset偏移处保存下一个空闲对象的指针 */
*(void **)(object + s->offset) = fp;
}