/*
* This happens when the module gets unloaded and
* doesn't destroy its slab cache and noone else reuses
* the vmalloc area of the module. Print a warning.
*/
#ifdef CONFIG_X86_UACCESS_INDIRECT
if (__direct_get_user(tmp,pc->name)) {
#else
if (__get_user(tmp,pc->name)) {
#endif
printk("SLAB: cache with size %d has lost its "
"name\n", pc->objsize);
continue;
}
if (!strcmp(pc->name,name)) {
printk("kmem_cache_create: duplicate "
"cache %s\n",name);
up(&cache_chain_sem);
unlock_cpu_hotplug();
BUG();
}
}
set_fs(old_fs);
}
if (unlikely(!ac->avail)) {
int x;
x = cache_grow(cachep, flags);
// cache_grow can reenable interrupts, then ac could change.
ac = ac_data(cachep);
//如果grow失败,返回NULL
if (!x && ac->avail == 0) // no objects in sight? abort
return NULL;
//如果grow成功,则重复上述操作,即从三链表中取空闲对象^_^
if (!ac->avail) // objects refilled by interrupt?
goto retry;
}
ac->touched = 1;
return ac_entry(ac)[--ac->avail];
}
这段代码涉及到slab_bufctl(),等我们看完分配,释放的全过程后。再来详细分析它涉及到的各项操作,cache_grow()用来做slab分配器与slab的交互。它的代码如下示:
static int cache_grow (kmem_cache_t * cachep, int flags)
{
struct slab *slabp;
void *objp;
size_t offset;
int local_flags;
unsigned long ctor_flags;
if (flags & ~(SLAB_DMA|SLAB_LEVEL_MASK|SLAB_NO_GROW))
BUG();
if (flags & SLAB_NO_GROW)
return 0;
ctor_flags = SLAB_CTOR_CONSTRUCTOR;
local_flags = (flags & SLAB_LEVEL_MASK);
if (!(local_flags & __GFP_WAIT))
/*
* Not allowed to sleep. Need to tell a constructor about
* this - it might need to know...
*/
ctor_flags |= SLAB_CTOR_ATOMIC;
/* About to mess with non-constant members - lock. */
check_irq_off();
spin_lock(&cachep->spinlock);
//取得下一个偏移索引(着色机制在前面已经详细分析了)
offset = cachep->colour_next;
cachep->colour_next++;
//如果大于允许的最大颜色,那就把计数归位,即为0
if (cachep->colour_next >= cachep->colour)
cachep->colour_next = 0;
//计算偏移量
offset *= cachep->colour_off;
spin_unlock(&cachep->spinlock);
if (local_flags & __GFP_WAIT)
local_irq_enable();
kmem_flagcheck(cachep, flags);
//向伙伴系统申请内存
if (!(objp = kmem_getpages(cachep, flags, -1)))
goto failed;
//分配slab描述符,这里有两种情况,一种是slab在缓存外部,另一种是内部
if (!(slabp = alloc_slabmgmt(cachep, objp, offset, local_flags)))
goto opps1;
return slabp;
}
cache_init_objs()初始化分配得到的每一个对象,代码如下:
static void cache_init_objs (kmem_cache_t * cachep,
struct slab * slabp, unsigned long ctor_flags)
{
int i;
for (i = 0; i num; i++) {
//取slab中的每一个对像
void* objp = slabp->s_mem+cachep->objsize*i;
#if DEBUG
//忽略掉debug信息
/* need to poison the objs? */
if (cachep->flags & SLAB_POISON)
poison_obj(cachep, objp, POISON_FREE);
if (cachep->flags & SLAB_STORE_USER)
*dbg_userword(cachep, objp) = NULL;
if (cachep->flags & SLAB_RED_ZONE) {
*dbg_redzone1(cachep, objp) = RED_INACTIVE;
*dbg_redzone2(cachep, objp) = RED_INACTIVE;
}
/*
* Constructors are not allowed to allocate memory from
* the same cache which they are a constructor for.
* Otherwise, deadlock. They must also be threaded.
*/
if (cachep->ctor && !(cachep->flags & SLAB_POISON))
cachep->ctor(objp+obj_dbghead(cachep), cachep, ctor_flags);
if (cachep->flags & SLAB_RED_ZONE) {
if (*dbg_redzone2(cachep, objp) != RED_INACTIVE)
slab_error(cachep, "constructor overwrote the"
" end of an object");
if (*dbg_redzone1(cachep, objp) != RED_INACTIVE)
slab_error(cachep, "constructor overwrote the"
" start of an object");
}
if ((cachep->objsize % PAGE_SIZE) == 0 && OFF_SLAB(cachep) && cachep->flags & SLAB_POISON)
kernel_map_pages(virt_to_page(objp), cachep->objsize/PAGE_SIZE, 0);
#else
//如果有初始化函数,则调用之
if (cachep->ctor)
cachep->ctor(objp, cachep, ctor_flags);
#endif
//更新bufctl数组
slab_bufctl(slabp) = i+1;
}
//置末尾描述符
slab_bufctl(slabp)[i-1] = BUFCTL_END;
slabp->free = 0;
}
同样,slab_bufctl的分析,等讲完释放对像的时候再继续
到此,我们已经看完到分配对象的全过程,接着来看怎么释放一个对象