iT邦幫忙

2021 iThome 鐵人賽

DAY 15
0
自我挑戰組

當你凝視linux, linux也在凝視你系列 第 15

Day15 對 VMA 上下其手

  • 分享至 

  • xImage
  •  

前言

昨天將 VMA結構檢視了一遍,也大概了解vma_area_structmm_struct 所包含的資料,那麼實際上會如何操作VMA呢?

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;
}

VMA 的查找操作

1.查詢VMA

當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,查找的目標如下

  1. addr 在該VMA的空間範圍內, 也就是 vma->vm_start <= addr <= vma->vm_end
  2. 距離該 addr 最近且結束地址大於 addr 的VMA。

如果兩個條件都不滿足,會返回 NULL ,如果滿足條件二, addr 不包含在該VMA內。
find_vma_intersection()用來找出與 start_addrend_addr 有交疊的 VMA,此函數可使用 find_vma() 完成; find_vma_prev() 則是找回前繼的成員。

2.插入VMA

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插入鏈表以及紅黑樹中。

3.合併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節點, addrend 代表新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


上一篇
Day 14 VMA來襲
下一篇
Day16 熟悉又陌生的 malloc()
系列文
當你凝視linux, linux也在凝視你30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言