Linux核心中,關於虛存管理的最基本的嵌入式管理單元應該是struct vm_area_struct了,它描述的是一段連續的、具有相同訪問屬性的虛存空間,該虛存空間的大小為實體記憶體頁面的整數倍。
下面是struct vm_area_struct結構體的定義:
/* * This struct defines a memory VMM memory area. There is color: black; background-color: #a0ffff;">vm_area_struct { struct mm_struct * vm_mm; /* VM area parameters */ unsigned long vm_start; unsigned long vm_end;/* linked list of VM areas per task, sorted by address */ struct vm_area_struct *vm_next; pgprot_t vm_page_prot; unsigned long vm_flags; /* AVL tree of VM areas per task, sorted by address */ short vm_avl_height; struct vm_area_struct * vm_avl_left; struct vm_area_struct * vm_avl_right; /* For areas with an address space and backing store, * font-size: 10px;">vm_area_struct *vm_next_share; struct vm_area_struct **vm_pprev_share; struct vm_operations_struct * vm_ops; unsigned long vm_pgoff; /* offset in PAGE_SIZE units, *not* PAGE_CACHE_SIZE */ struct file * vm_file; unsigned long vm_raend; void * vm_private_data; /* was vm_pte (shared mem) */ }; |
vm_area_struct結構所描述的虛存空間以vm_start、vm_end成員表示,它們分別儲存了該虛存空間的首地址和末地址後第一個位元組的地址,以位元組為單位,所以虛存空間範圍可以用[vm_start, vm_end)表示。
通常,進程所使用到的虛存空間不連續,且各部分虛存空間的訪問屬性也可能不同。所以一個進程的虛存空間需要多個vm_area_struct結構來描述。在vm_area_struct結構的數目較少的時候,各個vm_area_struct按照升序排序,以單鏈表的形式組織資料(通過vm_next指標指向下一個vm_area_struct結構)。但是當vm_area_struct結構的資料較多的時候,仍然採用鏈表組織的化,勢必會影響到它的搜尋速度。針對這個問題,vm_area_struct還添加了vm_avl_hight(樹高)、vm_avl_left(左子節點)、vm_avl_right(右子節點)三個成員來實現AVL樹,以提高vm_area_struct的搜尋速度。
假如該vm_area_struct描述的是一個檔案對應的虛存空間,成員vm_file便指向被映射的檔案的file結構,vm_pgoff是該虛存空間起始地址在vm_file檔案裡面的檔案位移,單位為物理頁面。
一個程式可以選擇MAP_SHARED或MAP_PRIVATE共用模式將一個檔案的某部分資料對應到自己的虛存空間裡面。這兩種映射方式的區別在於:MAP_SHARED映射後在記憶體中對該虛存空間的資料進行修改會影響到其他以同樣方式映射該部分資料的進程,並且該修改還會被寫迴文件裡面去,也就是這些進程實際上是在共用這些資料。而MAP_PRIVATE映射後對該虛存空間的資料進行修改不會影響到其他進程,也不會被寫入檔案中。
來自不同進程,所有映射同一個檔案的vm_area_struct結構都會根據其共用模式分別組織成兩個鏈表。鏈表的鏈頭分別是:vm_file->f_dentry->d_inode->i_mapping->i_mmap_shared, vm_file->f_dentry->d_inode->i_mapping->i_mmap。而vm_area_struct結構中的vm_next_share指向鏈表中的下一個節點;vm_pprev_share是一個指標的指標,它的值是鏈表中上一個節點(前端節點)結構的vm_next_share(i_mmap_shared或i_mmap)的地址。
進程建立vm_area_struct結構後,只是說明進程可以訪問這個虛存空間,但有可能還沒有分配相應的物理頁面並建立好頁面映射。在這種情況下,若是進程執行中有指令需要訪問該虛存空間中的記憶體,便會產生一次缺頁異常。這時候,就需要通過vm_area_struct結構裡面的vm_ops->nopage所指向的函數來將產生缺頁異常的地址對應的檔案資料讀取出來。
vm_flags主要儲存了進程對該虛存空間的存取權限,然後還有一些其他的屬性。vm_page_prot是新映射的物理頁面的頁表項pgprot的預設值。