软脏(soft-dirty)是一个位于 PTE(页表项)上的标志位,用于跟踪任务写入的哪些页面。为了进行这种跟踪,需要执行以下步骤:
- 清除任务的 PTE 中的软脏位。
这可以通过向相关任务的 /proc/PID/clear_refs 文件写入“4”来完成。 - 等待一段时间。
- 从 PTE 中读取软脏位。
这可以通过从 /proc/PID/pagemap 文件中读取数据来完成。64 位 qword 中的第 55 位是软脏位。如果设置了该位,表示自步骤 1 以来相应的 PTE 已被写入。
在内部实现中,当清除软脏位时,PTE 的可写位也会被清除。因此,在此之后,当任务尝试修改某个虚拟地址处的页面时,会触发页面故障(#PF),内核会在相应的 PTE 上设置软脏位。
需要注意的是,尽管在清除软脏位后,所有任务的地址空间都被标记为只读,但在此之后发生的页面故障会被快速处理。这是因为页面仍然映射到物理内存,因此内核只需发现这一事实,并在 PTE 上设置可写和软脏位。
虽然在大多数情况下,通过页面故障来跟踪内存变化已经足够,但仍存在一种情况会导致丢失软脏位,即任务取消映射先前映射的内存区域,然后在完全相同的位置映射一个新的内存区域。当调用取消映射时,内核会内部清除 PTE 值,包括软脏位。为了通知用户空间应用程序有关这种内存区域的更新,内核总是将新的内存区域(以及扩展的区域)标记为软脏。
这个功能被活跃地用于检查点恢复(checkpoint-restore)项目。您可以在 http://criu.org 上找到更多关于此功能的详细信息。
-- Pavel Emelyanov, 2013 年 4 月 9 日