仓酷云
标题:
给大家带来linux内存办理之非一连物理地点分派(vmalloc)
[打印本页]
作者:
愤怒的大鸟
时间:
2015-1-16 12:01
标题:
给大家带来linux内存办理之非一连物理地点分派(vmalloc)
linux系统的文件布置,etc/,opt/目录的内容等;
后面我们已剖析了linux怎样使用同伴体系,slab分派器分派内存,用这些办法失掉的内存在物理地点上都是一连的,但是,有些时分,每次哀求内存时,体系都分派物理地点一连的内存块是分歧适的,能够使用小块内存“毗连”成年夜块可以使用的内存.这在操纵体系计划中也被称为“内存拼接”,明显,内存拼接在必要较年夜内存,而内存会见比拟之下不是很频仍的情形下是对照无效的.
在linux内核顶用来办理内存拼接的接口是vmalloc/vfree.用vmalloc分派失掉的内存在线性地点是光滑的,可是物理地点上长短一连的.
一:筹办常识:
Linux用vm_struct布局来暗示vmalloc利用的线性地点.vmalloc所利用的线性地点区间为:VMALLOC_STARTVMALLOC_END.借用<<Understanding.the.Linux.Kernel.3rd>>中的一副插图,以下示:
从上图中我们能够看到每个vmalloc_area用4KB离隔,如许做是为了很简单就可以捕获到越界会见,由于两头是一个“朴陋”.
二:相干的数据布局
上面来剖析一下vmallocarea的数据布局:
structvm_struct{
void*addr;//假造地点
unsignedlongsize;//vm的巨细
unsignedlongflags;//vm的标记
structpage**pages;//vm所映照的page
unsignedintnr_pages;//page个数
unsignedlongphys_addr;//对应的肇端物理地点
structvm_struct*next;//下一个vm.用来构成链表
}
全局变量vmlist用来办理vm组成的链表
全局变量vmlist用于会见vmlist所利用的旌旗灯号量
关于vm_struct有两个经常使用的操纵:get_vm_area/remove_vm_area
get_vm_area:用来分派一个符合巨细的vm布局,分派乐成以后,将其链进到vmlist中,代码在mm/vmalloc.c中.以下示:
//size为vm的巨细
structvm_struct*get_vm_area(unsignedlongsize,unsignedlongflags)
{
//在VMALLOC_START与VMALLOC_END找到一段符合的空间
return__get_vm_area(size,flags,VMALLOC_START,VMALLOC_END);
}
//参数申明:
//start:肇端地点end:停止地点size空间巨细
structvm_struct*__get_vm_area(unsignedlongsize,unsignedlongflags,
unsignedlongstart,unsignedlongend)
{
structvm_struct**p,*tmp,*area;
unsignedlongalign=1;
unsignedlongaddr;
//假如指定了VM_IOREMAP.则调剂对齐因子
if(flags&VM_IOREMAP){
intbit=fls(size);
if(bit>IOREMAP_MAX_ORDER)
bit=IOREMAP_MAX_ORDER;
elseif(bit<PAGE_SHIFT)
bit=PAGE_SHIFT;
align=1ul<<bit;
}
//将肇端地点依照对齐因子对齐
addr=ALIGN(start,align);
//分派一个vm_struct布局空间
area=kmalloc(sizeof(*area),GFP_KERNEL);
if(unlikely(!area))
returnNULL;
//PAGE_SIZE:在i32中为4KB,即下面所说的距离朴陋
size+=PAGE_SIZE;
if(unlikely(!size)){
kfree(area);
returnNULL;
}
write_lock(&vmlist_lock);
//遍历vmlist:找到符合巨细的末利用空间
for(p=&vmlist;(tmp=*p)!=NULL;p=&tmp-&
12345下一页
在linux中学习命令的最好办法是学习Shell脚本编程,Shell脚本比起其他语言来学习简单,但是功能却十分强大.通过学习Shell编程,能让你掌握大量的linux命令。
作者:
愤怒的大鸟
时间:
2015-1-16 13:05
标题:
给大家带来linux内存办理之非一连物理地点分派(vmalloc)
有些人号称用过十几种甚至几十种linux,向人谈论起来头头是到,好像懂的很多。
gt;next){</P> //若肇端地点落在某一个vm区间,则调剂肇端地点为vm区间的开端
if((unsignedlong)tmp->addr<addr){
if((unsignedlong)tmp->addr+tmp->size>=addr)
addr=ALIGN(tmp->size+
(unsignedlong)tmp->addr,align);
continue;
}
//size+addr<addr?除非size==0
if((size+addr)<addr)
gotoout;
//两头的清闲能够包容下size巨细的vm.申明已找到了如许的一个vm
if(size+addr<=(unsignedlong)tmp->addr)
gotofound;
//调剂肇端地点为vm的停止地点
addr=ALIGN(tmp->size+(unsignedlong)tmp->addr,align);
//假如超越了局限
if(addr>end-size)
gotoout;
}
found:
//找到了符合巨细的空间,将area->addr赋值为addr,然后链进vmlist中
area->next=*p;
*p=area;
area->flags=flags;
area->addr=(void*)addr;
area->size=size;
area->pages=NULL;
area->nr_pages=0;
area->phys_addr=0;
write_unlock(&vmlist_lock);
returnarea;
out:
//没有找到符合巨细的空间,堕落前往
write_unlock(&vmlist_lock);
kfree(area);
if(printk_ratelimit())
printk(KERN_WARNING"allocationfailed:outofvmallocspace-usevmalloc=<size>toincreasesize.\n");
returnNULL;
}
这段代码不是很庞大,在此不具体剖析了.
remove_vm_area用来将响应的vm从vmlist中止开,使其暗示的空间能够被使用
//addr:对应vm的超始地点
structvm_struct*remove_vm_area(void*addr)
{
structvm_struct**p,*tmp;
write_lock(&vmlist_lock);
//遍历vmlist.找到超始地点为addr的vm
for(p=&vmlist;(tmp=*p)!=NULL;p=&tmp->next){
if(tmp->addr==addr)
gotofound;
}
write_unlock(&vmlist_lock);
returnNULL;
found:
//断开tmp所对应的映照干系
unmap_vm_area(tmp);
//找到了这个vm,将其从vmlist上断开
*p=tmp->next;
write_unlock(&vmlist_lock);
returntmp;
}
unmap_vm_area用来断开vm地点线性地点所对应的映照干系.它的代码以下:
voidunmap_vm_area(structvm_struct*area)
{
//vm所对应的肇端线性地点
unsignedlongaddress=(unsignedlong)area->addr;
//vm所对应的停止线性地点
unsignedlongend=(address+area->size);
pgd_t*dir;
//肇端地点地点的内核页目次项
dir=pgd_offset_k(address);
flush_cache_vunmap(address,end);
do{
//断开地点所对应的pmd映照
unmap_area_pmd(dir,address,end-address);
//运转到这里的时分,已断开了一个页目次所暗示的线性地点,而每一个页目次暗示的线性地点//巨细为PGDIR_SIZE
address=(address+PGDIR_SIZE)&PGDIR_MASK;
dir++;
}while(address&&(address<end));
//当抵达开端时停止轮回
flush_tlb_kernel_range((unsignedlong)area->addr,end);
}
//断开线性地点区间地点的pmd的映照
st
上一页12345下一页
使用gcc或g++进行编译,使用gdb进行调试;
作者:
愤怒的大鸟
时间:
2015-1-16 13:10
标题:
给大家带来linux内存办理之非一连物理地点分派(vmalloc)
vim除非你打算真正的学好linux,或者说打算长久时间学习他,而且肯花大量时间vim,否则,最好别碰
aticvoidunmap_area_pmd(pgd_t*dir,unsignedlongaddress,</P> unsignedlongsize)
{
unsignedlongend;
pmd_t*pmd;
if(pgd_none(*dir))
return;
if(pgd_bad(*dir)){
pgd_ERROR(*dir);
pgd_clear(dir);
return;
}
pmd=pmd_offset(dir,address);
address&=~PGDIR_MASK;
end=address+size;
if(end>PGDIR_SIZE)
end=PGDIR_SIZE;
do{
//断开线性地点地点的pte的映照干系
unmap_area_pte(pmd,address,end-address);
address=(address+PMD_SIZE)&PMD_MASK;
pmd++;
}while(address<end);
}
staticvoidunmap_area_pte(pmd_t*pmd,unsignedlongaddress,
unsignedlongsize)
{
unsignedlongend;
pte_t*pte;
if(pmd_none(*pmd))
return;
if(pmd_bad(*pmd)){
pmd_ERROR(*pmd);
pmd_clear(pmd);
return;
}
pte=pte_offset_kernel(pmd,address);
address&=~PMD_MASK;
end=address+size;
if(end>PMD_SIZE)
end=PMD_SIZE;
do{
pte_tpage;
//扫除pte的对应映照干系
page=ptep_get_and_clear(pte);
address+=PAGE_SIZE;
pte++;
if(pte_none(page))
continue;
if(pte_present(page))
continue;
printk(KERN_CRIT"Whee..Swappedoutpageinkernelpagetable\n");
}while(address<end);
}
经由这几个历程以后,实践上,它只是找到线性地点所对应的pte,然后断开pte的映照.值得注重的是:为了效力起见,这里只是断开了pte的映照,即只是将pte置为none,暗示pte末映照内存.并末断开pmd和pgd的映照
三:vmalloc的完成:
void*vmalloc(unsignedlongsize)
{
return__vmalloc(size,GFP_KERNEL|__GFP_HIGHMEM,PAGE_KERNEL);
}
实践上挪用__vmalloc:
void*__vmalloc(unsignedlongsize,intgfp_mask,pgprot_tprot)
{
structvm_struct*area;
structpage**pages;
unsignedintnr_pages,array_size,i;
//使哀求的巨细与页框对齐
size=PAGE_ALIGN(size);
//无效性反省
if(!size||(size>>PAGE_SHIFT)>num_physpages)
returnNULL;
//获得一个无效的VM,这个函数我们在后面已具体的剖析过了
area=get_vm_area(size,VM_ALLOC);
if(!area)
returnNULL;
//所要映照的页面总数
nr_pages=size>>PAGE_SHIFT;
//页面形貌符所占的空间
array_size=(nr_pages*sizeof(structpage*));
area->nr_pages=nr_pages;
area->pages=pages=kmalloc(array_size,(gfp_mask&~__GFP_HIGHMEM));
//假如空间分派失利
if(!area->pages){
remove_vm_area(area->addr);
kfree(area);
returnNULL;
}
memset(area->pages,0,array_size);
//为每个页面分派空间
for(i=0;i<area->nr_pages;i++){
area->pages
=al
上一页12345下一页
写学习日记,这是学习历程的见证,同时我坚持认为是增强学习信念的法宝。以上是我学习Linux的心得体会,希望对大家的学习有所帮助,由于水平有限,本文难免有所欠缺,望请指正。
作者:
愤怒的大鸟
时间:
2015-1-16 13:11
标题:
给大家带来linux内存办理之非一连物理地点分派(vmalloc)
系统管理相关命令:df、top、free、quota、at、lp、adduser、groupaddkill、crontab、tar、unzip、gunzip、last
loc_page(gfp_mask);</P> if(unlikely(!area->pages
)){
/*Successfullyallocatedipages,freethemin__vunmap()*/
area->nr_pages=i;
gotofail;
}
}
//为所分派的页面创建映照干系
if(map_vm_area(area,prot,&pages))
gotofail;
returnarea->addr;
fail:
vfree(area->addr);
returnNULL;
}
map_vm_area为所分派的内存创建映照干系,它的程序流程与unmap_vm_area差未几,都是从pgd找到pte,假如一样的映照干系不存在,则新建之.(如:pgd对应的pmd不存在,则新建pmd项,使pgd指向建好的pmd.同理,假如pmd所映照的pte项不存在,则新建pte,然后创建映照),然后将pte映照到响应的页表.代码以下:
intmap_vm_area(structvm_struct*area,pgprot_tprot,structpage***pages)
{
unsignedlongaddress=(unsignedlong)area->addr;
unsignedlongend=address+(area->size-PAGE_SIZE);
pgd_t*dir;
interr=0;
//vm肇端地点地点的页目次
dir=pgd_offset_k(address);
spin_lock(&init_mm.page_table_lock);
do{
pmd_t*pmd=pmd_alloc(&init_mm,dir,address);
if(!pmd){
err=-ENOMEM;
break;
}
//轮到pmd了^_^
if(map_area_pmd(pmd,address,end-address,prot,pages)){
err=-ENOMEM;
break;
}
address=(address+PGDIR_SIZE)&PGDIR_MASK;
dir++;
}while(address&&(address<end));
spin_unlock(&init_mm.page_table_lock);
flush_cache_vmap((unsignedlong)area->addr,end);
returnerr;
}
staticintmap_area_pmd(pmd_t*pmd,unsignedlongaddress,
unsignedlongsize,pgprot_tprot,
structpage***pages)
{
unsignedlongbase,end;
base=address&PGDIR_MASK;
address&=~PGDIR_MASK;
end=address+size;
if(end>PGDIR_SIZE)
end=PGDIR_SIZE;
do{
pte_t*pte=pte_alloc_kernel(&init_mm,pmd,base+address);
if(!pte)
return-ENOMEM;
//轮到pte了^_^
if(map_area_pte(pte,address,end-address,prot,pages))
return-ENOMEM;
address=(address+PMD_SIZE)&PMD_MASK;
pmd++;
}while(address<end);
return0;
}
//为页表页创建映照干系
staticintmap_area_pte(pte_t*pte,unsignedlongaddress,
unsignedlongsize,pgprot_tprot,
structpage***pages)
{
unsignedlongend;
address&=~PMD_MASK;
end=address+size;
if(end>PMD_SIZE)
end=PMD_SIZE;
do{
structpage*page=**pages;
WARN_ON(!pte_none(*pte));
if(!page)
return-ENOMEM;
//详细的映照在这里了^_^
set_pte(pte,mk_pte(page,prot));
address+=PAGE_SIZE;
pte++;
(*pages)++;
}while(add
上一页12345下一页
看不懂man文档的人.在linux中,命令可分为系统基本命令和应用程序命令.系统基本命令是所有的unix类系统都支持的命令,走到哪都不变,只要是unix类系统上就肯定有.
作者:
愤怒的大鸟
时间:
2015-1-16 13:30
标题:
给大家带来linux内存办理之非一连物理地点分派(vmalloc)
不同版本的Linux命令数量不一样,这里笔者把它们中比较重要的和使用频率最多的命令。
ress<end);</P> return0;
}
只需了解了断开映照的历程,这段代码是很好了解的.
总而言之:linux在创建映照的时分,从pgd到pte响应的创建映照干系,最初将pte映照到分派失掉的物理内存.而在断开映照的时分,linux内核从pgd找到pte,然后将pte置为none,暗示pte末创建映照干系.
四:vfree的完成:
代码以下:
voidvfree(void*addr)
{
BUG_ON(in_interrupt());
__vunmap(addr,1);
}
跟踪至__vunmap:
void__vunmap(void*addr,intdeallocate_pages)
{
structvm_struct*area;
//参数无效性反省
if(!addr)
return;
//判别addr是不是是按页框对齐的
if((PAGE_SIZE-1)&(unsignedlong)addr){
printk(KERN_ERR"Tryingtovfree()badaddress(%p)\n",addr);
WARN_ON(1);
return;
}
//remove_vm_area:这个函数我们在之前已剖析过了^_^
area=remove_vm_area(addr);
if(unlikely(!area)){
//没有找到肇端地点为addr的vm.则有效,加入
printk(KERN_ERR"Tryingtovfree()nonexistentvmarea(%p)\n",
addr);
WARN_ON(1);
return;
}
if(deallocate_pages){
inti;
for(i=0;i<area->nr_pages;i++){
if(unlikely(!area->pages
))
BUG();
//开释哀求取得的页面
__free_page(area->pages
);
}
//开释分派的page形貌符
kfree(area->pages);
}
//开释内核的vm形貌符
kfree(area);
return;
}
五:总结
经由下面的剖析,我们能够看到,vmalloc分派内存的历程是非常低效的,不但要从同伴体系中取内存并且要创建映照干系,明显,用vmalloc分派较小的内存是分歧算的。别的。有个成绩值得思索一下:为何用__get_free_page不必要创建映照干系,而vmalloc就必要呢?
实在,不论利用何种体例。线性地点到物理地点的转换终极都要经由硬件的页式办理往完成。所分歧的是__get_free_page前往的线性地点是属于(PAGE_OFFSET,HIGH_MEMORY)之间的,这段线性地点在内核初始化的时分就完成了映照。而vmalloc利用的线性地点是属于(VMALLOC_STARTVMALLOC_END)之间的,也就是说属于一个一时映照区,以是必需为其创建映照干系
</p>
上一页12345
如果你学不好的话,你在linux中开发的机会就很少,或者说几乎没有,它的优势就消失了,然后随着时间的流逝,你就会全部忘记她;
作者:
飘飘悠悠
时间:
2015-1-18 16:51
发问的时候一定要注意到某些礼节。因为Linux社区是一个松散的组织、也不承担回复每个帖子的义务。它不是技术支持。
作者:
第二个灵魂
时间:
2015-1-27 13:15
如果你想深入学习Linux,看不懂因为文档实在是太难了。写的最好的、最全面的文档都是英语写的,最先发布的技术信息也都是用英语写的。
作者:
海妖
时间:
2015-2-5 13:51
通过自学老师给的资料和向同学请教,掌握了一些基本的操作,比如挂载优盘,编译程序,在Linux环境下运行,转换目录等等。学了这些基础才能进行下面的模拟OS程序。?
作者:
山那边是海
时间:
2015-2-12 02:57
Linux是参照Unix思想设计的,理解掌握Linux必须按照Unix思维来进行。思想性的转变比暂时性的技术提高更有用,因为他能帮助你加快学习速度。
作者:
小女巫
时间:
2015-3-2 22:25
熟悉系统的基本操作,Linux的图形界面直观,操作简便,多加上机练习就可熟悉操作,在Linux下学习办公软件等常用软件。
作者:
活着的死人
时间:
2015-3-11 08:36
如果上面的措施没有解决问题,此时你就需要Linux社区的帮助了。 Linux的使用者一般都是专业人士,他们有着很好的电脑背景且愿意协助他人。
作者:
兰色精灵
时间:
2015-3-18 07:38
我学习Linux的心得体会 ,希望对大家的学习有所帮助,由于水平有限,本文难免有所欠缺,望请指正。
作者:
只想知道
时间:
2015-3-25 19:16
linux鸟哥的私房菜,第三版,基础篇,网上有pdf下的,看它的目录和每章的介绍就行了,这个绝对原创!
欢迎光临 仓酷云 (http://ckuyun.com/)
Powered by Discuz! X3.2