【问题标题】:What is in the PTE address field for an anonymously zero-fill-on-demand mapped page?匿名按需填零映射页面的 PTE 地址字段是什么?
【发布时间】:2022-01-02 12:13:31
【问题描述】:

当程序调用mmap 分配一个匿名页,也称为零需求页时,对应的页表项(PTE)的地址字段中出现了什么?我假设内核确实在物理内存中创建一个零初始化页面(并将该物理页面的页码输入PTE),直到请求进程实际接触该页面 - 因此术语需求为零。由于它不是磁盘地址,也不是 0(用于未分配的页面),所以那里会出现什么值?作为一个不同但相关的问题,内核如何“知道”该页面将作为零需求页面处理,即故障处理程序应该找到一个物理页面并将其初始化为 0 而不是从磁盘?

【问题讨论】:

  • 我不知道答案,但这完全取决于软件:一旦硬件看到页面已清除当前位,它就会忽略其他所有内容,因此地址字段可以包含内核的任何内容请 - 它不一定代表一个地址。尤其是在 64 位系统上,有大量可用位,因此可以使用一个来表示“请求零页面”。
  • 或者就此而言,内核可以完全忽略 PTE 内容,并维护一些其他数据结构,它可以在其中查找虚拟地址并查看应该如何处理它。我隐约记得 Linux 做了一些组合:一些相关数据在 PTE 中,一些在其他 vm 结构中。
  • 我认为您的第二个问题已由第一个回答:故障处理程序查看 PTE 和 vm 数据结构,并根据该信息看到此页面的需求为零- 此时它分配一个物理页面,更新 PTE 以指向该页面,刷新 TLB,并返回用户空间以恢复错误指令。
  • @Nate Eldredge——谢谢。是的,当然这取决于内核(但感谢为普通读者记录了这一点)——但我的问题来自 Bryant 和 O'Hallaron 对 Linux 页表的描述,其中地址字段是物理页码(如果页面存在于内存中),磁盘地址(如果不存在,但页面已分配),或 0/NULL(如果页面未分配)——所以它们没有描述如果页面已分配,它有什么但不存在,也没有磁盘地址。

标签: linux-kernel virtual-memory page-tables zero-initialization demand-paging


【解决方案1】:

我假设内核不会在物理内存中创建零初始化页面

确实,通常是这种情况。除非有特殊情况,例如如果指定 MAP_POPULATE 来显式请求初始化页面(也称为“pre-fauting”)。

相应的页表条目(PTE)的地址字段中出现了什么?

mmap 之后,您甚至没有为页面分配 PTE(或者通常,您在任何页表级别都没有任何条目)。对于CPU而言,页面甚至不存在。如果您要遍历页表,您只会到达一个点(在任意级别),相应的条目被标记为“不存在”。

既然它不是磁盘地址,也不会是 0(用于未分配的页面),那么那里会出现什么值?

对于 CPU 而言,页面是未分配的。在第一个页面错误时,可能会发生两件事:

  1. 对于 read 页面错误,PTE 被更新为指向zero page:这是一个始终完全归零的特殊页面,并且由任何匿名的 PTE 指向系统中尚未修改的(需求为零)页面。
  2. 对于 write 页面错误,将分配一个实际的物理页面,并更新相应的 PTE 以指向其物理地址。

直接引用the documentation:

匿名内存或匿名映射表示不受文件系统支持的内存。此类映射是为程序的堆栈和堆隐式创建的,或者通过显式调用 mmap(2) 系统调用创建。通常,匿名映射只定义允许程序访问的虚拟内存区域。读取访问将导致创建一个页表条目,该条目引用一个用零填充的特殊物理页。当程序执行写入时,将分配一个常规物理页面来保存写入的数据。该页面将被标记为脏页面,如果内核决定重新使用它,脏页面将被换出。


内核如何“知道”该页面将作为零需求页面处理,即故障处理程序应该找到一个物理页面并将其初始化为 0,而不是从磁盘复制页面?

当页面错误发生时,内核页面错误处理程序(架构-依赖)确定页面属于哪个 VMA,并检索相应的struct vm_area_struct(由内核本身或通过mmap 系统调用)。然后将该结构与所需的故障信息 (struct vm_fault) 一起传递给架构独立代码 (do_fault())。

vm_area_struct 然后包含处理故障所需的所有剩余信息(例如,->vm_file 字段,如果是文件支持的映射,则为 != NULL)。字段->vm_ops 指向一个struct vm_operations_struct,它定义了一组函数指针以在不同场合调用。特别是匿名 VMA 有->vm_ops == NULL

对于其他类型的页面,->fault() 是处理页面错误时使用的函数。该函数知道要检查什么以及如何实际处理故障。

B & O 也描述了 VMA,但没有解释内核如何使用 VMA 来区分未分配页面和要创建和零初始化的已分配页面。

简单,只需检查vma->vm_ops == NULL,在这种情况下,您就知道该页面是零需求匿名页面。然后在页面错误上根据需要采取行动(读取错误 -> 更新 PTE 以指向全局零页面,写入错误 -> 分配页面并更新 PTE)。

【讨论】:

  • 好的,谢谢。有关我的问题的背景,请参阅我对@Nate Eldredge 的回复。 Bryant 和 O'Hallaron 的说法听起来好像只有三种可能性,都是由 PTE 决定的:(1)页面存在,所以地址是内存中的页码; (2) 页面不存在,PTE 有地址,所以那一定是磁盘地址,缺页处理程序应该在内存中找到一个位置来复制它,复制它,然后将新地址输入到 PTE ;或者(3)页不存在,地址为NULL,所以页必须是未分配的。
  • B & O 也描述了 VMA,但没有解释内核如何使用 VMA 来区分未分配页面和要创建和零初始化的已分配页面。跨度>
  • @AmittaiAviram 检查我的更新答案
猜你喜欢
  • 2017-07-17
  • 1970-01-01
  • 2014-09-05
  • 1970-01-01
  • 1970-01-01
  • 2018-07-29
  • 2013-07-06
  • 1970-01-01
  • 2013-10-20
相关资源
最近更新 更多