全部博文(50)
分类: LINUX
2014-04-04 11:54:48
原文地址:Vi Linux内存 之 Slab分配器(七) 作者:palals
销毁一个cache节点。通常这只发生在卸载module时。
kmem_cache_destroy
销毁一个cache节点。
void kmem_cache_destroy(struct kmem_cache *cachep)
{
BUG_ON(!cachep || in_interrupt());
/* Find the cache in the chain of caches. */
get_online_cpus();
mutex_lock(&cache_chain_mutex);
/*
* the chain is never empty, cache_cache is never destroyed
*/
/* 将cache节点从cache_chain链表中摘除 */
list_del(&cachep->next);
/* 释放空slab链中的slab,并检查其他两个链表。在销毁cache前,必须先销毁其中的slab */
if (__cache_shrink(cachep)) {
/* 满slab链或部分满slab链不为空 */
slab_error(cachep, "Can't free all objects");
/* cache非空,重新加入到cache_chain链表中 */
list_add(&cachep->next, &cache_chain);
mutex_unlock(&cache_chain_mutex);
put_online_cpus();
return;
}
if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU))
rcu_barrier();
__kmem_cache_destroy(cachep);
mutex_unlock(&cache_chain_mutex);
put_online_cpus();
}
__cache_shrink
释放空slab链表中的slab。
static int __cache_shrink(struct kmem_cache *cachep)
{
int ret = 0, i = 0;
struct kmem_list3 *l3;
/* 释放local cache中对象 */
drain_cpu_caches(cachep);
check_irq_on();
for_each_online_node(i) {
l3 = cachep->nodelists[i];
if (!l3)
continue;
/* 释放空slab链表中的slab */
drain_freelist(cachep, l3, l3->free_objects);
/* 检查满slab链表和部分满slab链表中是否还有slab */
ret += !list_empty(&l3->slabs_full) ||
!list_empty(&l3->slabs_partial);
}
return (ret ? 1 : 0);
}
drain_cpu_caches
释放local cache和shared local cache中的对象。
static void drain_cpu_caches(struct kmem_cache *cachep)
{
struct kmem_list3 *l3;
int node;
/* 释放每个cpu local cache中的对象 */
on_each_cpu(do_drain, cachep, 1);
check_irq_on();
/* NUMA相关 */
for_each_online_node(node) {
l3 = cachep->nodelists[node];
if (l3 && l3->alien)
drain_alien_cache(cachep, l3->alien);
}
/* 释放shared local cache中的对象 */
for_each_online_node(node) {
l3 = cachep->nodelists[node];
if (l3)
drain_array(cachep, l3, l3->shared, 1, node);
}
}
do_drain
释放local cache中的对象。
static void do_drain(void *arg)
{
struct kmem_cache *cachep = arg;
struct array_cache *ac;
int node = numa_mem_id();
check_irq_off();
/* 获得本cpu的local cache */
ac = cpu_cache_get(cachep);
spin_lock(&cachep->nodelists[node]->list_lock);
/* 释放local cache中的对象 */
free_block(cachep, ac->entry, ac->avail, node);
spin_unlock(&cachep->nodelists[node]->list_lock);
ac->avail = 0;
}
drain_array
释放local cache中一定数目的对象。
void drain_array(struct kmem_cache *cachep, struct kmem_list3 *l3,
struct array_cache *ac, int force, int node)
{
int tofree;
if (!ac || !ac->avail)
return;
if (ac->touched && !force) {
ac->touched = 0;
} else {
spin_lock_irq(&l3->list_lock);
if (ac->avail) {
/* 计算释放对象的数目 */
tofree = force ? ac->avail : (ac->limit + 4) / 5;
if (tofree > ac->avail)
tofree = (ac->avail + 1) / 2;
/* 释放对象,从entry前面开始 */
free_block(cachep, ac->entry, tofree, node);
ac->avail -= tofree;
/* 后面的对象前移 */
memmove(ac->entry, &(ac->entry[tofree]),
sizeof(void *) * ac->avail);
}
spin_unlock_irq(&l3->list_lock);
}
}
drain_freelist
销毁空slab链表中的slab。
static int drain_freelist(struct kmem_cache *cache,
struct kmem_list3 *l3, int tofree)
{
struct list_head *p;
int nr_freed;
struct slab *slabp;
nr_freed = 0;
/* 释放空slab链表中的slab */
while (nr_freed < tofree && !list_empty(&l3->slabs_free)) {
spin_lock_irq(&l3->list_lock);
p = l3->slabs_free.prev;
if (p == &l3->slabs_free) {
spin_unlock_irq(&l3->list_lock);
goto out;
}
slabp = list_entry(p, struct slab, list);
#if DEBUG
BUG_ON(slabp->inuse);
#endif
/* 将slab从空slab链表中摘除 */
list_del(&slabp->list);
/*
* Safe to drop the lock. The slab is no longer linked
* to the cache.
*/
/* 总空闲对象数减去每个slab中对象数 */
l3->free_objects -= cache->num;
spin_unlock_irq(&l3->list_lock);
/* 销毁slab,包括slab管理对象和slab对象 */
slab_destroy(cache, slabp);
nr_freed++;
}
out:
return nr_freed;
}
__kmem_cache_destroy
static void __kmem_cache_destroy(struct kmem_cache *cachep)
{
int i;
struct kmem_list3 *l3;
/* 释放每个cpu local cache使用的struct array_cache对象,注意此时是online cpu, cpu如果是down状
态,并没有释放 */
for_each_online_cpu(i)
kfree(cachep->array[i]);
/* NUMA: free the list3 structures */
for_each_online_node(i) {
l3 = cachep->nodelists[i];
if (l3) {
/* 释放shared local cache使用的struct array_cache对象 */
kfree(l3->shared);
free_alien_cache(l3->alien);
kfree(l3);
}
}
/* 释放cache节点使用的struct kmem_cache对象 */
kmem_cache_free(&cache_cache, cachep);
}