五月天青色头像情侣网名,国产亚洲av片在线观看18女人,黑人巨茎大战俄罗斯美女,扒下她的小内裤打屁股

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

深度分析Linux內(nèi)存映射——mmap(從這四點(diǎn)入手~)

2022-06-14 20:14 作者:補(bǔ)給站Linux內(nèi)核  | 我要投稿

一 mmap系統(tǒng)調(diào)用

1.內(nèi)存映射

  • 所謂的內(nèi)存映射就是把物理內(nèi)存映射到進(jìn)程的地址空間之內(nèi),這些應(yīng)用程序就可以直接使用輸入輸出的地址空間,從而提高讀寫的效率。Linux提供了mmap()函數(shù),用來(lái)映射物理內(nèi)存。在驅(qū)動(dòng)程序中,應(yīng)用程序以設(shè)備文件為對(duì)象,調(diào)用mmap()函數(shù),內(nèi)核進(jìn)行內(nèi)存映射的準(zhǔn)備工作,生成vm_area_struct結(jié)構(gòu)體,然后調(diào)用設(shè)備驅(qū)動(dòng)程序中定義的mmap函數(shù)。

2.mmap系統(tǒng)調(diào)用

  • mmap將一個(gè)文件或者其它對(duì)象映射進(jìn)內(nèi)存。文件被映射到多個(gè)頁(yè)上,如果文件的大小不是所有頁(yè)的大小之和,最后一個(gè)頁(yè)不被使用的空間將會(huì)清零。munmap執(zhí)行相反的操作,刪除特定地址區(qū)域的對(duì)象映射。

  • 當(dāng)使用mmap映射文件到進(jìn)程后,就可以直接操作這段虛擬地址進(jìn)行文件的讀寫等操作,不必再調(diào)用read,write等系統(tǒng)調(diào)用.但需注意,直接對(duì)該段內(nèi)存寫時(shí)不會(huì)寫入超過(guò)當(dāng)前文件大小的內(nèi)容.

  • 采用共享內(nèi)存通信的一個(gè)顯而易見的好處是效率高,因?yàn)檫M(jìn)程可以直接讀寫內(nèi)存,而不需要任何數(shù)據(jù)的拷貝。對(duì)于像管道和消息隊(duì)列等通信方式,則需要在內(nèi)核和用戶空間進(jìn)行四次的數(shù)據(jù)拷貝,而共享內(nèi)存則只拷貝兩次數(shù)據(jù):一次從輸入文件到共享內(nèi)存區(qū),另一次從共享內(nèi)存區(qū)到輸出文件。實(shí)際上,進(jìn)程之間在共享內(nèi)存時(shí),并不總是讀寫少量數(shù)據(jù)后就解除映射,有新的通信時(shí),再重新建立共享內(nèi)存區(qū)域。而是保持共享區(qū)域,直到通信完畢為止,這樣,數(shù)據(jù)內(nèi)容一直保存在共享內(nèi)存中,并沒(méi)有寫回文件。共享內(nèi)存中的內(nèi)容往往是在解除映射時(shí)才寫回文件的。因此,采用共享內(nèi)存的通信方式效率是非常高的。 ?

  • 基于文件的映射,在mmap和munmap執(zhí)行過(guò)程的任何時(shí)刻,被映射文件的st_atime可能被更新。如果st_atime字段在前述的情況下沒(méi)有得到更新,首次對(duì)映射區(qū)的第一個(gè)頁(yè)索引時(shí)會(huì)更新該字段的值。用PROT_WRITE 和 MAP_SHARED標(biāo)志建立起來(lái)的文件映射,其st_ctime 和 st_mtime在對(duì)映射區(qū)寫入之后,但在msync()通過(guò)MS_SYNC 和 MS_ASYNC兩個(gè)標(biāo)志調(diào)用之前會(huì)被更新。

用法:

#include <sys/mman.h> void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); int munmap(void *start, size_t length);

返回說(shuō)明:

成功執(zhí)行時(shí),mmap()返回被映射區(qū)的指針,munmap()返回0。失敗時(shí),mmap()返回MAP_FAILED[其值為(void *)-1],munmap返回-1。errno被設(shè)為以下的某個(gè)值 EACCES:訪問(wèn)出錯(cuò) EAGAIN:文件已被鎖定,或者太多的內(nèi)存已被鎖定 EBADF:fd不是有效的文件描述詞 EINVAL:一個(gè)或者多個(gè)參數(shù)無(wú)效 ENFILE:已達(dá)到系統(tǒng)對(duì)打開文件的限制 ENODEV:指定文件所在的文件系統(tǒng)不支持內(nèi)存映射 ENOMEM:內(nèi)存不足,或者進(jìn)程已超出最大內(nèi)存映射數(shù)量 EPERM:權(quán)能不足,操作不允許 ETXTBSY:已寫的方式打開文件,同時(shí)指定MAP_DENYWRITE標(biāo)志 SIGSEGV:試著向只讀區(qū)寫入 SIGBUS:試著訪問(wèn)不屬于進(jìn)程的內(nèi)存區(qū)


【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個(gè)人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦!?。。ê曨l教程、電子書、實(shí)戰(zhàn)項(xiàng)目及代碼)? ? ? ?


參數(shù):

start:映射區(qū)的開始地址。 length:映射區(qū)的長(zhǎng)度。 prot:期望的內(nèi)存保護(hù)標(biāo)志,不能與文件的打開模式?jīng)_突。是以下的某個(gè)值,可以通過(guò)or運(yùn)算合理地組合在一起 PROT_EXEC //頁(yè)內(nèi)容可以被執(zhí)行 PROT_READ //頁(yè)內(nèi)容可以被讀取 PROT_WRITE //頁(yè)可以被寫入 PROT_NONE //頁(yè)不可訪問(wèn) flags:指定映射對(duì)象的類型,映射選項(xiàng)和映射頁(yè)是否可以共享。它的值可以是一個(gè)或者多個(gè)以下位的組合體 MAP_FIXED //使用指定的映射起始地址,如果由start和len參數(shù)指定的內(nèi)存區(qū)重疊于現(xiàn)存的映射空間,重疊部分將會(huì)被丟棄。如果指定的起始地址不可用,操作將會(huì)失敗。并且起始地址必須落在頁(yè)的邊界上。 MAP_SHARED //與其它所有映射這個(gè)對(duì)象的進(jìn)程共享映射空間。對(duì)共享區(qū)的寫入,相當(dāng)于輸出到文件。直到msync()或者munmap()被調(diào)用,文件實(shí)際上不會(huì)被更新。 MAP_PRIVATE //建立一個(gè)寫入時(shí)拷貝的私有映射。內(nèi)存區(qū)域的寫入不會(huì)影響到原文件。這個(gè)標(biāo)志和以上標(biāo)志是互斥的,只能使用其中一個(gè)。 MAP_DENYWRITE //這個(gè)標(biāo)志被忽略。 MAP_EXECUTABLE //同上 MAP_NORESERVE //不要為這個(gè)映射保留交換空間。當(dāng)交換空間被保留,對(duì)映射區(qū)修改的可能會(huì)得到保證。當(dāng)交換空間不被保留,同時(shí)內(nèi)存不足,對(duì)映射區(qū)的修改會(huì)引起段違例信號(hào)。 MAP_LOCKED //鎖定映射區(qū)的頁(yè)面,從而防止頁(yè)面被交換出內(nèi)存。 MAP_GROWSDOWN //用于堆棧,告訴內(nèi)核VM系統(tǒng),映射區(qū)可以向下擴(kuò)展。 MAP_ANONYMOUS //匿名映射,映射區(qū)不與任何文件關(guān)聯(lián)。 MAP_ANON //MAP_ANONYMOUS的別稱,不再被使用。 MAP_FILE //兼容標(biāo)志,被忽略。 MAP_32BIT //將映射區(qū)放在進(jìn)程地址空間的低2GB,MAP_FIXED指定時(shí)會(huì)被忽略。當(dāng)前這個(gè)標(biāo)志只在x86-64平臺(tái)上得到支持。 MAP_POPULATE //為文件映射通過(guò)預(yù)讀的方式準(zhǔn)備好頁(yè)表。隨后對(duì)映射區(qū)的訪問(wèn)不會(huì)被頁(yè)違例阻塞。 MAP_NONBLOCK //僅和MAP_POPULATE一起使用時(shí)才有意義。不執(zhí)行預(yù)讀,只為已存在于內(nèi)存中的頁(yè)面建立頁(yè)表入口。 fd:有效的文件描述詞。如果MAP_ANONYMOUS被設(shè)定,為了兼容問(wèn)題,其值應(yīng)為-1。 offset:被映射對(duì)象內(nèi)容的起點(diǎn)。

3.munmap系統(tǒng)調(diào)用

  • 該調(diào)用在進(jìn)程地址空間中解除一個(gè)映射關(guān)系,addr是調(diào)用mmap()時(shí)返回的地址,len是映射區(qū)的大小。當(dāng)映射關(guān)系解除后,對(duì)原來(lái)映射地址的訪問(wèn)將導(dǎo)致段錯(cuò)誤發(fā)生。

4.msync系統(tǒng)調(diào)用

一般說(shuō)來(lái),進(jìn)程在映射空間的對(duì)共享內(nèi)容的改變并不直接寫回到磁盤文件中,往往在調(diào)用munmap()后才執(zhí)行該操作??梢酝ㄟ^(guò)調(diào)用msync()實(shí)現(xiàn)磁盤上文件內(nèi)容與共享內(nèi)存區(qū)的內(nèi)容一致。

二 系統(tǒng)調(diào)用mmap()用于共享內(nèi)存的兩種方式

1.使用普通文件提供的內(nèi)存映射:適用于任何進(jìn)程之間;此時(shí),需要打開或創(chuàng)建一個(gè)文件,然后再調(diào)用mmap();典型調(diào)用代碼如下:

三 mmap進(jìn)行內(nèi)存映射的原理

  • mmap系統(tǒng)調(diào)用的最終目的是將,設(shè)備或文件映射到用戶進(jìn)程的虛擬地址空間,實(shí)現(xiàn)用戶進(jìn)程對(duì)文件的直接讀寫,這個(gè)任務(wù)可以分為以下三步:

1.在用戶虛擬地址空間中尋找空閑的滿足要求的一段連續(xù)的虛擬地址空間,為映射做準(zhǔn)備(由內(nèi)核mmap系統(tǒng)調(diào)用完成)

  • 每個(gè)進(jìn)程擁有3G字節(jié)的用戶虛存空間。但是,這并不意味著用戶進(jìn)程在這3G的范圍內(nèi)可以任意使用,因?yàn)樘摯婵臻g最終得映射到某個(gè)物理存儲(chǔ)空間(內(nèi)存或磁盤空間),才真正可以使用。

  • 那么,內(nèi)核怎樣管理每個(gè)進(jìn)程3G的虛存空間呢?概括地說(shuō),用戶進(jìn)程經(jīng)過(guò)編譯、鏈接后形成的映象文件有一個(gè)代碼段和數(shù)據(jù)段(包括data段和bss段),其中代碼段在下,數(shù)據(jù)段在上。數(shù)據(jù)段中包括了所有靜態(tài)分配的數(shù)據(jù)空間,即全局變量和所有申明為static的局部變量,這些空間是進(jìn)程所必需的基本要求,這些空間是在建立一個(gè)進(jìn)程的運(yùn)行映像時(shí)就分配好的。除此之外,堆棧使用的空間也屬于基本要求,所以也是在建立進(jìn)程時(shí)就分配好的,

  • 在內(nèi)核中,這樣每個(gè)區(qū)域用一個(gè)結(jié)構(gòu)struct vm_area_struct 來(lái)表示.它描述的是一段連續(xù)的、具有相同訪問(wèn)屬性的虛存空間,該虛存空間的大小為物理內(nèi)存頁(yè)面的整數(shù)倍。可以使用 cat /proc/<pid>/maps來(lái)查看一個(gè)進(jìn)程的內(nèi)存使用情況,pid是進(jìn)程號(hào).其中顯示的每一行對(duì)應(yīng)進(jìn)程的一個(gè)vm_area_struct結(jié)構(gòu).

  • 下面是struct vm_area_struct結(jié)構(gòu)體的定義:

  • 通常,進(jìn)程所使用到的虛存空間不連續(xù),且各部分虛存空間的訪問(wèn)屬性也可能不同。所以一個(gè)進(jìn)程的虛存空間需要多個(gè)vm_area_struct結(jié)構(gòu)來(lái)描述。在vm_area_struct結(jié)構(gòu)的數(shù)目較少的時(shí)候,各個(gè)vm_area_struct按照升序排序,以單鏈表的形式組織數(shù)據(jù)(通過(guò)vm_next指針指向下一個(gè)vm_area_struct結(jié)構(gòu))。但是當(dāng)vm_area_struct結(jié)構(gòu)的數(shù)據(jù)較多的時(shí)候,仍然采用鏈表組織的化,勢(shì)必會(huì)影響到它的搜索速度。針對(duì)這個(gè)問(wèn)題,vm_area_struct還添加了vm_avl_hight(樹高)、vm_avl_left(左子節(jié)點(diǎn))、vm_avl_right(右子節(jié)點(diǎn))三個(gè)成員來(lái)實(shí)現(xiàn)AVL樹,以提高vm_area_struct的搜索速度。

  • 假如該vm_area_struct描述的是一個(gè)文件映射的虛存空間,成員vm_file便指向被映射的文件的file結(jié)構(gòu),vm_pgoff是該虛存空間起始地址在vm_file文件里面的文件偏移,單位為物理頁(yè)面。

  • 因此,mmap系統(tǒng)調(diào)用所完成的工作就是準(zhǔn)備這樣一段虛存空間,并建立vm_area_struct結(jié)構(gòu)體,將其傳給具體的設(shè)備驅(qū)動(dòng)程序

2.建立虛擬地址空間和文件或設(shè)備的物理地址之間的映射(設(shè)備驅(qū)動(dòng)完成)

  • 建立文件映射的第二步就是建立虛擬地址和具體的物理地址之間的映射,這是通過(guò)修改進(jìn)程頁(yè)表來(lái)實(shí)現(xiàn)的.mmap方法是file_opeartions結(jié)構(gòu)的成員:

  • linux有2個(gè)方法建立頁(yè)表:

(1) 使用remap_pfn_range一次建立所有頁(yè)表.

返回值:

  • 成功返回 0, 失敗返回一個(gè)負(fù)的錯(cuò)誤值

參數(shù)說(shuō)明:

  • vma 用戶進(jìn)程創(chuàng)建一個(gè)vma區(qū)域

  • virt_addr 重新映射應(yīng)當(dāng)開始的用戶虛擬地址. 這個(gè)函數(shù)建立頁(yè)表為這個(gè)虛擬地址范圍從 virt_addr 到 virt_addr_size.

  • pfn 頁(yè)幀號(hào), 對(duì)應(yīng)虛擬地址應(yīng)當(dāng)被映射的物理地址. 這個(gè)頁(yè)幀號(hào)簡(jiǎn)單地是物理地址右移 PAGE_SHIFT 位. 對(duì)大部分使用, VMA 結(jié)構(gòu)的 vm_paoff 成員正好包含你需要的值. 這個(gè)函數(shù)影響物理地址從 (pfn<<PAGE_SHIFT) 到 (pfn<<PAGE_SHIFT)+size.

  • size 正在被重新映射的區(qū)的大小, 以字節(jié).

  • prot 給新 VMA 要求的"protection". 驅(qū)動(dòng)可(并且應(yīng)當(dāng))使用在vma->vm_page_prot 中找到的值.

(2) 使用nopage VMA方法每次建立一個(gè)頁(yè)表項(xiàng).

返回值:

  • 成功則返回一個(gè)有效映射頁(yè),失敗返回NULL.

參數(shù)說(shuō)明:

  • address 代表從用戶空間傳過(guò)來(lái)的用戶空間虛擬地址.

  • 返回一個(gè)有效映射頁(yè).

(3) 使用方面的限制:

  • remap_pfn_range不能映射常規(guī)內(nèi)存,只存取保留頁(yè)和在物理內(nèi)存頂之上的物理地址。因?yàn)楸A繇?yè)和在物理內(nèi)存頂之上的物理地址內(nèi)存管理系統(tǒng)的各個(gè)子模塊管理不到。640 KB 和 1MB 是保留頁(yè)可能映射,設(shè)備I/O內(nèi)存也可以映射。如果想把kmalloc()申請(qǐng)的內(nèi)存映射到用戶空間,則可以通過(guò)mem_map_reserve()把相應(yīng)的內(nèi)存設(shè)置為保留后就可以。

(4) remap_pfn_range與nopage的區(qū)別

  • remap_pfn_range一次性建立頁(yè)表,而nopage通過(guò)缺頁(yè)中斷找到內(nèi)核虛擬地址,然后通過(guò)內(nèi)核虛擬地址找到對(duì)應(yīng)的物理頁(yè)

  • remap_pfn_range函數(shù)只對(duì)保留頁(yè)和物理內(nèi)存之外的物理地址映射,而對(duì)常規(guī)RAM,remap_pfn_range函數(shù)不能映射,而nopage函數(shù)可以映射常規(guī)的RAM。

3 當(dāng)實(shí)際訪問(wèn)新映射的頁(yè)面時(shí)的操作(由缺頁(yè)中斷完成)


  1. page cache及swap cache中頁(yè)面的區(qū)分:一個(gè)被訪問(wèn)文件的物理頁(yè)面都駐留在page cache或swap cache中,一個(gè)頁(yè)面的所有信息由struct page來(lái)描述。struct page中有一個(gè)域?yàn)橹羔榤apping ,它指向一個(gè)struct address_space類型結(jié)構(gòu)。page cache或swap cache中的所有頁(yè)面就是根據(jù)address_space結(jié)構(gòu)以及一個(gè)偏移量來(lái)區(qū)分的。

  2. 文件與 address_space結(jié)構(gòu)的對(duì)應(yīng):一個(gè)具體的文件在打開后,內(nèi)核會(huì)在內(nèi)存中為之建立一個(gè)struct inode結(jié)構(gòu),其中的i_mapping域指向一個(gè)address_space結(jié)構(gòu)。這樣,一個(gè)文件就對(duì)應(yīng)一個(gè)address_space結(jié)構(gòu),一個(gè) address_space與一個(gè)偏移量能夠確定一個(gè)page cache 或swap cache中的一個(gè)頁(yè)面。因此,當(dāng)要尋址某個(gè)數(shù)據(jù)時(shí),很容易根據(jù)給定的文件及數(shù)據(jù)在文件內(nèi)的偏移量而找到相應(yīng)的頁(yè)面。

  3. 進(jìn)程調(diào)用mmap()時(shí),只是在進(jìn)程空間內(nèi)新增了一塊相應(yīng)大小的緩沖區(qū),并設(shè)置了相應(yīng)的訪問(wèn)標(biāo)識(shí),但并沒(méi)有建立進(jìn)程空間到物理頁(yè)面的映射。因此,第一次訪問(wèn)該空間時(shí),會(huì)引發(fā)一個(gè)缺頁(yè)異常。

  4. 對(duì)于共享內(nèi)存映射情況,缺頁(yè)異常處理程序首先在swap cache中尋找目標(biāo)頁(yè)(符合address_space以及偏移量的物理頁(yè)),如果找到,則直接返回地址;如果沒(méi)有找到,則判斷該頁(yè)是否在交換區(qū) (swap area),如果在,則執(zhí)行一個(gè)換入操作;如果上述兩種情況都不滿足,處理程序?qū)⒎峙湫碌奈锢眄?yè)面,并把它插入到page cache中。進(jìn)程最終將更新進(jìn)程頁(yè)表。

  5. 所有進(jìn)程在映射同一個(gè)共享內(nèi)存區(qū)域時(shí),情況都一樣,在建立線性地址與物理地址之間的映射之后,不論進(jìn)程各自的返回地址如何,實(shí)際訪問(wèn)的必然是同一個(gè)共享內(nèi)存區(qū)域?qū)?yīng)的物理頁(yè)面。

  • 注:對(duì)于映射普通文件情況(非共享映射),缺頁(yè)異常處理程序首先會(huì)在page cache中根據(jù)address_space以及數(shù)據(jù)偏移量尋找相應(yīng)的頁(yè)面。如果沒(méi)有找到,則說(shuō)明文件數(shù)據(jù)還沒(méi)有讀入內(nèi)存,處理程序會(huì)從磁盤讀入相應(yīng)的頁(yè)面,并返回相應(yīng)地址,同時(shí),進(jìn)程頁(yè)表也會(huì)更新.


四 總結(jié)

  1. 對(duì)于mmap的內(nèi)存映射,是將物理內(nèi)存映射到進(jìn)程的虛擬地址空間中去,那么進(jìn)程對(duì)文件的訪問(wèn)就相當(dāng)于直接對(duì)內(nèi)存的訪問(wèn),從而加快了讀寫操作的效率。在這里,remap_pfn_range函數(shù)是一次性的建立頁(yè)表,而nopage函數(shù)是根據(jù)page fault產(chǎn)生的進(jìn)程虛擬地址去找到內(nèi)核相對(duì)應(yīng)的邏輯地址,再通過(guò)這個(gè)邏輯地址去找到page。完成映射過(guò)程。remap_pfn_range不能對(duì)常規(guī)內(nèi)存映射,只能對(duì)保留的內(nèi)存與物理內(nèi)存之外的進(jìn)行映射。

  2. 在這里,要分清幾個(gè)地址,一個(gè)是物理地址,這個(gè)很簡(jiǎn)單,就是物理內(nèi)存的實(shí)際地址。第二個(gè)是內(nèi)核虛擬地址,即內(nèi)核可以直接訪問(wèn)的地址,如kmalloc,vmalloc等內(nèi)核函數(shù)返回的地址,kmalloc返回的地址也稱為內(nèi)核邏輯地址。內(nèi)核虛擬地址與實(shí)際的物理地址只有一個(gè)偏移量。第三個(gè)是進(jìn)程虛擬地址,這個(gè)地址處于用戶空間。而對(duì)于mmap函數(shù)映射的是物理地址到進(jìn)程虛擬地址,而不是把物理地址映射到內(nèi)核虛擬地址。而ioremap函數(shù)是將物理地址映射為內(nèi)核虛擬地址。

  3. 用戶空間的進(jìn)程調(diào)用mmap函數(shù),首先進(jìn)行必要的處理,生成vma結(jié)構(gòu)體,然后調(diào)用remap_pfn_range函數(shù)建立頁(yè)表。而用戶空間的mmap函數(shù)返回的是映射到進(jìn)程地址空間的首地址。所以mmap函數(shù)與remap_pfn_range函數(shù)是不同的,前者只是生成mmap,而建立頁(yè)表通過(guò)remap_pfn_range函數(shù)來(lái)完成。



深度分析Linux內(nèi)存映射——mmap(從這四點(diǎn)入手~)的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
射阳县| 怀来县| 台江县| 拉孜县| 驻马店市| 红桥区| 额敏县| 乾安县| 凤凰县| 连州市| 桦川县| 宣威市| 南靖县| 本溪| 林周县| 阿鲁科尔沁旗| 姜堰市| 秭归县| 资兴市| 东莞市| 楚雄市| 凤台县| 海阳市| 碌曲县| 河西区| 遵化市| 观塘区| 富平县| 兴化市| 东海县| 饶平县| 偃师市| 嘉黎县| 曲周县| 延庆县| 车致| 蓝田县| 抚宁县| 天水市| 上蔡县| 乌兰察布市|