如何在Linux内核中找到具有页面的进程?

如何在Linux内核中找到具有页面的进程?

我正在开发一个关于Linux内核mm(内存管理)的项目,并且有一个页面,我需要找到该页面所属的进程。

但是,我找不到任何不修改内核的方法。所以,我真的想知道是否可以在不修改内核的情况下做到这一点。

详细来说,当我有一个VMA时,也可以将VMA转换成相应的页面,我想知道VMA或页面属于哪个进程。

例如,在mm/page_io.c(Linux内核源代码树)中:

    int __swap_writepage(struct page *page, struct writeback_control *wbc,
        void (*end_write_func)(struct bio *, int))
{
        struct bio *bio;
        int ret, rw = WRITE;
        struct swap_info_struct *sis = page_swap_info(page);
...
        ret = bdev_write_page(sis->bdev, swap_page_sector(page), page, wbc);
        if (!ret) {
                count_vm_event(PSWPOUT);

                /* I should figure out what process is having the page above.
                 * But it is hard to know, because page is managed in LRU and
                 * it is not directly related to its process. What hints I have
                 * are page struct and some data structures which I could
                 * infer from the page only.
                 */

我正在等待您的精彩答复。谢谢你!

答案1

进程内存页

@G-Man 是正确的,/proc文件系统可以为您提供信息。他也是正确的,/proc/<pid>/maps会提供一些信息。例如,这是一些/proc/<pid>/maps输出:

7f2c09a0c000-7f2c09a0d000 r--p 00022000 08:03 3804420                    /usr/lib/ld-2.24.so
7f2c09a0d000-7f2c09a0e000 rw-p 00023000 08:03 3804420                    /usr/lib/ld-2.24.so
7f2c09a0e000-7f2c09a0f000 rw-p 00000000 00:00 0 
7ffc46cf9000-7ffc46d1a000 rw-p 00000000 00:00 0                          [stack]
7ffc46d86000-7ffc46d88000 r--p 00000000 00:00 0                          [vvar]
7ffc46d88000-7ffc46d8a000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

这里的问题是,我们在此输出中获取了虚拟页面,但无法从那里找到与物理页面的关系。

另一方面,/proc还有一个/proc/<pid>/pagemap是虚拟内存到实际内存页(包括交换区)的映射。让我们看看它man 5 proc告诉我们什么:

/proc/[pid]/pagemap (since Linux 2.6.25)
       This  file  shows the mapping of each of the process's virtual pages into physical page frames or swap area.
       It contains one 64-bit value for each virtual page, with the bits set as follows:

            63     If set, the page is present in RAM.

            62     If set, the page is in swap space

            61 (since Linux 3.5)
                   The page is a file-mapped page or a shared anonymous page.

            60-56 (since Linux 3.11)
                   Zero

            55 (Since Linux 3.11)
                   PTE is soft-dirty (see the kernel source file Documentation/vm/soft-dirty.txt).

            54-0   If the page is present in RAM (bit 63), then these bits provide the page frame number, which can
                   be  used  to  index  /proc/kpageflags and /proc/kpagecount.  If the page is present in swap (bit
                   62), then bits 4-0 give the swap type, and bits 54-5 encode the swap offset.

好的,每个内存页都有一个 64 位整数,以及一堆告诉我们该页做什么的标志。要阅读/proc/<pid>/pagemap我们需要 root 权限。此外,该文件只是 64 位整数的列表,因此我将使用:

[~]# cat /proc/950/pagemap |xxd |less
...
000020c0: 0585 0600 0000 00a0 0285 0600 0000 00a0  ................
000020d0: 0385 0600 0000 00a0 6692 0600 0000 00a0  ........f.......
000020e0: 6792 0600 0000 00a0 488e 0600 0000 00a0  g.......H.......
000020f0: 498e 0600 0000 00a0 1c93 0600 0000 00a0  I...............
00002100: c45e 0600 0000 00a0 c55e 0600 0000 00a0  .^.......^......
00002110: c65e 0600 0000 00a0 c75e 0600 0000 00a0  .^.......^......
00002120: c85e 0600 0000 00a0 c95e 0600 0000 00a0  .^.......^......
00002130: ca5e 0600 0000 00a0 f05e 0600 0000 00a0  .^.......^......
00002140: f15e 0600 0000 00a0 f25e 0600 0000 00a0  .^.......^......
00002150: f35e 0600 0000 00a0 f45e 0600 0000 00a0  .^.......^......
00002160: f55e 0600 0000 00a0 f65e 0600 0000 00a0  .^.......^......
...
000035c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000035d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000035e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000035f0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00003600: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00003610: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00003620: 0000 0000 0000 0000 c460 0400 0000 0081  .........`......
00003630: f02a 0400 0000 0081 b6f7 0100 0000 0081  .*..............
00003640: 804b 0300 0000 0081 0770 0400 0000 0081  .K.......p......
00003650: 2844 0500 0000 0081 3d9b 0400 0000 0081  (D......=.......
00003660: 192f 0400 0000 0081 813c 0300 0000 0081  ./.......<......
00003670: b1f7 0100 0000 0081 40a7 0300 0000 0081  ........@.......
00003680: ee58 0400 0000 0081 97c8 0300 0000 0081  .X..............
00003690: 9afa 0100 0000 0081 0000 0000 0000 0000  ................
000036a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000036b0: 4d80 0400 0000 0081 0bb7 0400 0000 0081  M...............
000036c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
...

上面的输出仅来自我的 shell 进程。那里有很多输出,因为它是进程整个内存的映射。当前未映射的所有部分仅包含零。

c85e 0600 0000 00a0让我们以小端机器上的页面(位于 xxd 输出的 0x2120 处)为例,将其反转为a000 0000 0006 5ec8.由于第一个字节是 0xa0,因此位 63 被设置,因此它是 RAM 中的一个页面。位编号从零开始,因此位 63 是最后一位(不是位 64)。最后54位是0x65ec8(前面有一堆零),这是实际页面的索引。

现在,页面2844 0500 0000 0081(位于 xxd 输出的 0x3650 处)可以反转为8100 0000 0005 4428.第一个字节是 0x81,其位 62 被设置,因此它是 SWAP 中的页面。我不确定设置第 56 位的原因:可能是未记录的内容或该人的错误(注意到第 55 位)。尽管如此,第 54-0 位告诉我们其他事情:0x28 为我们提供了交换类型,即 0x8;偏移量位于0x5442 >> 1(因为最后一位是交换类型的一部分)即 0x2a21。

(我希望这次我没有搞砸标志/小尾数计算。我第一次写这篇文章时确实搞砸了位数。)

页面处理问题

上面的唯一问题是那是进程->页面的映射。并不是真正的页面->进程。但是您可以搜索 every/proc/kpagecount以查看当前使用的所有页面(计数 > 0 的所有页面,即每页一个 64 位整数的另一个列表)。然后搜索所有proc/<pid>目录。如果进程快速启动和结束以至于您无法找到它们的/proc/<pid>.但这并不重要,除非您试图执行安全策略或类似的策略。 (永远不要相信/proc安全策略,因为事情变化太快)。

额外的

现在你可以使用0x54428索引来搜索页面标志,其中/proc/kpageflags将是0x54428th64位整数。这在 中也有描述man 5 proc

相关内容