【linux 内存管理】mmap.c文件代码分析do_mmap() 和 do_mmap_pgoff()

mmap.c文件代码分析do_mmap 和 do_mmap_pgoff


当某个程序的映像开始执行时,可执行映像必须装入到进程的虚拟地址空间。如果该进程用到了任何一个共享库,则共享库也必须装入到进程的虚拟地址空间。
由此可看出,Linux并不将映像装入到物理内存,相反,可执行文件只是被连接到进程的虚拟地址空间中。随着程序的运行,被引用的程序部分会由操作系统装入到物理内存,这种将映像链接到进程地址空间的方法被称为“内存映射”。

当可执行映像映射到进程的虚拟地址空间时,将产生一组vm_area_struct 结构来描述虚拟内存区间的起始点和终止点,每个 vm_area_struct 结构代表可执行映像的一部分,可能是可执行代码,也可能是初始化的变量或未初始化的数据,这些都是在函数 do_mmap()中来实现的

函数 do_mmap()为当前进程创建并初始化一个新的虚拟区,
如果分配成功,就把这个新的虚拟区与进程已有的其他虚拟区进行合并

页面的映射到底在何时建立:generic_file_mmap( )就是真正进行映射的函数。这个函数的实现涉及很多文件系统的内容,后续自己有时间再了解。

这里要说明的是,文件到虚存的映射仅仅是建立了一种映射关系,也就是说,虚存页面到物理页面之间的映射还没有建立。当某个可执行映象映射到进程虚拟内存中并开始执行时,
因为只有很少一部分虚拟内存区间装入到了物理内存,可能会遇到所访问的数据不在物理内存。
这时,处理器将向 Linux 报告一个页故障:(1.程序错误;2.缺页异常;3.要访问的虚地址被写保护,即保护错误)及其对应的故障原因,于是就用到了请页机制。

do_mmap()

static inline unsigned long do_mmap(struct file *file, unsigned long addr,
	unsigned long len, unsigned long prot,
	unsigned long flag, unsigned long offset)
	/*
	file:表示要映射的文件,file 结构将在第八章文件系统中进行介绍。
	addr:虚拟空间中的一个地址,表示从这个地址开始查找一个空闲的虚拟区。
	len:要映射的文件部分的长度。
	prot: 这个参数指定对这个虚拟区所包含页的存取权限。
		  可能的标志有 PROT_READ、PROT_WRITE、PROT_EXEC 和 PROT_NONE。
		  前 3 个标志与标志 VM_READ、VM_WRITE 及 VM_EXEC的意义一样。
		  PROT_NONE 表示进程没有以上 3 个存取权限中的任意一个。
		  
	flag:这个参数指定虚拟区的其他标志:
		  MAP_GROWSDOWN,MAP_LOCKED,MAP_DENYWRITE 和 MAP_EXECUTABLE : 它们的含义与表 6.1 中所列出标志的含义相同。
		  
		  MAP_SHARED 和 MAP_PRIVATE : 前一个标志指定虚拟区中的页可以被许多进程共享;后一个标志作用相反。
		  							   这两个标志都涉及 vm_area_struct 中的 VM_SHARED 标志。
		  							   
		  MAP_ANONYMOUS:表示这个虚拟区是匿名的,与任何文件无关。
		  
		  MAP_NORESERVE:函数不必预先检查空闲页面的数目。
		  
	offset\:文件内的偏移量,因为我们并不是一下子全部映射一个文件,可能只是映射文件的一部分,off 就表示那部分的起始位置。 
	
	 表 6.1 
	VM_DENYWRITE 	在这个区间映射一个打开后不能用来写的文件 
	VM_EXEC 		页可以被执行 
	VM_EXECUTABLE 	页含有可执行代码 
	VM_GROWSDOWN 	这个区间可以向低地址扩展 
	VM_GROWSUP 		这个区间可以向高地址扩展 
	VM_IO 			这个区间映射一个设备的 I/O 地址空间 
	VM_LOCKED 		页被锁住不能被交换出去 
	VM_MAYEXEC 		VM_EXEC 标志可以被设置 
	VM_MAYREAD 		VM_READ 标志可以被设置 
	VM_MAYSHARE 	VM_SHARE 标志可以被设置 
	VM_MAYWRITE 	VM_WRITE 标志可以被设置 
	VM_READ 		页是可读的 
	VM_SHARED 		页可以被多个进程共享 
	VM_SHM 			页用于 IPC 共享内存 
	VM_WRITE 		页是可写的
	*/
{
   
	unsigned long ret = -EINVAL;
	/*对参数 offset 的合法性检查后*/
	if ((offset + PAGE_ALIGN(len)) < offset)
		goto out;
	/*就调用 do_mmap_pgoff()函数,该函数才是内存映射的主要函数,*/
	if (!(offset & ~PAGE_MASK))
		ret = do_mmap_pgoff(file, addr, len, prot, flag, offset >> PAGE_SHIFT);
out:
	return ret;
}

do_mmap_pgoff()

// An highlighted block
unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned long len,
	unsigned long prot, unsigned long flags, unsigned long pgoff)

	/*负责把磁盘文件的逻辑地址映射到虚拟地址,以及把虚拟址映射到物理地址。*/
			 
	/*do_mmap在mm.h中do_mmap()为当前进程创建并初始化一个新的虚拟区,
	如果分配成功,就把这个新的虚拟区与进程已有的其他虚拟区进行合并*/

			 /*file:指向需要建立虚拟映射的文件,
			 addr:指定从何处开始查找一个空闲区域,
			 len:给出vma段的地址空间长度,
			 off:是vma段相对于文件file的起始地址的偏移量,
			 prot:为vma段所包含页的访问权限*/
{
   
	//为当前进程创建mm_struct内存描述符
	struct mm_struct * mm = current->mm;
	
	struct vm_area_struct * vma, * prev;
	unsigned int vm_flags;
	int correct_wcount = 0;
	int error;
	rb_node_t ** rb_link, * rb_parent;

	if (file && (!file->f_op || !file->f_op

你可能感兴趣的:(leetcode,c++,linux)