linux内核之存储管理二

  
几个重要的数据结构和函数
从硬件的角度来说, Linux 内核只要能为硬件准备好页面目录 PGD 、页面表 PT 以及全局段描述表 GDT 和局部描述表 LDT, 并正确设置有关的寄存器,就完成了内存管理机制中地址映射部分的准备工作。虽然最终的目的是地址映射,但是实际上内核所需要做的管理工作却要复杂得多。在与内存管理有关的内核代码中,有几个数据结构是很重要的,这些数据结构及其使用构成了代码中内存管理的基本框架。
页面目录 PGD 、中间目录 PMD 和页面表 PT 分别是由表项 pgd_t pmd_t 、以及 pte_t 构成的数组,而这些表项又都是数据结构。
内核中有个全局量 mem_map , 是一个指针,指向一个 page 数据结构的数组,每个 page 数据结构代表一个物理页面,真个数组就代表着系统中的全部物理页面。因此,页面表项的高 20 位对于软件和 MMU 硬件又着不同的意义。对于软件,这是一个物理页面的序号,将这个序号用做下标就可以从 mem_map 找到代表这个物理页面的 page 数据结构。对于硬件,则(在低位补上 12 0 后)就是物理页面的起始地址。还有一个常用的宏操作 set_pte() , 用来把一个表项的值设置到一个页面表项中。
在映射的过程中, MMU 首先检查的是 P 标志位,就是 _PAGE_PRESENT ,它指示着所映射的页面是否在内存中。只有在 P 标志位为 1 的时候 MMU 才会完成映射的全过程;否则就会因不能完成映射而产生一次缺页异常,此时表项中的其他内容对 MMU 就没有什么意义了。除 MMU 硬件根据页面表项的内容进行页面映射外,软件页可以设置或检测页面表项的内容,上面的 set_pte() 就是用来设置页面表项。内核中还为检测页面表项的内容定义了一些工具性的函数或宏操作。
对软件来说,页面表项为 0 表示尚未为这个表项(所代表的虚存页面)建立映射,所以还是空白;而如果页面表项不为 0 ,但 P 标志位为 0 ,则表示映射以及建立,但是所映射的物理页面不在内存中(已经换出到交换设备上)。
系统中的每个物理页面都又一个 page 结构(或 mem_map_t )。系统在初始化时根据物理内存的大小建立起一个 page 结构数组 mem_map, 作为物理页面的“仓库”,里面的每个 page 数据结构都代表着系统中的一个物理页面。每个物理页面的 page 结构在这个数组离的下标就是该物理页面的序号。“仓库”里的物理页面划分成 ZONE_HIGHMEM, ZONE_NORMA 两个管理区(根据系统配置还可以有第三个管理区 ZONE_HIGHMEM, 用于物理地址超过 1GB 的存储空间)。
管理区 ZONE_DMA 里的页面是专供 DMA 使用的。为什么供 DMA 使用的页面要单独加以管理呢?首先, DMA 使用的页面是磁盘 I/O 所必需的,如果把仓库中所有的物理页面都分配光了,那就无法进行页面与盘区的交换了。此外,还有特殊的原因。在 i386CPU 中,页式存储管理的硬件支持是在 CPU 内部实现的,而不像另有些 CPU 那样由一个单独的 MMU 提供,所以 DMA 不经过 MMU 提供的地址映射。这样,外部设备就要直接提供访问物理页面的地址,可是有些外设(特别是插在 ISA 总线上的外设接口卡)在这方面往往有些限制,要求用于 DMA 的物理地址不能过高。另一方面,正因为 DMA 不经过 MMU 提供的地址映射,当 DMA 所需的缓冲区超过一个物理页面的大小时,就要求两个页面在物理上连续,因为此时 DMA 控制器不能依靠在 CPU 内部的 MMU 将连续的虚存页面映射到物理上不连续的页面。所以,用于 DMA 的物理页面是要单独管理的。
每个管理区都有一个数据结构,即 zone_struct 数据结构。在 zone_struct 数据结构中有一组“空闲区间”( free_area_t )队列。为什么是“一组”队列,而不是“一个”队列呢?这也是因为常常需要成“块”地分配在物理空间内连续的多个页面,所以要按块的大小分别加以管理。因此,在管理区数据结构中既要有一个队列保持一些离散的物理页面,还要有一个队列来保持一些连续长度为 2 的页面块已经连续长度为 4 8 16 ….. 、直至 2MAX_ORDER 的页面块。常数 MAX_ORDER 定义为 10 ,也就是说最大的连续页面块可以达到 210 1024 个页面 , 4M 字节。
在传统的计算机结构中,整个物理空间都是均匀一致的, CPU 访问这个空间中的认可一个地址所需的时间都相同,所以称为“均匀存储结构”,简称 UMA 。可是,在一些新的系统结构中,特别是在多 CPU 结构的稀土女冠中,物理春出空间在这方面的一致性却成了问题。试想有这么一种结构:
系统的中心是一条总线,例如 PCT 总线。
有多个 CPU 模块连接在系统总线上,每个 CPU 模块都有本地的物理内存,
但是也可以通过系统总线访问其它 CPU 模块的内存。
系统总线上还连接着一个共用的存储模块,所有的 CPU 模块都可以通过系统总线访问它。
所有这些物理内存的地址互相连续而形成一个连续的物理地址空间。
显然,就某个特定的 CPU 而言,访问其本地的存储器是速度最快的,而穿过系统总线访问共用存储模块或其它 CPU 模块上的存储器就比较慢,而且还面临因可能的竞争而引起的不确定性。也就是说,在这样的系统中,其物理存储空间虽然地址连续,“质地”却不一致,所以称为“非均质存储结构”,简称 NUMA 。在 NUMA 结构的系统中分配连续的若干物理页面时一般都要求分配在质地相同的区间(称为 node, 即“节点”)。
事实上,严格意义上的 UMA 结构几乎不存在的。就拿配置最简单的单 CPU PC 来说,其物理存储空间就包括 RAM ROM, 还有图形卡上的静态 RAM 。但是在 UMA 结构中,除“主存” RAM 以外的存储器都很效,所以把它们放在特殊的地址上称为小小的“孤岛”,再在编程时特别加以主页就可以了。然而,在典型的 NUMA 结构中就需要来自内核中内存管理机制的支持了。
由于 NUMA 结构的引入,对于上述的物理页面管理机制也作了相应的修正。管理区不在是属于最高层的机构,而是在每个存储节点中都有两个管理区。而且前述的 page 结构数组也不再是全局性的,而是从属于具体的节点了。从而,在 zone_struct 结构之上又有了另一层代表存储节点的 pglist_data 数据结构。
前面几个数据结构都是用于物理空间管理的,现在来看看虚拟空间的管理,也就是虚存页面的管理。虚存空间的管理不像物理空间的管理那样有一个总的物理页面仓库,而是以进程为基础的,每个进程都是各自的虚存(用户)空间。不过,如前所述,每个进程的“系统空间”是统一为所有进程所共享的。
如果说物理空间是从“供的角度”来管理的,也就是说:“仓库还有些什么”;则虚存空间的管理是从“需”的角度来管理的,就是“我们需要用虚存空间中的那些部分”。同时,一个进程所需要使用的虚存空间中的各个部位又未必是连续的,通常形成若干离散的虚存“区间”。很自然地,对虚存区间的抽象是一个重要的数据结构。在 Linux 内核中,这就 vm_area_struct 数据结构。在内核中用于这个数据结构的变量名常常是 vma
在两种情况下虚存页面(或区间)会跟磁盘文件发生关系。一种是盘区交换( swap , 当内存页面不够分配时,一些久未使用的页面可以被交换到磁盘上去,腾出物理页面以供更急需的进程使用,这就是大家所知道的一般意义上的“按需调度”页式虚存管理。另一种情况是将一个磁盘文件映射到一个进程的用户空间中。 Linux 提供了一个系统调用 mmap() ( 实际上是从 Unix SysVR4.2 开始的 ) ,使一个进程可以将一个已经打开的文件映射到其用户空间中,此后,就可以像访问内存中的一个字符数组那样来访问这个文件的内容,而不必通过 lseek() read() write() 等进行文件操作。
由于虚存区间与磁盘文件的这种联系,在 vm_area_struct 结构中相应地设置了一些成分,用以记录和管理此种联系。
虚存空间结构中另一个重要的成分是 vm_ops ,这是指向一个 vm_operation_struct 数据结构的指针。
最后, vm_area_struct 中还有一个指针 vm_mm , 该指针指向一个 mm_struct 数据结构,在内核代码中,用于这个数据结构(指针)的变量名常常是 mm
显然,这是在比 vm_area_struct 更高层上使用的数据结构。事实上,每个进程只有一个 mm_struct 结构,在每个进程的“进程控制快”,即 task_struct 结构中,又一个指针指向该进程的 mm_strcut 结构。可以说, mm_strcut 数据结构是进程整个用户空间的抽象,也是总的控制结构。结构中的头三个指针都是关于虚存区间的。第一个 mmap 用来建立一个虚存区间结构的单链线性队列。第二个 mmap_avl 用来建立一个虚存区间结构的 AVL 树。第三个指针 mmap_cache, 用来指向最近一次用到的那个虚存区间结构。
虽然一个进程只使用一个 mm_strcut 结构,反过来一个 mm_struct 结构却可能为多个进程共享。
在内核中经常用到这样的操作:给定一个属于某个进程的虚拟地址,要求找到其所属的区间已经相应的 vma_area_struct 结构。这是由 find_vma() 来实现。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值