`
tomhibolu
  • 浏览: 1385315 次
文章分类
社区版块
存档分类
最新评论

kernel hacker修炼之道之内存管理-SLAB(销毁SLAB高速缓存kmem_cache_destroy())

 
阅读更多

销毁SLAB高速缓存kmem_cache_destroy()

作者:李万鹏 于北京 borqs


调用kmem_cache_destroy()释放cache。这个函数一般是在模块卸载的时候调用,在调用这个函数之前,cache应该是empty的。调用者必须保证在执行kmem_cache_destroy()的时候,不会对这个cache有任何内存分配。这里将share local slab中的指针释放回slab,然后对slabs_free上所有的slab进行释放。


int kmem_cache_destroy (kmem_cache_t * cachep)
{
int i;
/*指针不能为空,也不能在中断上下文*/
if (!cachep || in_interrupt())
BUG();

/* Don't let CPUs to come and go */
lock_cpu_hotplug();
/* Find the cache in the chain of caches. */
down(&cache_chain_sem);
/*将cache从cache_chain链表上删掉*/
list_del(&cachep->next);
up(&cache_chain_sem);
/*将slab中的对象都释放掉,如果slabs_partial或slabs_full链表不为空,则无法释放左右对象,再把cache加回以cache_chain为链表头的链表*/
if (__cache_shrink(cachep)) {
slab_error(cachep, "Can't free all objects");
down(&cache_chain_sem);
list_add(&cachep->next,&cache_chain);
up(&cache_chain_sem);
unlock_cpu_hotplug();
return 1;
}
if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU))
synchronize_kernel();
/* no cpu_online check required here since we clear the percpu
* array on cpu offline and set this to NULL.
*/
/*释放cpu local slab 数组*/
for (i = 0; i < NR_CPUS; i++)
kfree(cachep->array[i]);
/* NUMA: free the list3 structures */
/*释放共享local cpu slab*/
kfree(cachep->lists.shared);
cachep->lists.shared = NULL;
/*释放cache的描述符*/
kmem_cache_free(&cache_cache, cachep);
unlock_cpu_hotplug();
return 0;
}


static int __cache_shrink(kmem_cache_t *cachep)
{
struct slab *slabp;
int ret;
/*将共享local slab上的对象全部释放回slab*/
drain_cpu_caches(cachep);

check_irq_on();
spin_lock_irq(&cachep->spinlock);
/*释放slabs_free上的所有对象,然后释放slab块*/
for(;;) {
struct list_head *p;

p = cachep->lists.slabs_free.prev;
if (p == &cachep->lists.slabs_free)
break;

slabp = list_entry(cachep->lists.slabs_free.prev, struct slab, list);
#if DEBUG
if (slabp->inuse)
BUG();
#endif
list_del(&slabp->list);

cachep->lists.free_objects -= cachep->num;
spin_unlock_irq(&cachep->spinlock);
slab_destroy(cachep, slabp);
spin_lock_irq(&cachep->spinlock);
}
ret = !list_empty(&cachep->lists.slabs_full) ||
!list_empty(&cachep->lists.slabs_partial);
spin_unlock_irq(&cachep->spinlock);
return ret;
}


static void drain_cpu_caches(kmem_cache_t *cachep)
{
smp_call_function_all_cpus(do_drain, cachep);
check_irq_on();
spin_lock_irq(&cachep->spinlock);
/*如果存在共享 local slab,将其释放回slab*/
if (cachep->lists.shared)
drain_array_locked(cachep, cachep->lists.shared, 1);
spin_unlock_irq(&cachep->spinlock);
}

static void drain_array_locked(kmem_cache_t *cachep,
struct array_cache *ac, int force)
{
int tofree;

check_spinlock_acquired(cachep);
if (ac->touched && !force) {
ac->touched = 0;
} else if (ac->avail) {
/*如果存在对象*/
tofree = force ? ac->avail : (ac->limit+4)/5;
if (tofree > ac->avail) {
tofree = (ac->avail+1)/2;
}
/*将对象归还给slab*/
free_block(cachep, ac_entry(ac), tofree);
ac->avail -= tofree;
memmove(&ac_entry(ac)[0], &ac_entry(ac)[tofree],
sizeof(void*)*ac->avail);
}
}


static void free_block(kmem_cache_t *cachep, void **objpp, int nr_objects)
{
int i;

check_spinlock_acquired(cachep);

/* NUMA: move add into loop */
/*要释放多少个对象,cache空闲对象的数目就增加多少*/
cachep->lists.free_objects += nr_objects;

for (i = 0; i < nr_objects; i++) {
void *objp = objpp[i];
struct slab *slabp;
unsigned int objnr;
/**获得对象坐在slab的地址/
slabp = GET_PAGE_SLAB(virt_to_page(objp));
/*把slab从它所在的链表上删除*/
list_del(&slabp->list);
/*计算对象的number*/
objnr = (objp - slabp->s_mem) / cachep->objsize;
check_slabp(cachep, slabp);
#if DEBUG
if (slab_bufctl(slabp)[objnr] != BUFCTL_FREE) {
printk(KERN_ERR "slab: double free detected in cache '%s', objp %p.\n",
cachep->name, objp);
BUG();
}
#endif
/*kmem_bufctl_t数组指向下一个空闲的对象*/
slab_bufctl(slabp)[objnr] = slabp->free;
slabp->free = objnr;
STATS_DEC_ACTIVE(cachep);
/*slab中对象的使用计数减一*/
slabp->inuse--;
check_slabp(cachep, slabp);

/*如果slab中没有正在使用的了*/
if (slabp->inuse == 0) {
/*如果cache的空闲对象大于cache空闲对象的上限*/
if (cachep->lists.free_objects > cachep->free_limit) {
/*从cache空闲对象的数目中减去这个slab中空闲对象的数目*/
cachep->lists.free_objects -= cachep->num;
/*撤销这个slab块*/
slab_destroy(cachep, slabp);
} else {
/*否则把这个slab添加到slabs_free链表上*/
list_add(&slabp->list,
&list3_data_ptr(cachep, objp)->slabs_free);
}
} else {
/* Unconditionally move a slab to the end of the
* partial list on free - maximum time for the
* other objects to be freed, too.
*/
/*如果还有正在使用的则把slab添加到slabs_partial链表上*/
list_add_tail(&slabp->list,
&list3_data_ptr(cachep, objp)->slabs_partial);
}
}
}




分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics