Day15 对 VMA 上下其手

前言

昨天将 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


<<:  Day30. Blue Prism本届最终章 –BP幕後花絮

>>:  #16 Automation (4)

【前端效能优化】Lighthouse 检测後将图片转为 webp 格式

原先的网站表现分数只有 74分 更换图片格式後网站表现分数 97分 可以看见最大内容绘制 LCP(L...

[Day 18] 转换 OpenAPI 文件为 Postman Collection 做 Web API 自动化测试

Web API 测试可以是後端工程师使用测试框架撰写白箱测试,也可以是 QA 使用测试工具进行黑箱测...

Angular#1 安装环境

若有无法执行,请讯息或留言。 感谢你让我有修正的机会 :) Angular 1. Visual St...

Day22 类别与物件--魔术方法2 及 封装private

物件导向的封装特性 封装特性:在一个物件产生之後,物件的部分成员属性和成员方法在逻辑上是不允许在物件...

Day 19 - 建立 canvas QRCode

前述 今天因为时间不足 T_T .... 所以教大家使用 qrcode.react ,可以很快速的产...