6.slab层
为了便于数据的频繁分配和回收,Linux内核提供了slab层(也就是所谓的slab分配器)。slab分配器扮演了通用数据结构缓存层的角色。
slab层把不同的对象划分为所谓高速缓存(cache)组,其中每个高速缓存都存放不同类型的对象。这些高速缓存又被划分为slab,slab由一个或多个物理上连续的页组成。一般情况下,slab也就仅仅由一页组成。每个调整缓存可以由多个slab组成。
每个slab都包含一些对象成员,这里的对象指的是被缓存的数据结构。每个slab处于三种状态之一:满、部分满或空。每个高速缓存都是用 kmem_cache_s 结构来表示。这个结构包含三个链表 slabs_full,slabs_partial 和 slabs_empty,均存放在 kmem_lists 结构内。这些链表包含高速缓存中的所有slab。slab描述符 struct slab 用来描述每个slab:
struct slab { struct list_head list; /* 满、部分满或空链表 */ unsigned long colouroff; /* slab 着色的偏移量 */ void *s_mem; /* 在 slab 中的第一个对象 */ unsigned int inuse; /* 已分配的对象数 */ kmem_bufctl_t tree; /* 第一个空间对象(如果有的话) */ };
一个新的高速缓存是通过以下函数创建:
kmem_cache_t *kmem_cache_create( const char *name, /* 存放着高速缓存的名字 */ size_t size, /* 高速缓存中每个元素的大小 */ size_t align, /* 高速缓存内第一个对象的偏移,通常0可以满足要求 */ unsigned long flags, /* 控制高速缓存的行为,可以为0,或者标志组合 */ void (*ctor)( void *, kmem_cache_t *, unsigned long ), /* 构造函数 */ void (*dtor)( void *, kmem_cache_t *, unsigned long )); /* 析构函数 */
kmem_cache_create 在成功时会返回一个指向所创建高速缓存的指针,否则,返回 NULL。这个函数不能在中断上下文中调用,因为它可能会睡眠。
要销毁一个高速缓存,则调用:
int kmem_cache_destroy( kmem_cache_t *cachep );
调用该函数之前必须确保存在以下两个条件:
1)高速缓存中的所有slab都必须为空。
2)在调用 kmem_cache_destroy 期间不再访问这个高速缓存,调用者必须确保这种同步。
该函数成功执行,返回0;否则,返回非0值。
创建高速缓存之后,就可以通过下列函数从中获取对象:
void *kmem_cache_alloc( kmem_cache_t *cachep, int flags );
该函数从给定的高速缓存 cachep 中返回一个指向对象的指针,如果高速缓存的所有 slab 中都没有空间的对象,那么 slab层必须通过 kmem_getpages 获取新的页,flags的值传递给 __get_free_pages。应该使用 GFP_KERNEL 或 GFP_ATOMIC。
释放一个对象,并把它返回给原先的slab,可以使用下面这个函数:
void kmem_cache_free( kmem_cache_t *cachep, void *objp);