Linu虚拟内存分析

上传人:jin****ng 文档编号:110345306 上传时间:2022-06-18 格式:DOC 页数:29 大小:439KB
返回 下载 相关 举报
Linu虚拟内存分析_第1页
第1页 / 共29页
Linu虚拟内存分析_第2页
第2页 / 共29页
Linu虚拟内存分析_第3页
第3页 / 共29页
亲,该文档总共29页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
Linux 虚 存 分 析 报 告第一章前言2第二章LINUX虚存管理概述31、LINUX 虚存管理的基本特点32、LINUX 虚存管理的主要实现技术3第三章LINUX虚存管理数据结构41、32-BIT 虚拟地址42、LINUX 的多级页表结构53、页表项的格式64、动态地址映射75、用户进程的虚拟内存结构76、我们的工作10第四章PROCESS的虚存管理数据结构的建立、维护、拆除及相关系统调用流程 111、进程的载入、创建及内存管理数据结构和链结关系的建立112、数据结构及链结关系的拆除(SYS一exit)133、缺页中断服务14第五章主要函数分析16MEMORY.C16MMAP.C22第一章 前 言Linux 是一个功能强大的操作系统,而内存管理则是操作系统的核心,它负责管理计 算机系统的存储器。作为操作系统的核心,必须能够克服物理内存的局限,使用户进程在 透明方式下,拥有比实际物理内存大得多的内存。其策略之一就是使用虚拟内存oLinux成 功地实现了以虚拟内存为核心的内存管理策略,强大得分页机制,公平得交换方式,各类 有效得高速缓存,以及以页保护为主得保护措施等。内存管理的目的是要尽可能地方便用 户。同时Linux系统通过对用户进程虚存的有效管理,作到了虚存对一般用户和Linux程序 员的透明。本文首先阐述了 Linux 虚存管理以基本特点和主要实现技术,并分析了 Linux 虚存管 理的主要数据结构及其相关关系。围绕它的建立、维护、使用和拆除,作了一个粗浅的剖 析,因本人水平有限,有不当之处,敬请指正。第二章Linux虚存管理概述Linux 的内存管理采用页式管理,使用多级页表,动态地址转换机构与主存、辅存共同 实现虚拟内存:每个用户Process拥有4GB的虚拟地址空间,Process在运行过程中可以动 态浮动和扩展,为用户提供了透明的、灵活有效的内存使用方式,下面简述Linux虚存管理 以基本特点和主要实现技术:1、Linux 虚存管理的基本特点1. 更大的地址空间。 虚拟内存可以是系统实际拥有的物理内存的若干倍。因而它使得操作系统看起来拥有比实际大得多的内存。2. 合理的物理内存分配。Linux通过共享和交换策略,使各个运行的进程能公平地共享内存。3. 保护。Linux存储管理子系统为每一内存页设置了“上锁位”在线性地址及每级页表 页项上设置了“读/写”位,这样来确保某一个进程不受其他进程的干扰。即使某一 个进程失败了,也不会影响到其他进程和操作系统本身。4. 共享虚拟内存Linux 实现的虚拟内存允许两个进程之间互相共享内存,例如:共享的库。在 这种情形之下,库代码仅存在于一个进程,而不需要为每一个应用都复制一份。2、Linux 虚存管理的主要实现技术1、请求调页(demanding paging)与内存扩展用户 Process 创建时,并不是将它所需所有页都分配给相应物理页。开始时只装入页面 中 Process 的第一个页面,其他页根据 Process 运行过程的请求从外存调入所需页面,当 Process访问一个页表项P位为0的页中地址时,表示此页不在主存中,将产生缺页中断, 系统调用handle_mm_fault()处理访问异常,为之分配相应物理页后,它再调用swap_in() 函数,从外存中读入该页面。Linux是一种请求式分页存贮管理,这才使之可以运行大于主存空间的Process。2、 页换出策略内存中页面不足时,Linux使用页面AGE技术实现了页淘汰策略的最近最少使用(LRU) 算法:即每次换出时,总是选择最老的页换出,对易于从其他设备上获取的非脏not dirty) 页面。Linux采用丢弃(discarding)技术,如果发生过写操作,则将该页写入系统的Swapfile 中,这样就可以加快换入的速度。3、内存共享Linux将内存划分为4K大小的页面,为内存共享提供了基础:(1) 不同进程间页面共享时,可令共享该页的Process的页表项(pte)均指向该页。(2) 对 kernel 代码和数据段的共享,通过 Process 创建时 fork() 函数将 kernel 代码和数据 段映射到用户虚存的 3GB4GB 的空间中去,所以每个 Process 都可以通过一定方式共享 kernel的代码和数据段。4、内存保护采用了“Hole”技术、虚存段的保护、地址转换机构、页表存取控制位(R/W位)等 技术实现了内存保护。“Hole”技术 物理内存前4K是一空页(empty_zero_page),用来捕获NULL指 针的异常访问。在Process每个虚存段后,都有一个“4K”的“Hole”,用来捕获虚存段的 越界访问。虚存段保护方式主存中虚存段的全部或部分可以设为保护方式,防止非法访问。页表项存取控制位(R/W位) 页表项以“R/W”位表示此页的存取权限“1”为 可读写,“0”为不可读写,可用来防止越权访问。地址转换机构 分页存贮管理方法中,地址转换机构进行的页面映象实际上防止了 各Process的主存块间互不干扰,起到Process隔离的作用。5、动态地址变换利用i386的地址变换机构Linux实现了动态地址变换,Process执行时访问到某一虚拟 地址时才确定其对应的物理地址。这种方式为Process存贮块的动态和动态扩展提供了基础。第三章 Linux 虚存管理数据结构1、32-bit 虚拟地址在Linux中,4GB的虚存需通过32-bit地址进行寻址。(Linux中虚拟地址与线形地址为同一概念)虚拟地址被分割成3 个子位段,其中2 个子位段包含10 位, 1 个子位段包含12 位,如图2.1 所示:32-bit Virtual Address12图 1 32 位虚拟地址3个子位段分别表示不同含义:子位段1指向被称作页目录(PGD)的一张表,子位段2指 向被称作页表(PTE)的一张表,子位段3指向页内地址。2、Linux 的多级页表结构标准的Linux的虚存页表为三级页表,依次为页目剥Page Directory-PGD)、中间页目 录(Page Middle Directory-PMD)、页表(Page Table)PTE)。如图 2.2 所示。PGDPMDPTEPAGE FRAME图 2 Linux 的多级页表结构在i386机器上Linux的页表结构实际为两级,PGD和PMD页表是合二为一的。所有 有关PMD的操作实际上是对PGD的操作。所以原代码中形如*-pgd-*()和*-卩皿小-*()的函数 实现的功能也是一样的。页目录(PGD)是一个大小为4K的表,每一个process只有一个页目录,以4字节为一 个表项,分成1024 个表项(或称入口点);该表项的值为所指页表的始地址。 32位虚拟地址 的第 1 个子位段共 10 位,其值的范围从0 到 1023,对应于页目录的一个入口点。页目录(PTE)的每一个入口点的值为此表项所指的一页框(page frame),32位虚拟地址的第2 个子位段共10 位,其值的范围从0 到 1023。页框(page frame)并不是物理页,它指是虚存的一个地址空间。3、页表项的格式Linux 中页表每一个表项的格式,如图所示:31 12 11 7 6 5 4 3 2 1 0AddressReservedDAUSRWP图 3 页表项格式其中,各位段的含义如下:P:存在位,表示该表项对地址的转换是否有效。i386处理器在P=0时不解释表 项中的任何位,此时这些位的含义完全由软件自行解释。P位提供了至关重要 的属性,以支持分页机制。如果P=l,则表示虚拟地址所对应的页框存在于物 理内存中,访问该虚拟地址的程序可以正常运行;P=0,则表示虚拟地址所对 应的页框不存在于物理内存中,访问该虚拟地址的程序将会引发页访问异常, 产生缺页中断。使得Operating System可以把缺少的页从磁盘上读入内存,并 将读入页存入到表项中,然后将该页标志为存在,再使引起异常的程序继续执 行。R/W :读写位,表示对该表项指向的页可以进行读、写或执行操作。 R/W=l 则该页 可写,可读,且可执行; R/W=0 则该页可读,可执行,但不可写。当处理器 处于特权级 02 时, R/W 位被忽略。如该表项位于页目录中,则作用于该表 项映射的所有各页。U/S :用户/系统位。 U/S=l 则该页可在任何处理器特权级下访问; U/S=0 则该页只能在处理器特权级02 下被访问。如该表项位于页目录中,则作用于该表项映 射的所有各页。D: 已写标志位。在对该表项映射的页进行写访问之前,处理器对该位置1。如该 表项是页目录中表项,处理器不修改D位。Address :页框物理地址的高20位。系统将物理内存分割成4K大小的内存页框Address 实际上代表了页框的帧号。4、动态地址映射Linus虚存采用动态地址映射方式,即Process的地址空间和存储空间的对应关系是在程 序的执行过程中实现的:Process每用到一个地址时,都需虚存的地址转换机构把虚拟地址 转化为内存的实际地址。其地址映射如下图所示:Physical Addres1 Shift 2 bits hShift 2 bits |000001 00001101100001001 p11111111图 432 位虚拟地址转换图动态地址映射使 Linux 可以实现 Process 在主存中的动态重定位,虚存段的动态扩展和移动;也为虚存的实现提供了基础。5、用户进程的虚拟内存结构用户进程的虚拟内存结构如图所示mm_struct每一个进程的task_struct中都有一个结构mm_struct,此结构包含了进程中与储存管理 相关的大部分信息,其申明如下:struct mm_struct int count; /使用该mm结构的个数,如果是多处理机,则有可能count 1pgd_t * pgd; /* 进程页目录的起始地址,如上图所示 */unsigned long context;unsigned long start_code, end_code, start_data, end_data;/*start_code、end_code:进程代码段的起始地址和结束地址。start_data、end_data:进程数据段的起始地址和结束地址。*/unsigned long start_brk, brk, start_stack, start_mmap;unsigned long arg_start, arg_end, env_start, env_end;/* arg_start、arg_end:调用参数区的起始地址和结束地址。env_start、env_end:进程环境区的起始地址和结束地址。*/unsigned long rss, total_vm, locked_vm;/* rss:进程内容驻留在物理内存的页面总数。*/unsigned long def_flags;struct vm_area_struct * mmap;/*以双向链表组成的vma模块的首指针。*/struct vm_area_struct * mmap_avl; /* 以 avl 树结构组成的虚拟空间的首指针。 */ struct semaphore mmap_sem;用户进程虚存管理的数据结构如图5所示。用户共有4GB的虚存空间,实际可申请的 虚存空间为03GB。3GB4GB的虚存空间在用户进程创建时,已由函数fork()将kernel的 代码段和数据段映射到3GB4GB的虚存空间。因而所有进程的3GB4GB的虚存空间的映 象都是相同的,从而以这种方式使所有进程共享kernel的代码段和数据段。VMA进程的虚拟空间通常由一个个vma块组成,这些块的结构如下所示:struct vm_area_struct struct mm_struct * vm_mm; unsigned long vm_start; unsigned long vm_end; pgprot_t vm_page_prot; unsigned short vm_flags;/* VM area parameters */该 vma 块代表的使用虚拟空间的起始地址 /该 vma 块代表的使用虚拟空间的结束地址/保护位/标志位/* AVL tree of VM areas per task, sorted by address */short vm_avl_height;/avl 树高度struct vm_area_struct * vm_avl_left;/vma 块的左子节点struct vm_area_struct * vm_avl_right;/vma 块的右子节点/* linked list of VM areas per task, sorted by address */struct vm_area_struct * vm_next;/* 在按地址大小排列的单向链表上的下一个指针*/* for areas with inode, the circular list inode-i_mmap */* for shm areas, the circular list of attaches */* otherwise unused */struct vm_area_struct * vm_next_share;struct vm_area_struct * vm_prev_share;/* more */struct vm_operations_struct * vm_ops; /对 VMA 块进行操作的函数集 unsigned long vm_offset;struct inode * vm_inode;/该 VMA 块对应的文件unsigned long vm_pte; /* shared mem */;采用 avl 树的优点是可以快速找到相关地址所在的 vma 块。同时,同一个任务的 vma 块还按前后顺序排成一个线性链表。6、我们的工作针对上图所示的用户进程虚存管理的数据结构,围绕它的建立、维护、使用和拆除, 我们组作了相应的工作,主要包括以下几点:1、进程的载入、创建及内存管理数据结构和链结关系的建立(sys_execve, sys_fork, sys_clone)2、页表的建立与释放( new_page_tables, free_page_tables, )3、虚拟内存的申请与释放(sys_mmap, sys_munmap)4、缺页中断处理(do_page_fault)5、虚拟块 VMA 的管理(sys_remap, sys_mprotect)6、数据结构及链结关系的拆除(sysexit)其中,虚拟内存的申请与释放由林涛和徐玫峰同学负责,虚拟块VMA的管理由范昭伟同学负责,相关的工作体现在他们的分析报告中。第四章 Process 的虚存管理数据结构的建立、维护、拆 除及相关系统调用流程1、进程的载入、创建及内存管理数据结构和链结关系的建立sys_execve 系统调用负责将可执行文件映象载入到内存,与内存相关的操作主要是:通 过调用 exit_mmap 清除当前进程的所有的虚存块,通过调用 clear_page_table 清除当前进程 的页表项,通过调用 flush_old_signals 清除当前进程的残留信号,通过调用 flush_old_files 清除当前进程的已打开文件,从而将当前进程掏空,成为一个空壳。然后系统根据bprm结 构更新 current 进程的控制块,并通过调用两次 do_mmap 分别将执行文件的代码段和数据段 映射到虚存。系统一般只将前两页载入物理内存中,同时分配一页给堆栈,其它的均留在硬 盘中通过虚拟内存映射机制映射为虚拟内存。当运行中发生缺页中断时,系统处理缺页中断, 将缺页调入物理内存中,如果发生物理内存不足的情况,则由kswapd()选择合适的页调入交 换文件中或扔掉(如未发生写操作)。具体流程如下:asmlinkage int sys_execve(struct pt_regs regs)为do_execve()的调用准备参数do_execve()初始化bprm /* bprm是struct linux_binprm,进程控制块中某些参数的暂存器*/ search_binary_handler()/*寻找二进制文件的处理程序(handler),并用该handler (一般是load_aout_binary)程序处理该二进制文件*/load_aout_binary()do_load_aout_binary()/异常情况判断,flush_old_exec(bprm)exec_mmap()/ if necessary, then copy_on_write exit_mmap(current-mm)/清除当前进程的所有的虚存块clear_page_table(current)/清除当前进程的页表项flush_tlb_mm(current-mm); /?flush_thread(); /?flush_old_signals(current-sig); /清除当前进程的残留信号 flush_old_files(current-files);/清除当前进程的已打开文件/到此为止,当前进程已被掏空,成为一个空壳。根据 bprm 结构更新 current 进程的控制块do_mmap(); /将执行文件的代码段映射到虚存do_mmap(); /将执行文件的数据段映射到虚存 / do_load_aout_binary/end for load_aout_binary/ end for search_binary_handler /end for do_execve /end for sys_execve2、do_fork()当通过 sys_fork 和 sys_clone 系统调用来创建子进程时,系统将通过 do_fork 函数来完 成大部分的创建任务,do_fork函数首先申请一页的核心空间给进程控制块,再申请一页的 核心空间给系统堆栈,再通过 copy_mm 函数为子进程复制父进程的虚拟空间(如果是 sys_clone系统调用,则不用复制,子进程的mm指针指向父进程mm_struct),具体流程如 下:asmlinkage int sys_fork(struct pt_regs regs)return do_fork(SIGCHLD, regs.esp, ®s);asmlinkage int sys_clone(struct pt_regs regs)unsigned long clone_flags;unsigned long newsp;clone_flags = regs.ebx;newsp = regs.ecx;if (!newsp)newsp = regs.esp;return do_fork(clone_flags, newsp, ®s);do_fork()申请一页的核心空间给进程控制块 (struct task_struct *p) 申请一页的核心空间给系统堆栈*P=*current; /复制父进程的进程控制块作必要的修改copy_mm()如果是 clone 父子进程的 mm 指针指向同一个 mm_struct; mm_struct-count+;else /画图struct mm_struct *mm = 申请一页核心空间; *mm = *current-mm; /复制父进程的相关信息new_page_tables(); 建立新的页目录表pgd,且复制init进程的768-1023项 dup_mmap();/复制父进程的虚拟空间映射for对于父进程中的每一个VMA块复制该VMA块,作相应修改并重新链起来; copy_page_range(mm, current-mm, 该 VMA 块)其工作机制是循环调用copy_pmd_range,将vma块中的所有虚 拟空间复制到对应的虚拟空间中。在做复制之前,必须确保新 任务对应的 被复制的虚拟空间中必须都为零。 /end for dup_mmap()/ end for copy_mm()/end for do_fork()2、数据结构及链结关系的拆除(sys_eXt)sys_exit()系统调用sys_exit来结束进程,调用exit_mm()将所有虚拟内存都结束掉,最后中止进 程。asmlinkage int sys_exit(int error_code) ()do_exit()kerneld_exit();_exit_mm(current);if ( !-current-mm-count ) /无其他进程共享该 mm_structexit_mmap(mm);for 对于当前进程 current-mm 中的每一个 VMA 块,调用 vm_ops-unmap 释放该 VMA 块对应的虚拟空间调用zap_page_range将指向释放掉的虚拟空间中的pte页表项清 零。调用kfree释放该VMA块结构占用的物理空间。 free_page_tables(mm);/将 mm-pdg 中所有的 pte 页表项清空,并将 mm-pdg 清空 kfree(mm);current-mm = init.mm /end for _exit_mm(current);_exit_files(current);_exit_fs(current);_exit_sighand(current);/end for do_exit;3、缺页中断服务 当程序在运行中,访问到的无效的虚拟地址的时候,系统将激发出缺页中断。激发缺页中断的情况通常有四种:1. COW 型中断,当某个进程进行写操作时,如果写的页是多进程在使用时, 为了不影响其它进程的正常运行,通常需要将该页复制一份,供执行写操作 的进程单独使用。2. 被访问的物理页由于太长时间没有访问而被kswapd置换到swap file中。3. 被访问的物理页由于是第一次访问,所以还在磁盘上或由于访问后被置换时 因为没有发生写操作,而未写到swap file中。4. 当进程动态的访问一片存储区域时,如在程序中动态开辟的数组等,则该页 不在 swap file 中,也不在磁盘上。缺页中断服务入口程序是函数 do_page_faultdo_page_fault 首先进行各种错误情况判断,并作相应处理,然后根据 error_code 来判断缺页中断类型:第一种情况采用 do_wp_page 函数来处理,第二、三、四种情况由 do_no_page 函数来处理。下面将分别介绍这些函数的流程图。void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,unsigned long address, int write_access)图 7 do_wp_page 示意图void do_no_page(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long address, int write_access)根据 address 计算三级页表中 pgd/pmd/pte 的值,如无对应的项,分配空间将 其填上if ( pte_present(entry) ) 该页已在内存中,return;可能是共享该页的其他进程已将该页读入else if (!pte_none(entry)/情况 2pte中该项非空,说明该页被kswapd置换到swap file中, 调用 do_swap_page 读入该页;else if ( !vma-vm_ops | !vma-vm_ops-nopage)/情况 4该页对应的VMA块没有相应的nopage操作,说明该VMA块对应的是 数据段内容调用_get_free_page 操作为该页分配内存,并将该页赋值为 0,同时链入 该进程的页表中else/情况 3调用虚拟块操作将磁盘中对应文件读入page中, 将 pte 表中对应的项指向该页。 将该页 dirty 位置位,如果该页有多进程使用,且非共享,置写保护位。第五章 主要函数分析Memory.c在该文件中,Linux提供了对虚拟内存操作的若干函数,其中包括对虚拟页的复制、新 建页表、清除页表、处理缺页中断等等。1static inline void copy_page(unsigned long from, unsigned long to)为了节约内存的使用,在系统中,各进程通常采用共享内存,即不同的进程可以共享 同一段代码段或数据段。当某一进程发生对共享的内存发生写操作时,为了不影响其它进 程的正常运行,系统将把该内存块复制一份,供需要写操作的进程使用,这就是所谓的 copy-on-write机制。copy_page就是提供复制内存功能的函数,它调用C语言中标准的内存 操作函数,将首地址为from的一块虚拟内存页复制到首地址为to的空间中。2、void clear_page_tables(struct task_struct * tsk)clear_page_table的功能是将传入的结构tsk中的pgd页表中的所有项都清零,同时将二 级页表所占的空间都释放掉。传入clear_page_tables的是当前进程的tsk结构,取得该进程 的一级页目录指针pgd 后,采用循环的方式,调用free_one_pgd清除pgd表。表共1024项。 在free_one_pgd中,实际执行的功能只调用一次free_one_pmd (在80x86中,由于硬件的 限制,只有两级地址映射,故将 pmd 与 pgd 合并在一起)。在 free_one_pmd 中,函数调用 pte_free将对应于pmd的二级页表所占的物理空间释放掉(进程代码、数据所用的物理内存 在 do_munmap 释放掉了)并将 pmd 赋值为零。clear_page_table 在系统启动一个可执行文件的映象或载入一个动态链接库时被调用。 在 fs/exec.c 中的 dooad_elf_binary()或 dooad_aout_binary()调用 flash_old_exec,后者调用 exec_mmap,而exec_mmap调用clear_page_table。其主要功能是当启动一个新的应用程序 的时候,将复制的mm_struct中的页表清除干净,并释放掉原有的所有二级页表空间。3、void oom(struct task_struct * task)返回出错信息。4、void free_page_tables(struct mm_struct * mm)在 free_page_table 中,大部分的代码与 clear_page_table 中的函数一致。所不同的是,该函数在最后调用了 pgd_free(page_dir),即不光释放掉二级页表所占的空间,同时还释放一级页目录所占的空间。这是因为 free_page_tables 被_exit_mm 调用,_exit_mm 又被 do_exit (kernel/kernel.c)调用。当进程中止、系统退出或系统重起时都需要用do_exit (属 于进程管理)将所有的进程结束掉。在结束进程过程中,将调用free_page_table将进程的 空间全部释放掉,当然包括释放进程一级页目录所占的空间。5、int new_page_tables(struct task_struct * tsk)该函数的主要功能是建立新的页目录表,它的主要流程如如下:1. 调用pgd_alloc()为新的页目录表申请一片4K空间。2. 将初始化进程的内存结构中从768项开始到1023项的内容复制给新的页表(所有 的进程都共用虚拟空间中3G4G的内存,即在核心态时可以访问所有相同的存 储空间)。3. 调用宏 SET_PAGE_DIR (include/asm/pgtable.h)将进程控制块 tsk-ts-CR3 的值 改为新的页目录表的首地址,同时将CPU中的CR3寄存器的值改为新的页目录表 的首地址,从而使新进程进入自己的运行空间。4. 将 tsk-mm-pgd 改为新的页目录表的首地址。new_page_tables 被 copy_mm 调用,而 copy_mm 被 copy_mm_do_fork 调用,这两个函 数都在 kernel/fork.c 中。同时,new_page_tables 也可以在 exec_mmap (fs/exec.c)中调用。 即新的进程的产生可以通过两种途径,一种是fork,在程序中动态地生成新的进程,这样新 进程的页表原始信息利用copy_mm从其父进程中继承而得,另一种是运行一个可执行文件 映象,通过文件系统中的exec.c,将映象复制到tsk结构中。两种方法都需要调用new_page_tables 为新进程分配页目录表。6、static inline void copy_one_pte(pte_t * old_pte, pte_t * new_pte, int cow)将原 pte 页表项复制到 new_pte 上,其流程如下:1. 检测old_pte是否在内存中,如不在物理内存中,调用swap_duplicate按old_pte在 swap file中的入口地址,将old_pte复制到内存中,同时把old_pte的入口地址赋给 new_pte 并返回。反之转向 3。2. 获取 old_pte 对应的物理地址的页号。3. 根据页号判断old_pte是否为系统保留的,如果为系统保留的,这些页为所有的进 程在核心态下使用,用户进程没有写的权利,则只需将 old_pte 指针直接转赋给 new_pte 后返回。反之则该 pte 属于普通内存的,则转向 4。4. 根据传入的 C-O-W 标志,为 old_pte 置写保护标志,如果该页是从 swap_cache 中 得来的,将old_pte页置上“dirty”标志。将old_pte赋值给new_pte。5. 将 mem_map 结构中关于物理内存使用进程的个数的数值 count 加 1。7、static inline int copy_pte_range(pmd_t *dst_pmd, pmd_t *src_pmd,unsigned long address, unsigned long size, int cow)通过循环调用 copy_one_pte 将从源 src_pmd 中以地址 address 开始的长度为 size 的空间 复制给 dst_pmd 中。如 dst_pmd 中还未分配地址为 address 的页表项,则先给三级页表 pte 表分配 4K 空间。(每调用一次 copy_one_pte 复制 4K 空间。在一次 copy_pte_range 中最多 可复制4M空间)。8、static inline int copy_pmd_range(pgd_t *dst_pgd, pgd_t *src_pgd,unsigned long address, unsigned long size, int cow)通过循环调用 copy_pte_range 将从源 src_pgd 中以地址 address 开始的长度为 size 的空 间复制给dst_pgd中。如dst_pgd中还未分配地址为address的页表项,则在一级(同时也是 二级)页表中给对应的pmd分配目录项。9、int copy_page_range(struct mm_struct *dst, struct mm_struct *src,struct vm_area_struct *vma)该函数的主要功能是将某个任务或进程的vma块复制给另一个任务或进程。其工作机 制是循环调用copy_pmd_range,将vma块中的所有虚拟空间复制到对应的虚拟空间中。在 做复制之前,必须确保新任务对应的被复制的虚拟空间中必须都为零。 copy_page_range 按 dup_mmap()-copy_mm()-do_fork()的顺序被调用(以上三个函数均在kernel/fork.c中)。当 进程被创建的时候,需要从父进程处复制所有的虚拟空间, copy_page_range 完成的就是这 个任务。copy_page_range的函数调用关系见图8。图 8 copy_page_range 示意图9、static inline void free_pte(pte_t page)虚存页 page 如在内存中,且不为系统的保留内存,调用 free_page 将其释放掉(如在系 统保留区中,则为全系统共享,故不能删除)。如page在swap file中,调用swap_free()将其释放。10、static inline void forget_pte(pte_t page)如 page 不为空,调用 free_pte 将其释放。11、static inline void zap_pte_range(pmd_t * pmd, unsigned long address,unsigned long size)zap为zero all pages的缩写。该函数的作用是将在pmd中从虚拟地址address开始,长 度为size的内存块通过循环调用pte_clear将其页表项清零,调用free_pte将所含空间中的 物理内存或交换空间中的虚存页释放掉。在释放之前,必须检查从address开始长度为size 的内存块有无越过PMD_SIZE.(溢出则可使指针逃出01023的区间)。12、static inline void zap_pmd_range(pgd_t * dir, unsigned long address, unsigned long size)函数结构与 zap_pte_range 类似,通过调用 zap_pte_range 完成对所有落在 address 到 address+size区间中的所有pte的清零工作。zap_pmd_range至多清除4M空间的物理内存。13、int zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size)函数结构与前两个函数类似。将任务从 address 开始到 address+size 长度内的所有对应的pmd都清零。zap_page_range的调用关系与被调用的关系如图9可知。zap_page_range的 主要功能是在进行内存收缩、释放内存、退出虚存映射或移动页表的过程中,将不在使用 的物理内存从进程的三级页表中清除。(在讨论 clear_page_tables 时,就提到过当进程退出 时,释放页表之前,先保证将页表对应项清零,保证在处于退出状态时,进程不占用03G 的空间。)free_pagezap_page_rangezap_pmd_range图 9 zap_page_range 调用关系示意图14、static inline void zeromap_pte_range(pte_t * pte, unsigned long address,unsigned long size, pte_t zero_pte)15、static inline int zeromap_pmd_range(pmd_t * pmd, unsigned long address,unsigned long size, pte_t zero_pte)16、int zeromap_page_range(unsigned long address, unsigned long size, pgprot_t prot) 这三个函数与前面的三个函数从结构上看很相似,他们的功能是将虚拟空间中从地址 address 开始,长度为 size 的内存块所对应的物理内存都释放掉,同时将指向这些区域的 pte 都指向系统中专门开出的长度为4K,全为0的物理页。zeromap_page_range在kernel代码 中没有被引用,这个函数是旧版本的Linux遗留下来的,在新版本中已经被zap_page_range 所替代。17、static inline void remap_pte_range(pte_t * pte, unsigned long address, unsigned long size,unsigned long offset, pgprot_t prot)18、static inline int remap_pmd_range(pmd_t * pmd, unsigned long address, unsigned long size,unsigned long offset, pgprot_t prot)19、int remap_page_range(unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot)这三个函数也同前面的函数一样,层层调用,现仅介绍一下最后一个函数的作用。 remap_page_range 的功能是将原先被映射到虚拟内存地址 from 处的,大小为 size 的虚拟内 存块映射到以偏移量offset为起始地址的虚拟内存中,同时将原来的pte、pmd项都清零。 该函数也是逐级调用,在remap_pte_range中,通过set_pte将的物理页映射到新的虚拟内存 页表项pte上。remap_page_range函数的功能与下文中的remap.c中介绍的功能相近,因此 在 kernel 中也没有用到。20、unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page,unsigned long address)将虚拟内存页page链接到任务tsk中虚拟地址为address的虚拟内存中,其主要调用的 流程如下:put_dirty_page-setup_arg_page-dooad_xxx_binary(xxx 为 aout 或 elf, 这些函 数都在fsexec.c中),它的功能是将在载入可执行文件的时候,将其相关的堆栈信息、环境 变量等复制到当前进程的空间上。21、void handle_mm_fault(struct vm_area_struct * vma, unsigned long address,int write_access)用于处理ALPHA机中的缺页中断mmap.c在 mmap.c 中,主要提供了对进程内存管理进行支持的函数,主要包括了do_mmap 、do_munmap 等对进程的虚拟块堆 avl 数进行管理的函数。图 10 mmap.c 中函数调用图有关avl树的一些操作:1、static inline void avl_neighbours (struct vm_area_struct * node, struct vm_area_struct * tree, struct vm_area_struct * to_the_left, struct vm_area_struct * to_the_right)寻找 avl 树 tree 中的节点 node 的前序节点和后序节点,将结果放在指针 to_the_left 和 to_the_right 中,即使得*to_theeft-next=node, node-next=*to_the_right。在实际搜索中, 过程是找到 node 节点中的左节点的最右节点和右节点的最左节点,采用 avl 树搜索可以提 高效率。2、static inline void avl_rebalance (struct vm_area_struct * nodeplaces_ptr, int count) 将由于插入操作或删除操作而造成不平衡的 avl 树恢复成平衡状态。 nodeplaces_ptr 是 指向的是需要调整的子树的根节点, count 是该子树的高度。3、static inline void avl_insert (struct vm_area_struct * new_node,struct vm_area_struct * ptree)将新节点 new_node 插入 avl 树 ptree 中,并将该树重新生成平衡 avl 树。在创建 avl 树 时,将 vma 模块不断的插入 avl 树中,构建一个大的 avl 树。当进程创建时,复制父进程后 需要将以双向链表拷贝过来的vma链生成avl树。4、static inline void avl_insert_neighbours (struct vm_area_struct * new_node, struct vm_area_struct * ptree, struct vm_area_struct * to_the_left, struct vm_area_struct * to_the_right)将新节点 new_node 插入 avl 树 ptree 中,并将该树重新生成平衡 avl 树,同时返回该新 节点的前序节点和后序节点。5、static inline void avl_remove (struct vm_area_struct * node_to_delete, struct vm_area_struct * ptree)将指定要删除的节点 node_to_delete 从 avl 树 ptree 中删除。并将该树重新生成平衡 avl 树。该函数在释放虚存空间和归并vma链表是使用。7、static void printk_list (struct vm_area_struct * vma)8、static void printk_avl (struct vm_area_struct * tree)9、static void avl_checkheights (struct vm_area_struct * tree)10、static void avl_checkleft (struct vm_area_struct * tree, vm_avl_key_t key)11、static void avl_checkright (struct vm_area_struct * tree, vm_avl_key_t key)12、static void avl_checkorder (struct vm_area_struct * tree)13、static void avl_check (struct task_struct * task, char *caller)这些函数都是系统调试时用以检测avl树结构的正确性14、static inline int vm_enough_memory(long pages)通过计算当前系统中所剩的空间判断是否足够调用。可使用的内存包括缓冲存储器、 页缓存、主存中的空闲页、swap缓存等。15、static inline unsigned long vm_flags(unsigned long prot, unsigned long flags) 提供宏功能将页的保护位和标志位合并起来。16、unsigned long get_unmapped_area(unsigned long addr, unsigned long len)从虚拟内存address开始找到未分配的连续空间大于len的虚拟空间块,并将该快的首 地址返回。17、unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,unsigned long prot, unsigned long flags, unsigned long off)do_mmap 在 Linux 虚拟内存管理中是一个很重要的函数,它的主要功能是将可执行文 件的映象映射到虚拟内存中,或将别的进程中的内存信息映射到该进程的虚拟空间中。并 将映射了的虚拟块的vma加入到该进程的vma avl树中。其运行的流程如下,更详细的分析 请参阅林涛同学和徐玫峰同学的报告。检验给定的映射长度len是大于1页,小于一个任务的最大长度3G且加上进程的加上 偏移量 off 不会溢出。如不满足则退出。1. 如果当前任务的内存是上锁的,检验加上len后是否会超过当前进程上锁长度的界 限。如是则退出。2. 如果从文件映射,检验文件是否有读的权限。如无在退出。3. 调用 get_unmaped 取得从地址 address 开始未映射的连续虚拟空间大于 len 的虚存 块。4. 如从文件映射,保证该文件控制块有相应的映射操作。5. 为映射组织该区域申请 vma 结构。6. 调用vm_enough_memory有足够的内存。如无则释放6中申请的vma,退出。7. 如果是文件映射,调用 file-f_op_mmap 将该文件映射
展开阅读全文
相关资源
相关搜索

最新文档


当前位置:首页 > 办公文档 > 活动策划


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!