在滿足以下兩個條件時,slab分配器將為高速緩存創建新的slab
1.請求分配對象,但本地高速緩存沒有空閒對象可以分配,需要填充
2.kmem_list3維護的鏈表中沒有slab或者所有的slab都處於FULL鏈表中
這時,調用cache_grow()創建slab增大緩存容量
相關閱讀:
Linux Slab分配器(一)--概述 http://www.linuxidc.com/Linux/2012-06/62965.htm
Linux Slab分配器(二)--初始化 http://www.linuxidc.com/Linux/2012-06/62966.htm
Linux Slab分配器(三)--創建緩存 http://www.linuxidc.com/Linux/2012-06/63109.htm
Linux Slab分配器(四)--分配對象 http://www.linuxidc.com/Linux/2012-06/63138.htm
下圖給出了cache_grow()的代碼流程
- static int cache_grow(struct kmem_cache *cachep,
- gfp_t flags, int nodeid, void *objp)
- {
- struct slab *slabp;
- size_t offset;
- gfp_t local_flags;
- struct kmem_list3 *l3;
-
- /*
- * Be lazy and only check for valid flags here, keeping it out of the
- * critical path in kmem_cache_alloc().
- */
- BUG_ON(flags & GFP_SLAB_BUG_MASK);
- local_flags = flags & (GFP_CONSTRAINT_MASK|GFP_RECLAIM_MASK);
-
- /* Take the l3 list lock to change the colour_next on this node */
- check_irq_off();
- l3 = cachep->nodelists[nodeid];
- spin_lock(&l3->list_lock);
-
- /* Get colour for the slab, and cal the next value. */
- /*確定待創建的slab的顏色編號*/
- offset = l3->colour_next;
- /*更新下一個slab的顏色編號*/
- l3->colour_next++;
- /*顏色編號必須小於顏色數*/
- if (l3->colour_next >= cachep->colour)
- l3->colour_next = 0;
- spin_unlock(&l3->list_lock);
-
- /*確定待創建的slab的顏色*/
- offset *= cachep->colour_off;
-
- if (local_flags & __GFP_WAIT)
- local_irq_enable();
-
- /*
- * The test for missing atomic flag is performed here, rather than
- * the more obvious place, simply to reduce the critical path length
- * in kmem_cache_alloc(). If a caller is seriously mis-behaving they
- * will eventually be caught here (where it matters).
- */
- kmem_flagcheck(cachep, flags);
-
- /*
- * Get mem for the objs. Attempt to allocate a physical page from
- * 'nodeid'.
- */
- if (!objp)
- /*從伙伴系統分配頁框,這是slab分配器與伙伴系統的接口*/
- objp = kmem_getpages(cachep, local_flags, nodeid);
- if (!objp)
- goto failed;
-
- /* Get slab management. */
- /*分配slab管理區*/
- slabp = alloc_slabmgmt(cachep, objp, offset,
- local_flags & ~GFP_CONSTRAINT_MASK, nodeid);
- if (!slabp)
- goto opps1;
-
- /*建立頁面到slab和cache的映射,以便於根據obj迅速定位slab描述符和cache描述符*/
- slab_map_pages(cachep, slabp, objp);
-
- /*初始化對象*/
- cache_init_objs(cachep, slabp);
-
- if (local_flags & __GFP_WAIT)
- local_irq_disable();
- check_irq_off();
- spin_lock(&l3->list_lock);
-
- /* Make slab active. */
- /*將新創建的slab添加到free鏈表*/
- list_add_tail(&slabp->list, &(l3->slabs_free));
- STATS_INC_GROWN(cachep);
- l3->free_objects += cachep->num;
- spin_unlock(&l3->list_lock);
- return 1;
- opps1:
- kmem_freepages(cachep, objp);
- failed:
- if (local_flags & __GFP_WAIT)
- local_irq_disable();
- return 0;
- }