Linuxカーネルでは、copy_page_range
(mm / memory.c)に似たコードを記述したため、COW最適化を使用してあるプロセスから別のプロセスにメモリをコピーします。宛先アドレスと送信元アドレスはによってオフセットすることができPAGE_SIZE
、COWは引き続き機能します。ただし、ユーザープログラムで、同じ送信元アドレスから別の宛先アドレスにコピーすると、TLBが適切にフラッシュされていないように見えることに気付きました。高レベルでは、ユーザーレベルのコードは次のことを行います(一度に1ページ、0x1000バイトをマシンにコピーします)。
SRC = 0x20000000
- SRCに書き込みます(関連するページを呼び出します
page1
)。 - 宛先プロセスでSRCを0x30000000にコピーするSyscall。これで、srcプロセスアドレス0x20000000と宛先プロセスアドレス0x30000000が同じページを指します(
page1
)。 - SRCとは異なるものを記述します(これにより、COWを処理するためのページフォールトがトリガーされます)。送信元アドレスがを指していると仮定し
page2
ます。 - 宛先プロセスでSRCを0x30001000にコピーするシステムコール。
この時点で、2つの別々のページが存在する必要があります。SRC0x20000000 page2
DST 0x30000000 page1
DST 0x30001000page2
手順3で、src 0x20000000に別の何かを書き込んでも、ページフォールトは生成されないことがわかりました。検査すると、実際のページマッピングは次のようになります。SRC0x20000000 page1
DST 0x30000000 page1
DST 0x30001000page1
私のコードではflush_tlb_page
、送信元アドレスを呼び出して渡すと、ユーザーコードは適切なページマッピングで期待どおりに機能します。したがって、TLBを正しく維持していないと確信しています。ではcopy_page_range
、カーネルはmmu_notifier_invalidate_range_start/end
ページテーブルを変更する前後に呼び出します。私はまったく同じことをしていて、実際に正しいstruct_mmとアドレスをに渡していることを再確認しましたmmu_notifier_invalidate_range_start/end
。この関数はtlbのフラッシュを処理しませんか?
さて、文字通りこれを入力し終えたとき、私はチェックして、dup_mmap
の主要な呼び出し元(kernel / fork.c)が。を呼び出すことに気づきました。カーネルコードの前後に呼び出す必要があると思います。これは正しいです?正確には何をしますか?copy_page_range
dup_mmap
flush_tlb_mm
flush_cache_range
flush_tlb_range
mmu_notifier_invalidate_range_start/end