<code>Read the fucking source code!</code> --By 魯迅
<code>A picture is worth a thousand words.</code> --By 高爾基
說明:
Kernel版本:4.14
ARM64處理器,Contex-A53,雙核
使用工具:Source Insight 3.5, Visio
在之前的系列文章中,分析到了<code>Buddy System</code>的頁框配置設定,<code>Slub配置設定器</code>的小塊記憶體對象配置設定,這些配置設定的位址都是實體記憶體連續的。當記憶體碎片後,連續實體記憶體的配置設定就會變得困難,可以使用<code>vmap</code>機制,将不連續的實體記憶體頁框映射到連續的虛拟位址空間中。<code>vmalloc</code>的配置設定就是基于這個機制來實作的。
還記得下邊這張圖嗎?

<code>vmap/vmalloc</code>的區域就是在<code>VMALLOC_START ~ VMALLOC_END</code>之間。
開啟探索之旅吧。
這兩個資料結構比較簡單,直接上代碼:
<code>struct vmap_area</code>用于描述一段虛拟位址的區域,從結構體中<code>va_start/va_end</code>也能看出來。同時該結構體會通過<code>rb_node</code>挂在紅黑樹上,通過<code>list</code>挂在連結清單上。
<code>struct vmap_area</code>中<code>vm</code>字段是<code>struct vm_struct</code>結構,用于管理虛拟位址和實體頁之間的映射關系,可以将<code>struct vm_struct</code>構成一個連結清單,維護多段映射。
關系如下圖:
紅黑樹,本質上是一種二叉查找樹,它在二叉查找樹的基礎上增加了着色相關的性質,提升了紅黑樹在查找,插入,删除時的效率。在紅黑樹中,節點已經進行排序,對于每個節點,左側的的元素都在節點之前,右側的元素都在節點之後。
紅黑樹必須滿足以下四條規則:
每個節點不是紅就是黑;
紅黑樹的根必須是黑;
紅節點的子節點必須為黑;
從節點到子節點的每個路徑都包含相同數量的黑節點,統計黑節點個數時,空指針也算黑節點;
定義如下:
由于核心會頻繁的進行<code>vmap_area</code>的查找,紅黑樹的引入就是為了解決當查找數量非常多時效率低下的問題,在紅黑樹中,搜尋元素,插入,删除等操作,都會變得非常高效。至于紅黑樹的算法操作,本文就不再深入分析,知道它的用途即可。
<code>vmap</code>函數,完成的工作是,在<code>vmalloc</code>虛拟位址空間中找到一個空閑區域,然後将<code>page頁面數組</code>對應的實體記憶體映射到該區域,最終傳回映射的虛拟起始位址。
整體流程如下:
操作流程比較簡單,來一個樣例分析,就清晰明了了:
<code>vmap</code>調用中,關鍵函數為<code>alloc_vmap_area</code>,它先通過<code>vmap_area_root</code>二叉樹來查找第一個區域<code>first vm_area</code>,然後根據這個<code>first vm_area</code>去查找<code>vmap_area_list</code>連結清單中滿足大小的空間區域。
在<code>alloc_vmap_area</code>函數中,有幾個全局的變量:
用于緩存上一次配置設定成功的<code>vmap_area</code>,其中<code>cached_hole_size</code>用于記錄緩存<code>vmap_area</code>對應區域之前的空洞的大小。緩存機制當然也是為了提高配置設定的效率。
<code>vunmap</code>執行的是跟<code>vmap</code>相反的過程:從<code>vmap_area_root/vmap_area_list</code>中查找<code>vmap_area</code>區域,取消頁表映射,再從<code>vmap_area_root/vmap_area_list</code>中删除掉<code>vmap_area</code>,頁面返還給夥伴系統等。由于映射關系有改動,是以還需要進行TLB的重新整理,頻繁的TLB重新整理會降低性能,是以将其延遲進行處理,是以稱為<code>lazy tlb</code>。
來看看逆過程的流程:
<code>vmalloc</code>用于配置設定一個大的連續虛拟位址空間,該空間在實體上不連續的,是以也就不能用作DMA緩沖區。<code>vmalloc</code>配置設定的線性位址區域,在文章開頭的圖檔中也描述了:<code>VMALLOC_START ~ VMALLOC_END</code>。
直接分析調用流程:
從過程中可以看出,<code>vmalloc</code>和<code>vmap</code>的操作,大部分的邏輯操作是一樣的,比如從<code>VMALLOC_START ~ VMALLOC_END</code>區域之間查找并配置設定<code>vmap_area</code>, 比如對虛拟位址和實體頁框進行映射關系的建立。不同之處,在于<code>vmap</code>建立映射時,<code>page</code>是函數傳入進來的,而<code>vmalloc</code>是通過調用<code>alloc_page</code>接口向Buddy System申請配置設定的。
<code>vmalloc VS kmalloc</code>
到現在,我們應該能清楚<code>vmalloc</code>和<code>kmalloc</code>的差異了吧,<code>kmalloc</code>會根據申請的大小來選擇基于<code>slub配置設定器</code>或者基于<code>Buddy System</code>來申請連續的實體記憶體。而<code>vmalloc</code>則是通過<code>alloc_page</code>申請<code>order = 0</code>的頁面,再映射到連續的虛拟空間中,實體位址不連續,此外<code>vmalloc</code>可以休眠,不應在中斷處理程式中使用。
與<code>vmalloc</code>相比,<code>kmalloc</code>使用<code>ZONE_DMA和ZONE_NORMAL</code>空間,性能更快,缺點是連續實體記憶體空間的配置設定容易帶來碎片問題,讓碎片的管理變得困難。
直接上代碼:
如果在中斷上下文中,則推遲釋放,否則直接調用<code>__vunmap</code>,是以它的邏輯基本和<code>vunmap</code>一緻,不再贅述了。
作者:LoyenWang
出處:https://www.cnblogs.com/LoyenWang/
公衆号:<b>LoyenWang</b>
版權:本文版權歸作者和部落格園共有
轉載:歡迎轉載,但未經作者同意,必須保留此段聲明;必須在文章中給出原文連接配接;否則必究法律責任