【问题标题】:How to service page faults for shared files/regions如何处理共享文件/区域的页面错误
【发布时间】:2018-10-03 08:53:59
【问题描述】:
  • 2 个进程; P1、P2,在按需分页环境中
  • 两者都将文件区域 F 映射到其虚拟地址空间的区域(注意:虚拟地址空间的区域可能不同),以只读方式(例如,P1 和 P2 可能都执行相同的可执行文件,或者映射在同一个DLL中,F可以对应.text段)
  • P1 首先从该内存请求加载,导致页面错误。 OS 在区域映射中查找故障地址,看到 F 映射到该区域,找到要使用的帧,并将 F 的必要块读入该帧,然后更新 P1s 页表结构。

现在,当 P2 请求从同一内存加载(例如,在共享 DLL 中执行同一例程)时会发生什么? P2 肯定会在首次访问时出现页面错误;但是,操作系统如何知道数据已经存在于内存中,并且 P2s 页表结构应该更新为指向该已驻留的页框?

我唯一的结论是,操作系统必须维护一个全局结构来跟踪每个活动的文件映射区域:哪些部分驻留在内存中,以及它们驻留在哪些帧中。

作为一个具体的参考点,了解它在 Linux 或 Windows 下的工作原理会很棒。

【问题讨论】:

  • 在 Windows 中,最初两个进程 PTE 指向一个公共原型 PTE。该故障更新原型 PTE 以引用物理内存中页面的 PFN(页框号)数据库条目。 PFN 条目依次更新以指向原型 PTE。随后,可以通过从原型 PTE 获取 PFN 条目引用来使过程 PTE 有效。
  • 操作系统会跟踪内核维护的数据库中哪些文件被打开以及哪些进程被打开。此外,它随时跟踪每个打开文件的哪些部分映射到哪些页框,以及哪些进程的哪些虚拟页映射到页框。内核使用一大堆结构来维护所有这些信息。存在与权限和共享相关的复杂情况。基本上,当一个进程试图映射一个文件时,操作系统会检查请求部分是否已经在内存中,并在这种情况下使用相同的帧。
  • 我看不出这与进程中的映射地址范围有什么关系。当共享内存(图像/数据映射)的 PTE 条目在进程中有效时,它直接指向页面的 PFN 数据库条目。当 PTE 无效时,它会改为指向原型 PTE,并使用来自该通用原型 PTE 的信息处理故障。
  • @eryksun 经过一番思考,我删除了评论,因为无论如何都需要在页面边界上制作底层内存映射(4kb、2mb 或 1gb)。我需要阅读有关 PFN 数据库的更多信息。 FWIW,“指向”PFN 数据库条目的 PTE 似乎是用词不当。

标签: linux windows operating-system


【解决方案1】:

考虑 Linux 实现:

您所询问的内容是通过页面缓存维护的。如果保持简单:IO访问期间的每个文件页面首先被读入页面缓存(内存中缓存的文件数据) - 巧妙的哈希表。对文件的每一次进一步访问都是通过页面缓存完成的。更具体地说,使用以下方法:

page = find_get_page(mapping, index);

这里的映射 - 是指向 struct address_space 类型的指针

struct address_space { 
struct inode            *host;              /* owning inode */ 

index - 是文件中的块偏移量。

因此P2,知道文件(见inode和地址空间)和读取页面的偏移量将在页面错误时查询页面缓存。因为 P1 之前已经将页面放入页面缓存中,所以 P2 会找到它并将指针返回到适当的struct page,它已经从文件中读取了数据。

【讨论】:

  • 感谢您的回复。那么,在某个地方,Linux 维护了一个巨大的 (file, offset) -> page frame 的哈希表映射?因此,每个页面错误句柄首先查询这个?
  • 是的,请参阅 filemap_fault(最后一个内核源代码)函数。它从 pf 处理程序中调用以进行文件映射。
猜你喜欢
  • 1970-01-01
  • 2021-09-04
  • 2011-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-05
  • 1970-01-01
  • 2014-10-25
相关资源
最近更新 更多