📄 linux-+
字号:
unsigned int gfporder;<br>
<br>
/* force GFP flags, e.g. GFP_DMA */<br>
unsigned int gfpflags;<br>
<br>
size_t colour; /* cache colouring range */<br>
unsigned int colour_off; /* colour offset
*/<br>
unsigned int colour_next; /* cache
colouring */<br>
kmem_cache_t *slabp_cache;<br>
unsigned int growing;<br>
unsigned int dflags; /* dynamic flags */<br>
<br>
/* constructor func */<br>
void (*ctor)(void *, kmem_cache_t *,
unsigned long);<br>
<br>
/* de-constructor func */<br>
void (*dtor)(void *, kmem_cache_t *,
unsigned long);<br>
<br>
unsigned long failures;<br>
<br>
/* 3) cache creation/removal */<br>
char name[CACHE_NAMELEN];<br>
struct list_head next;<br>
#ifdef CONFIG_SMP<br>
/* 4) per-cpu data */<br>
cpucache_t *cpudata[NR_CPUS];<br>
#endif<br>
#if STATS<br>
unsigned long num_active;<br>
unsigned long num_allocations;<br>
unsigned long high_mark;<br>
unsigned long grown;<br>
unsigned long reaped;<br>
unsigned long errors;<br>
#ifdef CONFIG_SMP<br>
atomic_t allochit;<br>
atomic_t allocmiss;<br>
atomic_t freehit;<br>
atomic_t freemiss;<br>
#endif<br>
#endif<br>
};<br>
</font><br>
<font color="green">slabs</font>用它将这个cache的slab连成一个链表<br>
<font color="green">firstnotfull</font>指向第一个不满的slab,当分配(复用)对象的时候,首先考虑在它指向的slab里分配.<br>
<font color="green">objsize</font>该cache中对象大小<br>
<font color="green">flags</font><br>
<font color="green">num</font>对象个数<br>
<br>
<font color="green">gfporder</font>该cache中slab一个占用多少页面,当构造新的slab,按照这个大小向页面级分配器申请页面。<br>
<font color="green">gfpflags</font>申请页面时,向页面级分配器提出的要求,例如是否要求申请DMA的页面,是否要求申请是原子的(即页面分配器在分配的时候不能被阻塞)<br>
<font color="green">colour </font>colour的范围,这个cache的slab依次用0,1,...,colour-1,0,1,...为颜色。<br>
<font color="green">colour_off</font>这个cache中colour粒度,例如为一个L1-CACHE线。<br>
<font color="green">colour_next</font>下一个colour数,当cache分配一个新的slab时,采用这个colour,也就是colour
* colour_off为slab空出的字节数<br>
<font color="green">slabp_cache</font><font color="green"> </font>当这个cache中的slab,其管理部分(slab描述符和kmem_bufctl_t数组)放在slab外面时,这个指针指向放置的通用cache<br>
<font color="green">growing</font><br>
<font color="green">dflags</font><br>
<font color="green">ctor</font><font color="green"> </font>指向对象的构造器,在这个cache创建一个新的slab时,对里面所有的对象都进行一次构造调用(参见slab的设计思想中关于对象复用部分)<br>
<font color="green">dtor</font><font color="green"> </font>指向对象的析构器,在这个cache销毁一个slab时,对里面所有的对象都进行一次析构调用<br>
<font color="green">failures</font><br>
<br>
<font color="green">name</font><font color="green"> </font>这个cache的名字<br>
<font color="green">next</font><font color="green"> </font>用它和其它的cache串成一个链,在这个链上按照时钟算法定期地回收某个cache的部分slab<br>
<br>
<font color="blue"><br>
slab描述符<br>
</font><br>
<font color="green">typedef struct slab_s {<br>
struct list_head list;<br>
unsigned long colouroff;<br>
void *s_mem; /* including colour offset */<br>
unsigned int inuse; /* num of objs active in slab */<br>
kmem_bufctl_t free;<br>
} slab_t;<br>
</font><br>
<br>
<font color="green">list</font>用于链表,这个链表将cache中所有的slab连接起来<br>
<font color="green">colouroff</font>这个slab中第一个对象距离slab起始位置(也就是页块起始位置)的字节数,实际上s_mem=页块首地址+colouroff<br>
<font color="green">s_mem</font>这个slab中第一个对象的起始位置<br>
<font color="green">inuse</font>这个slab中被使用的对象个数,用于调整slab格局,当inuse=0说明这个slab全空,将这个slab从部分满的slab段中移动到全空的slab段中<br>
<font color="green">free</font>第一个未用对象的ID, 当在这个slab"分配"(复用)对象时,首先用这个ID的对象。<br>
<br>
<font color="blue"><br>
通用cache索引结构<br>
用这个结构组成的数组cache_sizes给不同尺寸的通用cache提供索引<br>
</font><font color="green">typedef struct cache_sizes {<br>
size_t cs_size;<br>
kmem_cache_t *cs_cachep;<br>
kmem_cache_t *cs_dmacachep;<br>
} cache_sizes_t;<br>
cs_size</font>通用cache的对象尺寸<br>
<font color="green">cs_cachep</font>指向一个通用cache,
它的对象尺寸为cs_size<br>
<font color="green">cs_dmacachep</font>指向一个通用DMA的cache,
它的对象尺寸为cs_size<br>
<br>
<br>
<br>
<font color="blue">Slab分配器的结构</font><br>
<br>
Slab 分配器用于管理内核的核心对象。<br>
<br>
它有若干个 cache 组成。每个 cache 管理一个特定类的对象。<br>
<br>
每个cache有若干个 slab (Slab分配器的名字可能就是怎么来的)组成,每个
slab<br>
实际上就是若干个页面组成的一个页块。这个页块被细分成许多对象。<br>
cache为管理这些slab, 通过 cache描述符( kmem_cache_t )以及指针将这些
slab<br>
连起来。<br>
</span></p>
<font color="blue">验证</font><br>
cache的数据结构中下面这个字段:<br>
struct kmem_cache_s {<br>
<br>
struct list_headslabs;<br>
... ...<br>
}<br>
<br>
与slab结构中下面字段:<br>
<br>
typedef struct slab_s {<br>
struct list_headlist;<br>
...<br>
} slab_t;<br>
<br>
共同构成这个链表.
<p><span class="post"><font color="#FF00FF">slab如何管理它的对象</font><br>
<br>
一个 slab 通过自己的 kmem_bufctl_t
数组,来管理它的空闲对象。这个数组的元素和该 slab中的对象是一一对应的。<br>
</span>初始化一个slab时,每个对象都是空的,所以这个数组每个元素(除最后一个)都指向下一个:<br>
在kmem_cache_init_objs中<br>
static inline void kmem_cache_init_objs (kmem_cache_t * cachep, slab_t * slabp,
unsigned long ctor_flags)<br>
{<br>
int i;<br>
<br>
for (i = 0; i < cachep->num; i++) {<br>
.. ...<br>
slab_bufctl(slabp)[ i ] = i+1;<br>
}<br>
slab_bufctl(slabp)[i-1] = BUFCTL_END;<br>
... ...<br>
}<br>
<br>
分配对象时,在下面的语句中,<br>
<br>
objp = slabp->s_mem + slabp->free*cachep->objsize;<br>
slabp->free=slab_bufctl(slabp)[slabp->free];<br>
<br>
取出free的数值1,计算对象1的位置即可。然后将free指向3.<br>
回收(应该说将对象置为未用)时,将数组中对象对应的元素插入链表头即可:<br>
slab_bufctl(slabp)[objnr] = slabp->free;<br>
slabp->free = objnr;<br>
</p>
<p class="post"><span class="post"><font color="#FF00FF">cache如何管理它的slab</font><br>
<br>
<font color="blue">格局</font><br>
<br>
一个cache的所有 slab 通过指针连成一个队列,这些 slab的排列始终保持一个格局:
全满的,部分满的,和全空的。<br>
另外,cache 描述符有一个指针始终指向第一个不满的slab(首先可能是部分满的,其次是全空的),当它指向描述符本身的时候,说明没有不满的
slab了。当 slab 是否满的状态有变化时,cache会调整它的位置,以保持上述格局,例如一个部分满的
slab由于它的最后一个对象被设置为不使用,即它为全空的了,那么它将被调整到全空的slab部分中。<br>
<br>
<FONT<BR>
当分配一个新的对象时,cache 首先通过 firstnotfull
找到它的第一个不满的slab,
在那么分配对象。如果没有不满的slab,<br>
则向页面级分配器申请一个页块,然后初始化为一个slab.<br>
<br>
<font color="blue">回收对象</font><br>
<br>
当回收一个对象时,即便在这之后,这个对象所在的 slab
为全空,cache也不会将这个 slab<br>
占用的页块还给页面级分配器。<br>
<br>
<font color="blue">回收slab</font><br>
<br>
slab分配器算法提供两种回收slab的方式,一种是回收某个特定的cache的所有全空的slab,直到有用户又在该cache分配新的
slab为止( kmem_cache_shrink);一种是对所有的 cache
采用时钟算法,每次选择一个比较合适的 cache,回收它部分的空
slab( kmem_cache_reap ).<br>
<br>
<font color="blue">验证</font><br>
<br>
每次分配的时候总是考察从firstnotfull指向的第一个不满的slab:<br>
#define kmem_cache_alloc_one(cachep) \<br>
({
\<br>
slab_t*slabp; \<br>
\<br>
/* Get slab alloc is to come from. */ \<br>
{ \<br>
struct list_head* p = cachep->firstnotfull;/*<----------这里*/ \<br>
if (p == &cachep->slabs) \<br>
goto<br>
alloc_new_slab;/*<---------如果这个指针指向cache了,说明没有不满的slab了,?br>簿褪撬狄
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -