原文:https://www.kernel.org/doc/Documentation/vm/pagemap.txt

用户空间角度下的pagemap

pagemap是内核中的一组新的接口,允许用户空间的程序通过读取/proc下的文件来检查页表及相关信息

pagemap文件包括四个组件:

  • /proc/pid/pagemap 该文件可以使一个用户空间的进程找到每一个虚拟页面映射到哪个物理帧。它为每一个物理页面包含一个64位的值,该值包含以下数据:

    • 0-54位是页帧号(page frame number aka PFN) if present
      • 0-4位是交换类型(swap type) if swapped
      • 5-54位是交换偏移(swap offset) if swapped
    • 55位表示pte is soft-dirty
    • 56位表示完全映射页(page exclusively mapped)(从linux4.2开始)
    • 57-60位为0
    • 61位表示页是文件页(file-page)还是匿名共享(shared-anon)(从linux3.5开始)
    • 62位表示页被交换(swapped)
    • 63位表示页存在(present)

    从linux4.0开始,只有拥有CAP_SYS_ADMIN特权的用户才能得到PFN这些数据。在4.0和4.1版本如果无此特权打开该文件,会失败并返回-EPERM。从linux4.2开始,如果用户没有此特权的话,读取PFN会得到0。原因就是PFn等数据的信息会帮助漏洞的利用

    如果页不存在但是在交换区,PFN就会包含编码后的交换文件号以及该页在交换区的偏移。未被映射的页返回空的PFN,这样就能精确地确定映射(或交换)了哪些页面,并在进程之间比较映射的页面

    高效的用户使用这个接口的话,会先用/proc/pid/maps来确定内存的哪些区域被映射了,然后使用lseek去跳过未被映射的区域

  • /proc/kpagecount 该文件包含每个页被映射的次数,该次数是一个64位的数字,以PFN作为索引

  • /proc/kpageflags 该文件包含每个页的一组64位的flags,以PFN作为索引

    flags为:

  1. LOCKED
  2. ERROR
  3. REFERENCED
  4. UPTODATE
  5. DIRTY
  6. LRU
  7. ACTIVE
  8. SLAB
  9. WRITEBACK
  10. RECLAIM
  11. BUDDY
  12. MMAP
  13. ANON
  14. SWAPCACHE
  15. SWAPBACKED
  16. COMPOUND_HEAD
  17. COMPOUND_TAIL
  18. HUGE
  19. UNEVICTABLE
  20. HWPOISON
  21. NOPAGE
  22. KSM
  23. THP
  24. BALLOON
  25. ZERO_PAGE
  26. IDLE
  • /proc/kpagecgrope 该文件包含每个页面管理的内存的cgroup的64位inode编号,以PFN为索引,只在CONFIG_MEMCG被设置后才可用

对页标志的简短介绍:

  1. LOCKED页被锁定为独占访问,例如,正在经受read/write IO

  2. 当连续页(compound page)被使用的时候,SLAB页被SLAB/SLOB/SLUB/SLQB内核内存分配器管理

  3. BUDDY一个空闲的内存锁,由伙伴系统分配器管理。伙伴系统以各种顺序组织空闲内存。一个次序为N的块有$2^N$个物理上连续的页面,其中只有第一个页面设置了BUDDY标志

  4. COMPOUND_HEAD

  5. COMPOUND_TAIL一个次序为N的连续页(compound page)包含$2^N$个物理连续页。一个次序为2的连续页的形式为“HTTT”,H指它是头页,T表示它(它们)是尾页。连续页的只要消耗着是hugeTLB pageSLUB,例如,内存分配器不同的设备驱动器。然而在这个接口中,只有huge/giga pages能被end users看到。

  6. HUGE这是HugeTLB page的组成页面

  7. HWPOISON硬件在此页上检测内存损坏:不要触碰这里的数据!

  8. NOPAGE在请求的地址没有页帧存在

  9. KSM在一个或多个进程之间动态共享的相同内存页

  10. THP相连的用来构造透明的大页面的页面

  11. BALLOON ballon compaction page 涨大的压缩页面???

  12. ZERO_PAGE zero page for pfn_zero or huge_zero page

  13. IDLE页面从被标记为idle开始就没有被访问。需要注意的是,如果通过PTE访问该页面,此标志可能会过时。要确保该标志是最新的,必须先读取/sys/kernel/mm/page_idle/bitmap

    [ IO相关的页标志 ]

    1. ERROR IO错误已发生

    2. UPTODATE页面有最新数据

      ie. for file backed page: (in-memory data revision >= on-disk one)

    3. DIRTY页以及被写入,因此包含新数据

      ie. for file backed page: (in-memory data revision > on-disk one)

    4. WRITEBACK页已经被同步到硬盘

    5. LRU页在LRU lists之一之内

    6. ACTIVE页在active LRU list之内

  14. UNEVICTABLE页在unevictable (non-)LRU list之内

    它以某种方式固定,而不是LRU页面回收的候选

    1. REFERENCED自从上次LRU list入队/重新入对以来已经重新引用该页面
    2. RECLAIM页面输出IO完成后将立即回收该页面
  15. MMAP一个内存映射页

  16. ANON一个非文件的一部分的内存映射页

  17. SWAPCACHE页被映射到交换空间,例如,有一个相关的交换入口

  18. SWAPBACKED页由swap/RAM支持

The page-types tool in the tools/vm directory can be used to query the above flags.

pagemap做一些有用的事情:

使用pagemap查找进程的内存使用情况像是如下这样:

  1. 读取/proc/pid/maps来确定内存空间中的哪一部分映射到了什么
  2. 选择你需要的部分
  3. 打开/proc/pid/pagemap并找到想要检查的页面
  4. pagemap为每一页读取一个uint64
  5. 打开/proc/kpagecount和/或/proc/kpageflags。你所读取的每一个PFN,查找文件中的那个条目,并读取所需的数据

例如,为了找到"unique set size" (USS),即只被一个内存独享的内存的数量。你可以遍历进程中的每个映射,超导PFN,然后在kpagecount中查找他们,并计算仅被引用一次的页面的个数

注意事项:

如果没有从8字节的边界开始读取,或者读取的大小不是8的倍数,读任何文件都会返回-EINVAL

在linux3.11之前,pagemap55-60位被用作表示page-shift(在某些架构里总是12)。从Linux 3.11开始,它们的含义在先清除soft-dirty bits后才改变。 从Linux 4.2开始,它们无条件地用于标志。

soft-dirty

原文:https://www.kernel.org/doc/Documentation/vm/soft-dirty.txt

soft-dirtyPTE的一位,用来帮助跟踪任务写入的页面。为了完成跟踪,页面应该:

  1. 从任务的PTEs清除soft-dirty

  2. wait some time

  3. PTEs读取soft-dirty

    读取/proc/pid/pagemap来完成此任务,第55位就是soft-dirty位。如果设置此位,就从步骤1开始写入相应的PTE

在内部,为了进行跟踪,当soft-dirty位被清除时,可写位被从PTE中清除。因此,在此之后,当任务试图修改某个虚拟地址处的页面时,#PF会出现,内核会在相应的PTE上设置soft-dirty位。

请注意,尽管在清除soft-dirty位后,所有任务的地址空间都标记为r / o,但是在此之后发生的PF-s将被快速处理。 之所以如此,是因为页面仍被映射到物理内存,因此内核所做的一切就是找出这一事实,并将可写位和soft-dirty位都放在PTE上。

虽然在大多数情况下,通过#PF-s来跟踪内存更改已经足够了,但是仍然存在这样一种情况,即我们可能会丢失soft-dirty位——一个任务取消映射一个以前映射的内存区域,然后在完全相同的位置映射一个新的内存区域。当unmap被调用时,内核内部会清除包括软脏位在内的PTE值。为了将这种内存区域更新通知用户空间应用程序,内核总是将新的内存区域(和扩展的区域)标记为soft-dirty