slab源码分析缓存器的创建.docx

上传人:b****3 文档编号:5479987 上传时间:2023-05-08 格式:DOCX 页数:38 大小:33.97KB
下载 相关 举报
slab源码分析缓存器的创建.docx_第1页
第1页 / 共38页
slab源码分析缓存器的创建.docx_第2页
第2页 / 共38页
slab源码分析缓存器的创建.docx_第3页
第3页 / 共38页
slab源码分析缓存器的创建.docx_第4页
第4页 / 共38页
slab源码分析缓存器的创建.docx_第5页
第5页 / 共38页
slab源码分析缓存器的创建.docx_第6页
第6页 / 共38页
slab源码分析缓存器的创建.docx_第7页
第7页 / 共38页
slab源码分析缓存器的创建.docx_第8页
第8页 / 共38页
slab源码分析缓存器的创建.docx_第9页
第9页 / 共38页
slab源码分析缓存器的创建.docx_第10页
第10页 / 共38页
slab源码分析缓存器的创建.docx_第11页
第11页 / 共38页
slab源码分析缓存器的创建.docx_第12页
第12页 / 共38页
slab源码分析缓存器的创建.docx_第13页
第13页 / 共38页
slab源码分析缓存器的创建.docx_第14页
第14页 / 共38页
slab源码分析缓存器的创建.docx_第15页
第15页 / 共38页
slab源码分析缓存器的创建.docx_第16页
第16页 / 共38页
slab源码分析缓存器的创建.docx_第17页
第17页 / 共38页
slab源码分析缓存器的创建.docx_第18页
第18页 / 共38页
slab源码分析缓存器的创建.docx_第19页
第19页 / 共38页
slab源码分析缓存器的创建.docx_第20页
第20页 / 共38页
亲,该文档总共38页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

slab源码分析缓存器的创建.docx

《slab源码分析缓存器的创建.docx》由会员分享,可在线阅读,更多相关《slab源码分析缓存器的创建.docx(38页珍藏版)》请在冰点文库上搜索。

slab源码分析缓存器的创建.docx

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

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > IT计算机 > 电脑基础知识

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2