mmap()系統(tǒng)調(diào)用是在用戶(hù)進(jìn)程與內(nèi)核之間共享內(nèi)存區(qū)域的常用方法。我們最近有個(gè)程序,需要應(yīng)用進(jìn)程能夠讀取內(nèi)核驅(qū)動(dòng)獲取的數(shù)據(jù),經(jīng)過(guò)簡(jiǎn)單的調(diào)研,決定采用mmap方式。實(shí)現(xiàn)起來(lái)不難,在驅(qū)動(dòng)中注冊(cè)一個(gè)字符設(shè)備,實(shí)現(xiàn)該設(shè)備的mmap()方法即可。但這其中有一點(diǎn)小曲折。
在實(shí)現(xiàn)設(shè)備的mmap()方法時(shí),需要將物理內(nèi)存映射到應(yīng)用程序通過(guò)mmap()系統(tǒng)調(diào)用傳下來(lái)的vma中。vma代表的是進(jìn)程的一段虛擬地址空間。在第一版里,考慮的不全面,利用alloc_pages()將整個(gè)內(nèi)存段申請(qǐng)為一段連續(xù)的物理地址空間。然后通過(guò)remap_pfn_range()函數(shù)將這段連續(xù)的物理內(nèi)存映射到vma中。經(jīng)過(guò)長(zhǎng)時(shí)間的測(cè)試,沒(méi)有發(fā)現(xiàn)問(wèn)題。直到今天,在部署一個(gè)老集群時(shí),遇到了問(wèn)題。這個(gè)集群中有很多老機(jī)器,內(nèi)存只有十多個(gè)G,而且長(zhǎng)時(shí)間運(yùn)行后產(chǎn)生了大量的內(nèi)存碎片。從而導(dǎo)致,我們無(wú)法獲得足夠的連續(xù)物理內(nèi)存。沒(méi)辦法,只好重新調(diào)整驅(qū)動(dòng)中分配內(nèi)存的方式,改用vmalloc獲取地址空間。
在kernel里,通常有3種申請(qǐng)內(nèi)存的方式:vmalloc, kmalloc, alloc_pages。kmalloc與alloc_pages類(lèi)似,均是申請(qǐng)連續(xù)的地址空間。而vmalloc則可以申請(qǐng)一段不連續(xù)的物理地址空間,并將其映射到連續(xù)的線性地址上。每次vmalloc之后,內(nèi)核會(huì)創(chuàng)建一個(gè)vm_struct,用以映射分配到的不連續(xù)的內(nèi)存區(qū)域。vm_struct類(lèi)似vma,但是又不是一回事。vma是將物理內(nèi)存映射到進(jìn)程的虛擬地址空間。而vm_struct是將物理內(nèi)存映射到內(nèi)核的線性地址空間。
既然vmalloc拿到的不是連續(xù)的物理內(nèi)存,那么將這些內(nèi)存映射到vma時(shí),就不能直接利用remap_pfn_range()了。
此時(shí)可以采用兩種方法,一種是實(shí)現(xiàn)vm_operations_struct的fault()方法,用以在缺頁(yè)時(shí)再映射需要的頁(yè)。此方法操作起來(lái)較為麻煩。
另一種方法是直接使用remap_vmalloc_range()函數(shù)。該函數(shù)的原型為:
int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,unsigned long pgoff)
其中參數(shù)vma是mmap使用調(diào)用傳下來(lái)的,addr即為vmalloc()所分配內(nèi)存的起始地址。而pgoff則為mmap()系統(tǒng)調(diào)用里的偏移參數(shù),可以通過(guò)vma->vm_pgoff獲得。該函數(shù)成功執(zhí)行后,返回值為0。如果返回值為負(fù)數(shù),則說(shuō)明出錯(cuò)了。通常是由于所傳的參數(shù)不正確。
需要注意的是,需要映射到用戶(hù)空間的內(nèi)存段,不能直接利用vmalloc()分配,而應(yīng)該使用vmalloc_user()函數(shù)。該函數(shù)除了分配內(nèi)存之外,還會(huì)將相應(yīng)的vm_struct結(jié)構(gòu)標(biāo)記為VM_USERMAP。否則,remap_vmalloc_range將返回錯(cuò)誤。
在這個(gè)項(xiàng)目中碰到的教訓(xùn)是,永遠(yuǎn)不要假設(shè)系統(tǒng)中一定會(huì)有超過(guò)一個(gè)頁(yè)的連續(xù)物理內(nèi)存。
不過(guò)較新的內(nèi)核具有compact機(jī)制,可以整理內(nèi)存碎片。但是,目前至少有一大部分機(jī)器不支持,或未開(kāi)啟此機(jī)制。
-
內(nèi)核
+關(guān)注
關(guān)注
4文章
1427瀏覽量
42220 -
內(nèi)存
+關(guān)注
關(guān)注
8文章
3156瀏覽量
75877 -
malloc
+關(guān)注
關(guān)注
0文章
53瀏覽量
302
原文標(biāo)題:vmalloc與mmap
文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
linux內(nèi)核系統(tǒng)調(diào)用之參數(shù)傳遞
拆解mmap內(nèi)存映射的本質(zhì)!

Linux的mmap文件內(nèi)存映射機(jī)制
字符設(shè)備驅(qū)動(dòng)另一種寫(xiě)法—mmap方法操作LED
Linux用戶(hù)空間與內(nèi)核空間的區(qū)別?
labview 中怎么獲取數(shù)值的指針(地址)?調(diào)用dll時(shí)要往里面?zhèn)?b class='flag-5'>地址
linux drivers中的mmap實(shí)現(xiàn)
Linux的mmap文件內(nèi)存映射機(jī)制
如何主動(dòng)調(diào)用獲取flag

PCI總線地址空間與系統(tǒng)地址空間的關(guān)系
內(nèi)核mmap_sem鎖的危害和相關(guān)優(yōu)化
Linux內(nèi)核之物理內(nèi)存組織結(jié)構(gòu)
Linux應(yīng)用開(kāi)發(fā)之共享內(nèi)存
Linux虛擬地址空間和物理地址空間的關(guān)系

mmap原理詳解

評(píng)論