昨天將 VMA結構檢視了一遍,也大概了解vma_area_struct
與 mm_struct
所包含的資料,那麼實際上會如何操作VMA呢?
首先要先了解,VMA 本身代表行程位址空間中的區間, VMA是有屬性,也就是該段資料可以做什麼樣的操作。 vm_flag
就是負責描述這些屬性的, 這個標誌記錄了這個屬性。 下列列出幾個常見的 vm_flag
VM_READ
: 代表VMA可讀取。VM_WRITW
: 代表VMA可寫入。VM_EXEC
: 代表VMA可執行。VM_SHARED
: 代表VMA允許多個行程共享。
VMA的屬性可以任意組合,但是最終仍要在硬體機制上時線,並且記錄在分頁表裡面的資料中。 在創建新的VMA時,可以用 vm_get_page_prot()
把 vm_flag
轉成具體的分頁表上的標記。
<mm/mmap.c>
pgprot_t vm_get_page_prot(unsigned long vm_flags){
pgprot_t ret = __pgprot(pgprot_val(protection_map[vm_flags \
& (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)]));
return ret;
}
當CPU 發出了一個虛擬位址,該如何確定這個位址是否已經分配了VMA呢? Kernel 提供了一個API進行 VMA的查詢。
<mm/mmap.c>
struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
struct vm_area_struct *find_vma_prev(struct mm_struct *mm, unsigned long addr,
struct vm_area_struct **pprev);
static inline struct vm_area_struct *find_vma_intersection(struct mm_struct * mm,
unsigned long start_addr, unsigned long end_addr)
find_vma()
可以根據給定的 addr
查找滿足以下條件之一的 VMA,查找的目標如下
addr
在該VMA的空間範圍內, 也就是 vma->vm_start
<= addr
<= vma->vm_end
addr
最近且結束地址大於 addr
的VMA。如果兩個條件都不滿足,會返回 NULL
,如果滿足條件二, addr
不包含在該VMA內。find_vma_intersection()
用來找出與 start_addr
或 end_addr
有交疊的 VMA,此函數可使用 find_vma()
完成; find_vma_prev()
則是找回前繼的成員。
insert_vm_struct()
是kernel 提供的插入VMA的API // 這裡有 __insert_vm_struct() 跟 insert_vm_struct() 有什麼差別? 還是根本沒差
int insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vma)
{
struct vm_area_struct *prev;
struct rb_node **rb_link, *rb_parent;
if (find_vma_links(mm, vma->vm_start, vma->vm_end,
&prev, &rb_link, &rb_parent))
return -ENOMEM;
if ((vma->vm_flags & VM_ACCOUNT) &&
security_vm_enough_memory_mm(mm, vma_pages(vma)))
return -ENOMEM;
if (vma_is_anonymous(vma)) {
BUG_ON(vma->anon_vma);
vma->vm_pgoff = vma->vm_start >> PAGE_SHIFT;
}
vma_link(mm, vma, prev, rb_link, rb_parent);
return 0;
}
第6行 find_vma_links()
查找實際要插入的位置。
第12行 vma_is_anonymous()
判斷是否是匿名映射的VMA
第17行 vma_link
將VMA插入鏈表以及紅黑樹中。
在新的VMA被加入行程的地址空間時,會檢查是否可以與目前現存的VMA合併, vma_merge()
會用來將一個VMA跟附近的VMA合併。
struct vm_area_struct *vma_merge(struct mm_struct *mm,
struct vm_area_struct *prev, unsigned long addr,
unsigned long end, unsigned long vm_flags,
struct anon_vma *anon_vma, struct file *file,
pgoff_t pgoff, struct mempolicy *policy,
struct vm_userfaultfd_ctx vm_userfaultfd_ctx)
在些參數之中 mm
是相關行程的 mm_struct
數據結構, prev
是新VMA前繼的VMA節點, addr
與 end
代表新VMA的起始地址與結束地址, vm_flags
代表新VMA的標記。 如果新VMA是文件映射,參數file
會指向file數據結構。 proff
指定文件映射的偏移量 。 anon_vma
是匿名映射的數據結構。
"__" underscore 在同一個檔案內 仍然算是不同的function, __ 的目的?
代表private for developer 不希望programer使用
另一些解法
https://stackoverflow.com/questions/10687053/meaning-of-double-underscore-in-the-beginning/10687114
https://hackmd.io/@VIRqdo35SvekIiH4p76B7g/BJ1kBwKo?type=view
https://b8807053.pixnet.net/blog/post/3612001