最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

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

萬字解析Linux內(nèi)核之mmu-gather操作

2022-11-05 15:32 作者:補(bǔ)給站Linux內(nèi)核  | 我要投稿

1開場(chǎng)白

環(huán)境:

  • 處理器架構(gòu):arm64

  • 內(nèi)核源碼:linux-5.10.50

  • ubuntu版本:20.04.1

  • 代碼閱讀工具:vim+ctags+cscope

本文講解Linux內(nèi)核虛擬內(nèi)存管理中的mmu_gather操作,看看它是如何保證刷tlb和釋放物理頁的順序的,又是如何將更多的頁面聚集起來統(tǒng)一釋放的。

通常在進(jìn)程退出或者執(zhí)行munmap的時(shí)候,內(nèi)核會(huì)解除相關(guān)虛擬內(nèi)存區(qū)域的頁表映射,刷/無效tlb,并釋放/回收相關(guān)的物理頁面,這一過程的正確順序如下:

1)解除頁表映射

2)刷相關(guān)TLB

3)釋放物理頁面

在刷相關(guān)虛擬內(nèi)存區(qū)域tlb之前,絕對(duì)不能先釋放物理頁面,否則可能導(dǎo)致不正確的結(jié)果,而mmu-gather(mmu 積聚)的作用就是保證這種順序,并將需要釋放的相關(guān)的物理頁面聚集起來統(tǒng)一釋放。

2.源代碼解讀

2.1 重要數(shù)據(jù)結(jié)構(gòu)體

首先我們先介紹一下,與mmu-gather相關(guān)的一些重要結(jié)構(gòu)體,對(duì)于理解源碼很有幫助。

相關(guān)的主要數(shù)據(jù)結(jié)構(gòu)有三個(gè):

結(jié)構(gòu)mmu_gather

結(jié)構(gòu)mmu_table_batch

結(jié)構(gòu)mmu_gather_batch

1)mmu_gather

來表示一次mmu積聚操作,在每次解除相關(guān)虛擬內(nèi)存區(qū)域時(shí)使用。

其中, mm 表示操作哪個(gè)進(jìn)程的虛擬內(nèi)存;批處理用于積聚進(jìn)程各級(jí)頁目錄的物理頁;start和end 表示操作的起始和結(jié)束虛擬地址,這兩個(gè)地址在處理過程中會(huì)被相應(yīng)的賦值;fullmm 表示是否操作整個(gè)用戶地址空間;freed_tables 表示我們已經(jīng)釋放了相關(guān)的頁目錄;cleared_ptes/pmds/puds/p4ds 表示我們?cè)谀膫€(gè)級(jí)別上清除了表項(xiàng);vma_exec 表示操作的是否為可執(zhí)行的 VMA; vma_huge 表示操作的是否為hugetlb的VMA;batch_count 表示積聚了多少個(gè)“批次”,后面會(huì)講到 ;active、local和__pages 和多批次釋放物理頁面相關(guān); active表示當(dāng)前處理的批次,local表示“本地”批次,__pages表示“本地”批次積聚的物理頁面。

這里需要說明一點(diǎn)就是,mmu積聚操作會(huì)涉及到local批次和多批次操作,local批次操作的物理頁面相關(guān)的struct page數(shù)組內(nèi)嵌到mmu_gather結(jié)構(gòu)的__pages中,且我們發(fā)現(xiàn)這個(gè)數(shù)組大小為8,也就是local批次最大積聚8 * 4k = 32k的內(nèi)存大小,這因?yàn)閙mu_gather結(jié)構(gòu)通常在內(nèi)核棧中分配,不能占用太多的內(nèi)核??臻g,而多批次由于動(dòng)態(tài)分配批次積聚結(jié)構(gòu)所以每個(gè)批次能積聚更多的頁面。

2)mmu_table_batch

用于積聚進(jìn)程使用的各級(jí)頁目錄的物理頁,在釋放進(jìn)程相關(guān)的頁目錄的物理頁時(shí)使用(文章中稱為頁表批次的積聚結(jié)構(gòu) )。

next 用于多批次積聚物理頁時(shí),連接下一個(gè)積聚批次結(jié)構(gòu) ;

nr 表示本次批次的積聚數(shù)組的頁面?zhèn)€數(shù);

max 表示本次批次的積聚數(shù)組最大的頁面?zhèn)€數(shù);

pages 表示本次批次積聚結(jié)構(gòu)的頁面數(shù)組。

2.2 總體調(diào)用

通常mmu-gather操作由一下幾部分函數(shù)組成:

**tlb_gather_mmu **

unmap_vmas

**free_pgtables **

tlb_finish_mmu

其中tlb_gather_mmu表示mmu-gather初始化,也就是struct mmu_gather的初始化;

unmap_vmas 表示解除相關(guān)虛擬內(nèi)存區(qū)域的頁表映射;

free_pgtables 表示釋放頁表操作 ;

tlb_finish_mmu 表示進(jìn)行刷tlb和釋放物理頁操作。


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

2.3 tlb_gather_mmu

這個(gè)函數(shù)主要是初始化從進(jìn)程內(nèi)核棧中傳遞過來的mmu_gather結(jié)構(gòu)。

下面給出tlb_gather_mmu時(shí)的圖解:



2.4 unmap_vmas

這個(gè)函數(shù)用于解除相關(guān)進(jìn)程虛擬內(nèi)存區(qū)域的頁表映射,還會(huì)將相關(guān)的物理頁面放入積聚結(jié)構(gòu)中,后面統(tǒng)一釋放。

下面我們來看下這個(gè)函數(shù):

函數(shù)傳遞進(jìn)已經(jīng)初始化好的mmu積聚結(jié)構(gòu)、操作的起始vma、以及虛擬內(nèi)存范圍[start_addr, end_addr], 然后調(diào)用unmap_single_vma來操作這個(gè)范圍內(nèi)的每一個(gè)vma。

unmap_single_vma的實(shí)現(xiàn)相關(guān)代碼比較多,在此不在贅述,我們會(huì)分析關(guān)鍵代碼,它主要做的工作為:通過遍歷進(jìn)程的多級(jí)頁表,來找到vma中每一個(gè)虛擬頁對(duì)應(yīng)的物理頁(存在的話),然后解除虛擬頁到物理頁的映射關(guān)系,最后將物理頁放入積聚結(jié)構(gòu)中。

總體調(diào)用如下:

下面我們省略中間各級(jí)頁表的遍歷過程,重點(diǎn)看下最后一級(jí)頁表的處理(這段代碼相當(dāng)關(guān) 鍵 ):

以上函數(shù),遍歷進(jìn)程相關(guān)頁表(一個(gè)pmd表項(xiàng)指向一個(gè)頁表)所描述的范圍的每一個(gè)虛擬頁,如果之前已經(jīng)建立過映射,就將相關(guān)的頁表項(xiàng)清除,對(duì)于在內(nèi)存中物理頁來說,需要調(diào)用__tlb_remove_page將其加入到mmu的積聚結(jié)構(gòu)中,下面重點(diǎn)看下這個(gè)函數(shù):


我們?cè)賮砜聪聇lb_next_batch的實(shí)現(xiàn):

這里有幾個(gè)地方需要注意:MAX_GATHER_BATCH_COUNT 表示的是mmu積聚操作最多可以有多少個(gè)批次積聚結(jié)構(gòu),他的值為10000UL/MAX_GATHER_BATCH (考慮到非搶占式內(nèi)核的soft lockups的影響)。MAX_GATHER_BATCH 表示一個(gè)批次的積聚結(jié)構(gòu)的 page數(shù)組的最多元素個(gè)數(shù),他的值為((PAGE_SIZE - sizeof(struct mmu_gather_batch)) / sizeof(void *)),也就是物理頁面大小去除掉struct mmu_gather_batch結(jié)構(gòu)大小。

下面給出相關(guān)圖解:

解除頁表過程:



添加的到積聚結(jié)構(gòu)頁面數(shù)組頁面小于等于8個(gè)的情況:



添加的到積聚結(jié)構(gòu)頁面數(shù)組頁面大于8個(gè)的情況:

1個(gè)批次積聚結(jié)構(gòu)->



2個(gè)批次積聚結(jié)構(gòu)->



更多批次積聚結(jié)構(gòu)加入->



2.5 free_pgtables

unmap_vmas函數(shù)主要是積聚了一些相關(guān)的虛擬頁面對(duì)應(yīng)的物理頁面,但是我們還需要釋放各級(jí)頁表對(duì)應(yīng)的物理頁等。下面看下free_pgtables的實(shí)現(xiàn):

首先看下它的主要脈絡(luò):


我們主要看free_pgd_range的實(shí)現(xiàn):

我們以最后一級(jí)頁表(pmd表項(xiàng)指向)為例說明:

看下pte_free_tlb函數(shù):

再看看__pte_free_tlb:

需要說明的是:對(duì)于存放各級(jí)頁目錄的物理頁的釋放,每當(dāng)一個(gè)頁表積聚結(jié)構(gòu)填滿了就會(huì)釋放,不會(huì)構(gòu)建批次鏈表。

2.6 tlb_finish_mmu

通過上面的unmap_vmas和free_pgtables之后,我們積聚了大量的物理頁以及存放各級(jí)頁目錄的物理頁,現(xiàn)在需要將這些頁面進(jìn)行釋放。

下面我們來看下tlb_finish_mmu做的mmu-gather的收尾動(dòng)作:

首先看下tlb_flush_mmu:

tlb_flush_mmu_tlbonly的實(shí)現(xiàn):

我們來看下tlb_flush:

最后我們看tlb_flush_mmu_free:

tlb_table_flush的實(shí)現(xiàn):

tlb_batch_pages_flush的實(shí)現(xiàn):

最終是:調(diào)用free_pages_and_swap_cache將物理頁的引用計(jì)數(shù)減1 ,引用計(jì)數(shù)為0時(shí)就將這個(gè)物理頁釋放,還給伙伴系統(tǒng)。

雖然上面已經(jīng)釋放了相關(guān)的各級(jí)頁表的物理頁和映射到進(jìn)程地址空間的物理頁,但是存放積聚結(jié)構(gòu)和page數(shù)組的物理頁還沒有釋放,所以調(diào)用tlb_batch_list_free來做這個(gè)事情:

于是相關(guān)的所有物理頁面都被釋放了(包括相關(guān)地址范圍內(nèi)進(jìn)程各級(jí)頁目錄對(duì)應(yīng)的物理頁,映射到進(jìn)程地址空間的物理頁,和各個(gè)積聚結(jié)構(gòu)所在的物理頁)。

最后給出整體的圖解:


tlb_flush_mmu函數(shù)的tlb_table_flush會(huì)將B鏈表中的相關(guān)物理頁面釋放(包括之前保存的各級(jí)頁表的頁面和mmu_table_batch結(jié)構(gòu)所在頁面),tlb_batch_pages_flush會(huì)將A鏈表的所有除了積聚結(jié)構(gòu)以外的所有物理頁面釋放,而tlb_batch_list_free會(huì)將A鏈表的所有批次積聚結(jié)構(gòu)(mmu_gather_batch)的物理頁面釋放。

3.應(yīng)用場(chǎng)景

使用mmu-gather的應(yīng)用場(chǎng)景主要是進(jìn)程退出,執(zhí)行execv和調(diào)用munmap等。

下面我們主要來看下他們的調(diào)用鏈:

3.1 進(jìn)程退出時(shí)

進(jìn)程退出時(shí)會(huì)釋放它的所有的相關(guān)聯(lián)的系統(tǒng)資源,其中就包括內(nèi)存資源:

3.2 執(zhí)行執(zhí)行時(shí)

執(zhí)行execv時(shí)進(jìn)程會(huì)將所有的mm釋放掉:

3.3 調(diào)用munmap時(shí)

執(zhí)行munmap時(shí),會(huì)將一個(gè)地址范圍的頁表解除并釋放相關(guān)的物理頁面:

4.總結(jié)

Linux內(nèi)核mmu-gather用于積聚解除映射的相關(guān)物理頁面,并保證了刷tlb和釋放物理頁面的順序。首先解除掉相關(guān)虛擬頁面對(duì)應(yīng)物理頁面(如果有的話)的頁表映射關(guān)系,然后將相關(guān)的物理頁面保存在積聚結(jié)構(gòu)的數(shù)組中,接著將相關(guān)的各級(jí)頁目錄表項(xiàng)清除,并放入頁表相關(guān)的積聚結(jié)構(gòu)的數(shù)組中,最后刷對(duì)應(yīng)內(nèi)存范圍的tlb,釋放掉所有放在積聚結(jié)構(gòu)數(shù)組中的物理頁面。




萬字解析Linux內(nèi)核之mmu-gather操作的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
平遥县| 治多县| 略阳县| 塔河县| 平顶山市| 丰都县| 镇坪县| 平安县| 交城县| 沽源县| 区。| 洛隆县| 西畴县| 普洱| 陇西县| 敦化市| 内丘县| 那曲县| 水富县| 云梦县| 黎平县| 广水市| 梅河口市| 屯门区| 琼海市| 嘉善县| 汉中市| 宁国市| 安徽省| 轮台县| 新野县| 阜南县| 永仁县| 芷江| 汶川县| 五原县| 九龙坡区| 珲春市| 嘉定区| 佛山市| 吉隆县|