水準有限,描述不當之處還請之處,轉載請注明出處http://blog.csdn.net/vanbreaker/article/details/7702677
建立新的slab主要有兩個工作,一個是從夥伴系統配置設定2^order個連續頁框給該slab,然後就是劃分slab中的對象。
函數new_slab()用來建立一個新的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);
page->slab = s;//設定頁描述符的slab指針
page->flags |= 1 << PG_slab;//為頁框增加一個slab屬性
if (s->flags & (SLAB_DEBUG_FREE | SLAB_RED_ZONE | SLAB_POISON |
SLAB_STORE_USER | SLAB_TRACE))
__SetPageSlubDebug(page);
/*擷取頁框的虛拟位址*/
start = page_address(page);
if (unlikely(s->flags & SLAB_POISON))
memset(start, POISON_INUSE, PAGE_SIZE << compound_order(page));
last = start;
for_each_object(p, s, start, page->objects) {
setup_object(s, page, last);//調用構造函數
set_freepointer(s, last, p); //設定空閑指針,即last後面的空閑對象為p
last = p;
}
setup_object(s, page, last);
set_freepointer(s, last, NULL); //最後一個對象的空閑指針設為NULL
/*設定page的freelist和inuse*/
page->freelist = start;
page->inuse = 0;
out:
return page;
}
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.
*/
/*确定gfp辨別*/
alloc_gfp = (flags | __GFP_NOWARN | __GFP_NORETRY) & ~__GFP_NOFAIL;
/*配置設定頁框*/
page = alloc_slab_page(alloc_gfp, node, oo);
/*如果配置設定失敗,則按min的标準進行配置設定*/
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(get_cpu_slab(s, raw_smp_processor_id()), ORDER_FALLBACK);
}
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);//從oo中提取出slab中的對象數放到儲存到page的objects中
mod_zone_page_state(page_zone(page),
(s->flags & SLAB_RECLAIM_ACCOUNT) ?
NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE,
1 << oo_order(oo));
return page;
}
函數alloc_slab_page()便是Slub配置設定器與夥伴系統的接口!
static inline struct page *alloc_slab_page(gfp_t flags, int node,
struct kmem_cache_order_objects oo)
{
int order = oo_order(oo);//從oo中提取出配置設定階數
flags |= __GFP_NOTRACK;
/*從夥伴系統中配置設定2^order個連續頁框*/
if (node == -1)
return alloc_pages(flags, order);
else
return alloc_pages_node(node, flags, order);
}
獲得了所需的頁框後,接下來就是在這些頁框中劃分對象,将他們全部組織起來
for_each_object(p, s, start, page->objects) {
setup_object(s, page, last);//調用構造函數
set_freepointer(s, last, p); //設定空閑指針,即last後面的空閑對象為p
last = p;
}
#define for_each_object(__p, __s, __addr, __objects) \
for (__p = (__addr); __p < (__addr) + (__objects) * (__s)->size;\
__p += (__s)->size)
static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)
{
/*注意kmem_cache中的offset是以位元組為機關的*/
*(void **)(object + s->offset) = fp;
}
初始化後的對象如下圖所示
銷毀slab通過函數discard_slab()來完成
static void discard_slab(struct kmem_cache *s, struct page *page)
{
/*減少節點的slab計數和對象計數*/
dec_slabs_node(s, page_to_nid(page), page->objects);
free_slab(s, page);//釋放slab
}
static void free_slab(struct kmem_cache *s, struct page *page)
{
if (unlikely(s->flags & SLAB_DESTROY_BY_RCU)) {
/*
* RCU free overloads the RCU head over the LRU
*/
struct rcu_head *head = (void *)&page->lru;
call_rcu(head, rcu_free_slab);//通過RCU方式來釋放
} else
__free_slab(s, page);//将slab所占頁框釋放回夥伴系統
}