天天看点

【存储管理】内核缓冲区的管理

专用缓冲区队列

(1)在kmem_cache_s中,slabs维持一个slab队列,firstnotfull指向队列中第一个含有空闲对象的slab,当firstnotfull== slabs表示队列中已不存在空闲对象slab,next用来cache_cache建立专用缓冲区slab队列的队列,及slab队列控制结构的队列,当slab的slabt与对象不再同一个slab上时即大对象,指针slabp_cache指向对方队列中的控制结构,num表示slab上有几个缓冲区,gfporder表示每一个slab的大小,objsize表示原始对象的大小(如node);

(2)在使用kmem_cache_create()时,参数offset为0表示对第一个缓冲区在slab中的位移并无要求,但flags是SLAB_HWCACHE_ALIGN表示要求与高速缓存中的缓冲行边界对齐,指明构造函数和拆除函数;具体功能是经过一系列的运算,以确定每一个slab有几个页面组成,划分成多少个对象缓冲区,slab的控制结构kmem_slab_t应该在slab上外面集中存储,还是与相应的缓冲区紧挨着放在一起,还有“颜色”数量等等,最后要将kmem_cache_t链入cache_cahe的next队列中;它只是建立了所需的专用缓冲区队列的基础设施,所形成的slab队列是个空队列,具体的创建等需要分配缓冲区时,却发现队列中无空闲的缓冲区可供分配,使用kmem_cache_grow来进行的;

(3)在_kmem_cache_alloc()中,kem_cache_alloc_one()通过队列头的指针firstnotfull,找到第一个含有空闲对象的slab,如果它与slabs相同,说明还未建立好slab队列,是个空队列或没有空闲对象的slab,应该进一步扩充;如果找到了空的slab,就使用kmem_cache_alloc_one_tail,return slab->smem+slab->free*cache->objsize,更新slabt,kmem_cache_t里的相关信息;如果slab队列中已经不存在包含空闲对象的slab,所以到标号alloc_new_slab中,使用kmem_cache_grow来分配一块新的slab,使缓冲区队列生长起来;

(4)在kmem_cache_grow中,首先对一些参数进行了一些检查以后,计算出下一块slab的着色区大小,通过kmem_getpages()分配用于具体对象缓冲区的页面,这个函数最终调用alloc_pages()分配空闲页面,然后使用kmem_cache_slabmgme建立起slab的管理信息,及更新inuse=0,以及更新colouroff着色区的大小s_mem=objp+colour_off;使用宏操作SET_PAGE_CACHE,SET_PAGE_SLAB设置page的prev和next,分别使他们属于所属的slab和slab队列,PageSetSlab设置page的PG_slab设置为1,以表明页面的用途;缓冲区队列增长以后, 在_kmem_cache_alloc()中try_again重试;

(5)其实在_kmem_cache_alloc()在之前,我们会调用skb_from_poll(),先从已分配的slab块中分配,如果失败的话再试_kmem_cache_alloc();缓冲区队列的缩小是通过kswapd定时地调用kmem_cache_reap()来收割,依次检查若干专用缓冲区slab队列,看是否有完全空闲的slab存在,有的话就将这些slab占用的内存页面释放;

(6)kmem_cache_free()中的kmem_cache_free_one()通过slab的链接数组释放给定对象,还要递减所属slab队列控制结构中的非空闲对象的计数即inuse,分为三种情况(原slab没有空闲对象后现在有了,原slab有空闲对象后现在所有的都空闲了,原slab有空闲对象后现在就多一个);

通用缓冲区队列

(1)kmalloc就是使用使用通用缓冲区队列的一个例子,它首先在cache_sizes结构数组中从小到大扫描,找到第一个能满足要求的队列,然后调用_kmem_cache_alloc()从该队列中分配一个缓冲区;