Linux处理内存缓存的关键内核函数

套接字缓冲区描述符
这个缓存是由net/core/skbuff.c的skb_init分配的,用于分配sk_buff缓冲区描述符。sk_buff结构可能是网络子系统中分配和回收注册次数最高的。
邻居协议映射
每个邻居协议都使用一个缓冲区,以分配存储L3层(网络层,例如:IP)到L2层(链路层,例如:Ethernet)地址映射的数据结构。
路由表
路由代码使用两块缓存,用于定义路径的两个数据结构。

以下是用于处理内存缓存的关键内核函数:

创建一个缓存:

void kmem_cache_free(struct kmem_cache *c, void *b)
{
if (unlikely(c->flags & SLAB_DESTROY_BY_RCU)) {
struct slob_rcu *slob_rcu;
slob_rcu = b + (c->size - sizeof(struct slob_rcu));
INIT_RCU_HEAD(&slob_rcu->head);
slob_rcu->size = c->size;
call_rcu(&slob_rcu->head, kmem_rcu_free);
} else {
__kmem_cache_free(b, c->size);
}
}

销毁一个缓存

void kmem_cache_destroy(struct kmem_cache *c)
{
slob_free(c, sizeof(struct kmem_cache));
}

为缓存分配一个缓冲:

void *kmem_cache_alloc(struct kmem_cache *c, gfp_t flags)
{
void *b;

if (c->size < PAGE_SIZE)
b = slob_alloc(c->size, flags, c->align);
else
b = (void *)__get_free_pages(flags, get_order(c->size));

if (c->ctor)
c->ctor(b, c, 0);

return b;
}

回收一个缓冲:

void kmem_cache_free(struct kmem_cache *c, void *b)
{
if (unlikely(c->flags & SLAB_DESTROY_BY_RCU)) {
struct slob_rcu *slob_rcu;
slob_rcu = b + (c->size - sizeof(struct slob_rcu));
INIT_RCU_HEAD(&slob_rcu->head);
slob_rcu->size = c->size;
call_rcu(&slob_rcu->head, kmem_rcu_free);
} else {
__kmem_cache_free(b, c->size);
}
}

通常由调用包裹函数(wrapper)实现分配和回收一个缓存缓冲区,包裹函数在较高层中管理用于处理分配和回收的请求。
例如用kfree_skb要求释放一个sk_buff缓冲区的一个实例时,只有当所有对该缓冲区的引用都已释放,而且相关的子系统(防火墙)也把所有必要的清理工作都做完后,才会去调用kmem_cache_free。
给定缓冲区(存在时)所能分配的实例数目的限制,通常由内容kmem_cache_alloc的包裹函数决定,但是有些时候可以通过/proc里的参数进行配置。

标签: 内存缓存

添加新评论