slab源码分析缓存器的创建.docx
- 文档编号:5479987
- 上传时间:2023-05-08
- 格式:DOCX
- 页数:38
- 大小:33.97KB
slab源码分析缓存器的创建.docx
《slab源码分析缓存器的创建.docx》由会员分享,可在线阅读,更多相关《slab源码分析缓存器的创建.docx(38页珍藏版)》请在冰点文库上搜索。
slab源码分析缓存器的创建
slab源码分析--缓存器的创建
这个函数通常是在内核初始化时进行的,或者在首次加载模块时进行的。
structkmem_cache*kmem_cache_create(constchar*name,size_tsize,size_talign,unsignedlongflags,
void(*ctor)(void*,structkmem_cache*,unsignedlong),void(*dtor)(void*,structkmem_cache*,unsignedlong));
name参数定义了缓存器的名称,proc文件系统(可以cat/proc/slabinfo查看)使用它标识这个缓存。
size参数指定了这个缓存器负责分配的对象大小。
align参数定义了每个对象必须的对齐。
flags参数指定了为缓存启用的选项。
flags的标志如图:
选项说明
RED_ZONE在对象头、尾插入标志,用来支持对缓冲区溢出的检查
SLAB_POISON使用一种已知模式(如0xa5a5a5a5)填充slab,允许对缓存中的对象进行监视,不过可以在外部进行修改)
SLAB_HWCACHE_ALIGN指定缓存对象必须与硬件缓存行对齐
ctor和dtor是构造函数和析构函数,这不用说。
在创建缓存器之后,kmem_cache_create()函数会返回对它的引用。
注意这个函数并没有向缓存器提供任何用来分配对象内存。
相反,在试图从缓存器(最初为空)分配对象时,会通过cache_alloc_refill()函数向伙伴系统申请内存。
当所有对象都被分配出去后,可以再次这样做。
首先给出该函数的调用机制流程图:
kmem_cache_create()函数:
创建缓存器
kmem_cache_zalloc()函数:
申请缓存器缓存
__cache_alloc()函数:
kmem_cache_alloc和kmalloc申请内存的总接口
__do_cache_alloc()函数:
转调函数
____cache_alloc()函数:
申请缓存的核心函数
ac=cpu_cache_get()函数,获得本地缓存
if(av->avail),本地缓存足够
取ac末尾最热数据,objp=ac->entry[--ac->avail]
缓存器缓存申请成功
cache_alloc_refill(),重新填充
if(ls->shared),本地共享缓存足够
transfer_objects()函数,本地共享缓存转给本地缓存
成功向ac中转移了至少一个可用对象
retry:
在三链中搜寻可分配对象
三链中有空闲对象
cache_grow()函数,从伙伴系统获取
kmem_getpages()和alloc_slabmgmt()函数,并执行retry
yes
no
yes
no
yes
no
下面来看kmem_cache_create()函数的实现:
/**
*kmem_cache_create-Createacache.
*@name:
Astringwhichisusedin/proc/slabinfotoidentifythiscache.
*@size:
Thesizeofobjectstobecreatedinthiscache.
*@align:
Therequired(必须的的)alignmentfortheobjects.//
*@flags:
SLABflags
*@ctor:
Aconstructorfortheobjects.
*@dtor:
Adestructorfortheobjects(notimplementedanymore).
*
*Returnsaptrtothecacheonsuccess,NULLonfailure.//成功返回cache指针,失败返回空
*Cannotbecalledwithinaint,butcanbeinterrupted.//不能在中断中调用,但是可以被打断
*The@ctorisrunwhennewpagesareallocatedbythecache
*andthe@dtorisrunbeforethepagesarehandedback.
*
*@namemustbevaliduntilthecacheisdestroyed.Thisimpliesthat
*themodulecallingthishastodestroythecachebeforegettingunloaded.
*
*Theflagsare//填充标记
*
*%SLAB_POISON-Poison(使污染)theslabwithaknowntestpattern(a5a5a5a5)//使用a5a5a5a5填充这片未初始化区域
*tocatchreferencestouninitialisedmemory.
*
*%SLAB_RED_ZONE-Insert`Red'zonesaroundtheallocatedmemorytocheck//添加红色警戒区,检测越界
*forbufferoverruns.
*
*%SLAB_HWCACHE_ALIGN-Aligntheobjectsinthiscachetoahardware//物理缓存行对齐,
*cacheline.Thiscanbebeneficialifyou'recountingcyclesasclosely
*asdavem.
*/
//创建缓存器
/*gfporder:
取值0~11遍历直到计算出cache的对象数量跳出循环,slab由2^gfporder个页面组成
buffer_size:
为当前cache中对象经过cache_line_size对齐后的大小
align:
是cache_line_size,按照该大小对齐
flags:
此处为0,用于标识内置slab还是外置slab
left_over:
输出值,记录slab中浪费空间的大小
num:
输出值,用于记录当前cache中允许存在的对象数目
*/
structkmem_cache*
kmem_cache_create(constchar*name,size_tsize,size_talign,
unsignedlongflags,
void(*ctor)(void*,structkmem_cache*,unsignedlong),
void(*dtor)(void*,structkmem_cache*,unsignedlong))
{
size_tleft_over,slab_size,ralign;
structkmem_cache*cachep=NULL,*pc;
/*
*Sanitychecks...theseareallserioususagebugs.
*/
//参数检查,名字不能为NULL,不能在中断中调用本函数(本函数可能会睡眠)
//获取长度不得小于4字节,即CPU字长,获取长度不得大于最大值(我剖析的这个版本是2^25,有的可能是2^22)
if(!
name||in_interrupt()||(size size>KMALLOC_MAX_SIZE||dtor){ printk(KERN_ERR"%s: Earlyerrorinslab%s\n",__FUNCTION__, name); BUG(); } /* *Weusecache_chain_mutextoensureaconsistentviewof *cpu_online_mapaswell.Pleaseseecpuup_callback */ mutex_lock(&cache_chain_mutex); #if0//DEBUG部分被我注释掉了,免得挡点//一些检查机制,无需关注 ... #endif /* *Checkthatsizeisintermsof(依据)words.Thisisneededtoavoid *unalignedaccessesforsomearchs(拱)whenredzoningisused,andmakes//避免当红色警戒区被使用时,避免未对齐的访问接触红区 *sureanyon-slabbufctl'sarealsocorrectlyaligned.//同时确保任何on-slab的bfclt正确对齐 */ //// //为什么kmem_cache_init函数已经计算过size,align了,这里还要计算? //因为这里是用来创建缓存器的,只是借用了cache_cache,而kmem_cache_init函数中初始化的是cache_cahce的 //size,align等成员,所以无关系。 //// //先检查对象! ! ! ! 是不是32位对齐,如果不是则进行调整 if(size&(BYTES_PER_WORD-1)){ size+=(BYTES_PER_WORD-1); size&=~(BYTES_PER_WORD-1); } /*calculatethefinalbufferalignment: */ /*1)archrecommendation: canbeoverriddenfordebug*/ //再检查对象! ! ! 要不要求按照缓冲行对齐 if(flags&SLAB_HWCACHE_ALIGN){ /* *Defaultalignment: asspecifiedbythearchcode.Exceptif *anobjectisreallysmall,thensqueezemultipleobjectsinto *onecacheline. */ ralign=cache_line_size(); while(size<=ralign/2)//进行对齐大小的调整,我们要保证对象的大小大于针对硬件缓冲行对齐所需的大小 ralign/=2; }else{//不需要按硬件缓冲行对齐,那就默认4字节,即32位 ralign=BYTES_PER_WORD; } /* *Redzoninganduserstorerequirewordalignmentorpossiblylarger. *Notethiswillbeoverriddenbyarchitectureorcallermandated *alignmentifeitherisgreaterthanBYTES_PER_WORD. */ //如果开启了DEBUG,则按需要进行相应的对齐 if(flags&SLAB_STORE_USER) ralign=BYTES_PER_WORD; if(flags&SLAB_RED_ZONE){ ralign=REDZONE_ALIGN; /*Ifredzoning,ensurethatthesecondredzoneissuitably *aligned,byadjustingtheobjectsizeaccordingly.*/ size+=REDZONE_ALIGN-1; size&=~(REDZONE_ALIGN-1); } /*2)archmandatedalignment*/ if(ralign ralign=ARCH_SLAB_MINALIGN; } /*3)callermandatedalignment*/ if(ralign ralign=align; } /*disabledebugifnecessary*/ if(ralign>__alignof__(unsignedlonglong)) flags&=~(SLAB_RED_ZONE|SLAB_STORE_USER); /* *4)Storeit. */ align=ralign;//通过上面一大堆计算,算出了align值 /*Getcache'sdescriptionobj.*/ //按照cache_cache的大小分配一个kmem_cache新实例,实际上cache_cache在内核初始化完成后就是kmem_cache了,为了内核初始化时可使用kmalloc,所以这里要用cache_cache cachep=kmem_cache_zalloc(&cache_cache,GFP_KERNEL);//哈哈,这就是使用cache_cache //这里会分配一块干净的清零过的内存 if(! cachep) gotooops; #ifDEBUG ... #endif /* *Determineiftheslabmanagementis'on'or'off'slab. *(bootstrappingcannotcopewithoffslabcachessodon'tdo *ittooearlyon.) */ //第一个条件通过PAGE_SIZE确定slab管理对象的存储方式,内置还是外置。 //初始化阶段采用内置式(kmem_cache_init()中创建两个普通高速缓存后就把slab_early_init置0了 if((size>=(PAGE_SIZE>>3))&&! slab_early_init) /* *Sizeislarge,assumebesttoplacetheslabmanagementobj *off-slab(shouldallowbetterpackingofobjs). */ flags|=CFLGS_OFF_SLAB; size=ALIGN(size,align);//从这一步可知,slab机制先把对象针对及其字长进行对齐,然后再在此基础上又针对硬件缓冲行进行对齐。 //以后所有的对齐都要照这个总的对齐值对齐 //计算碎片大小,计算slab由几个页面(order)组成,同时计算每个slab中有多少个对象 left_over=calculate_slab_order(cachep,size,align,flags);//这次计算的不是cache_cache了 if(! cachep->num){ printk(KERN_ERR "kmem_cache_create: couldn'tcreatecache%s.\n",name); kmem_cache_free(&cache_cache,cachep); cachep=NULL; gotooops; } //计算slab管理对象的大小,包括structslab对象和kmem_bufctl_t数组 slab_size=ALIGN(cachep->num*sizeof(kmem_bufctl_t) +sizeof(structslab),align); /* *Iftheslabhasbeenplacedoff-slab,andwehaveenoughspacethen *moveiton-slab.Thisisattheexpenseofanyextracolouring. */ //如果是一个外置slab,并且碎片大小大于slab管理对象的大小,则可将slab管理对象移到slab中,改造成一个内置slab! ! ! ! ! if(flags&CFLGS_OFF_SLAB&&left_over>=slab_size){ flags&=~CFLGS_OFF_SLAB; left_over-=slab_size;//slab_size就是slab管理对象大小 } if(flags&CFLGS_OFF_SLAB){ //align是针对slab对象的,如果slab管理者是外置存储,自然也不会像内置那样影响到后面slab对象的存储位置 //slab管理者也就不需要对齐了 /*reallyoffslab.Noneedformanualalignment*/ slab_size= cachep->num*sizeof(kmem_bufctl_t)+sizeof(structslab); } //着色块单位,为L1_CACHE_BYTES,即32字节 cachep->colour_off=cache_line_size(); /*Offsetmustbeamultipleofthealignment.*/ //着色单位必须是对齐单位的整数倍 if(cachep->colour_off cachep->colour_off=align; //计算碎片区域需要多少个着色块 cachep->colour=left_over/cachep->colour_off; //管理对象的大小 cachep->slab_size=slab_size; cachep->flags=flags; cachep->gfpflags=0; if(CONFIG_ZONE_DMA_FLAG&&(flags&SLAB_CACHE_DMA))//与伙伴系统交互的DMA标志 cachep->gfpflags|=GFP_DMA; //slab对象的大小 cachep->buffer_size=size; //倒数 cachep->reciprocal_buffer_size=reciprocal_value(size); //如果是外置slab,这里要分配一个管理对象,保存在slabp_cache中,如果是内置式的slab,此指针为空 //array_cachine,cache_cache,3list这几个肯定是内置式,不会进入这个 if(flags&CFLGS_OFF_SLAB){ cachep->slabp_cache=kmem_find_general_cachep(slab_size,0u); /* *Thisisapossibilityforoneofthemalloc_sizescaches. *Butsincewegooffslabonlyforobjectsizegreaterthan *PAGE_SIZE/8,andmalloc_sizesgetscreatedinascendingorder, *thisshouldnothappenatall. *ButleaveaBUG_ONforsomeluckydude. */ BUG_ON(! cachep->slabp_cache); } //kmem_cach的名字和它管理的对象的构造函数 cachep->ctor=ctor; cachep->name=name; //设置每个CPU上的localcache,配置localcache和slab三链 if(setup_cpu_cache(cachep)){ __kmem_cache_destroy(cachep); cachep=NULL; gotooops; } //将kmem_cache加入到cache_chain为头的kmem_cache链表中 /*cachesetupcompleted,linkitintothelist*/ list_add(&cachep->next,&cache_chain);//还是用了cache_chain oops: if(! cachep&&(flags&SLAB_PANIC)) panic("kmem_cache_create(): failedtocreateslab`%s'\n", name); mutex_unlock(&cache_chain_mutex);//mutex returncachep;//返回该kmem_cache } 在这个函数中,首先要计算一些对齐的值。 一是内存对齐,我们需要数据按照CPU字长进行对齐(比如结构体中间一个char类型数据32位下所占字节可能是4字节),这样才能提高CPU访问数据的效率。 其次如果设置了SLAB_HWCACHE_ALIGN,那么还要和缓存行(cachineline)进行对齐。 和缓存行除此之外,除了需要DEBUG,可能还需要一些对齐,不过这都不是我们关注的重点。 总之,前面一大串就是计算出了slab的对齐值。 然后调用kmem_cache_zalloc()函数为要创建的缓存器申请内存,我们知道,先前我们定义了cache_cache这个缓存器的缓存器,此时就派上用场了,这里就用它来做参数。 /** *kmem_cache_zalloc-Allocateanobject.Thememoryissettozero. *@cache: Thecachetoallocatefrom. *@flags: Seekmalloc(). * *Allocateanobjectfromthiscacheandsettheallocatedmemorytozero. *Theflagsareonlyrelevantifthecachehasno
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- slab 源码 分析 缓存 创建