序文
Linux プロセスのメカニズムに詳しい人なら、Linux の新しいプロセスが fork + exec の形式で作成されるプロセスであることを知っています。
fork の場合、親プロセスの関連データ構造がコピーされ、実行されるバイナリが更新されて実行されます。
その後、親プロセスと子プロセス間のメモリ管理はコピーオンライトに基づいて行われます。
ある物理ページについては、フォーク後、メモリを読み取り専用にし、書き込み要求が発生すると物理ページをコピーして操作を実行します。
テストケース
使用例は主に、スペースの一部を申請し、それを aaa に設定することです。
次にフォークすると、単一プロセスが親子プロセスになり、親プロセスはスペースを bbbb に設定し、子プロセスはスペースを ccccc に設定します。
上記の牛をデバッグするプロセスは次のとおりです。
#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
void processHandler(int pid, char *p1, char *processName) {
printf(" %s - %d, p1 : 0x%x, %s \n", processName, pid, p1, p1);
}
int main(int argc, char **argv) {
char *p1 = (char *) malloc(20);
memset(p1, 'a', 16);
printf(" %s - %d, p1 : 0x%x, %s \n", "parent", getpid(), p1, p1);
int childPid = fork();
sleep(rand() % 5);
if (childPid == 0) {
memset(p1, 'b', 16);
processHandler(getpid(), p1, "child1");
} else {
memset(p1, 'c', 16);
processHandler(getpid(), p1, "parent");
}
}
牛 親プロセスと子プロセスのページ テーブル エントリが読み取り専用に設定されている
まず ASLR を無効にします。この比較的小規模なケースでは、malloc が brk を呼び出して最初のブロック スペースを適用します。最初のアドレスは 0x602000 になります。
親プロセスと子プロセスのページテーブルエントリを読み取り専用に設定する場所はここです
copy_pte_range でこの vma の範囲を確認できます。[6299648 - 6434816] は [0x602000 - 0x6230000] です。malloc が適用したスペースはこの vma に属しています
親プロセス/子プロセスが対応するページのコンテンツを変更すると、cow は物理ページをコピーします。
ここでの現在のルールによれば、1 回の実行で 2 つのプロセスが生成され、他のプロセスは生成されません。
親プロセスは奇数、子プロセスは偶数です
ここでは、親/子プロセスが [0x602000 - 0x6230000] が配置されている領域を変更しようとし、その後、カーネルの関連処理が行われます。
変更するプロセスは、まず元の物理ページをコピーして読み取りおよび書き込み可能に設定し、その後、対応するプロセスが指定された物理ページを操作します。
変更後のプロセスでは、現在のプロセスのみが物理ページを使用できることがわかり、物理ページを直接再利用します。
物理ページのコピーは kmap_atomic + memcpy に基づいています
ここでの最初の操作のプロセス番号は 313 で、これは親プロセスに対応します。
変更後のプロセスでは、現在のプロセスのみが物理ページを使用できることがわかり、物理ページを直接再利用します。
(initramfs) ./Test23MemoryCowChildFirst
parent - 313, p1 : 0x602010, aaaaaaaaaaaaaaaa
child1 - 314, p1 : 0x602010, bbbbbbbbbbbbbbbb
parent - 313, p1 : 0x602010, cccccccccccccccc
ここでの最初の操作は、子プロセスが対応する読み取り専用ページを最初に変更するときです。
(initramfs) ./Test23MemoryCowChildFirst
parent - 319, p1 : 0x602010, aaaaaaaaaaaaaaaa
child1 - 320, p1 : 0x602010, bbbbbbbbbbbbbbbb
parent - 319, p1 : 0x602010, cccccccccccccccc
以上