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ルートアクセスが必要です。また、ファイルは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  ................
...

上記の出力は私のシェルプロセスからのみ来たものです。プロセスのメモリ全体のマップであるため、多くの出力があります。現在マップされていないすべての部品には0のみが含まれています。

c85e 0600 0000 00a0リトルエンディアンシステム(xxd出力の0x2120)のページを例にとり、a000 0000 0006 5ec8最初のバイトが0xa0なのでビット63がセットされてRAMのページになります。ビット番号は0から始まるため、ビット63は最後のビットです(ビット64ではありません)。最後の54ビットは、実際のページのインデックスである0x65ec8(前に0がたくさんあります)です。

これでページ2844 0500 0000 0081(xxd出力の0x3650)をに戻すことができます8100 0000 0005 4428。最初のバイトはビット62がセットされた0x81なので、SWAPのページです。なぜビット56がセットされているのか分かりません。文書化されていないコンテンツ、または人側のエラー(ビット55に注意)がある可能性があります。それにもかかわらず、ビット54-0は私たちに他のものを伝えます。 0x28は0x8のスワップタイプを提供します。オフセットは0x5442 >> 1(最後のビットがスワップタイプの一部であるため)0x2a21です。

(今回は符号/リトルエンディアン計算をめちゃくちゃにしないでほしいです。私がこの記事を初めて書いた時、確かにビット数をめちゃくちゃにしました。)

ページ処理の問題

上記の唯一の問題は、プロセス - >ページマッピングであることです。実際にはページ->プロセスではありません。ただし、/proc/kpagecount現在使用中のすべてのページ(1ページあたり64ビット整数の1つの別のリストである数が0より大きいすべてのページ)を表示するには、すべての項目を検索できます。次に、すべてのproc/<pid>ディレクトリを検索します。プロセスが起動しすぎて終了して見つからない場合/proc/<pid>でも、セキュリティポリシーまたは同様のポリシーを強制しない限り問題はありません。 (/proc状況が速すぎるため、セキュリティポリシーを決して信頼しないでください)。

追加

これで、64ビット整数の/proc/kpageflags0x54428インデックスを使用してページフラグを取得できます。0x54428thこれについても説明していますman 5 proc

関連情報