W jądrze Linuxa napisałem kod przypominający copy_page_range
(mm/memory.c), dzięki czemu można skopiować pamięć z jednego procesu do drugiego dzięki optymalizacji COW. Adres docelowy i adres źródłowy mogą być przesunięte o PAGE_SIZE
, a COW nadal działa. Zauważyłem jednak, że w programie użytkownika podczas kopiowania z tego samego adresu źródłowego do różnych adresów docelowych, TLB nie wydaje się być poprawnie przepłukane. Na wysokim poziomie, mój kod poziom użytkownik wykonuje następujące (I skopiować dokładnie jedną stronę, 0x1000 bajtów na moim komputerze, w czasie):Jądro Linuxa Unieważniające wpisy TLB
src = 0x20000000
- Napisz do SRC (wezwanie powiązany strona
page1
). - Syscall do skopiowania kodu SRC do 0x30000000 w procesie docelowym. Teraz adres procesu src 0x20000000 i adres procesu docelowego 0x30000000 wskazują tę samą stronę (
page1
). - Napisz coś innego niż SRC (powinno to wywołać błąd strony, aby obsłużyć COW). Załóżmy, że adres źródłowy wskazuje teraz na
page2
. - Syscall do skopiowania kodu SRC do 0x30001000 w procesie docelowym.
W tym momencie dwie oddzielne strony powinny istnieć: SRC 0x20000000 page2
DST 0x30000000 page1
DST 0x30001000 page2
Uważam, że w etapie 3, gdy piszę coś innego do src 0x20000000, bez widoku błąd jest generowany. Po inspekcji, rzeczywiste mapowanie strona to: SRC 0x20000000 page1
DST 0x30000000 page1
DST 0x30001000 page1
W moim kodu, jeśli zadzwonię flush_tlb_page
i przekazać adres źródłowy, kod użytkownik działa zgodnie z oczekiwaniami z odpowiednich przekształceń stronie . Jestem więc przekonany, że nie utrzymuję TLB poprawnie. W kodzie copy_page_range
jądro wywołuje mmu_notifier_invalidate_range_start/end
przed i po zmianie tablic stron. Robię dokładnie to samo i dwukrotnie sprawdzam, czy rzeczywiście przekazuję poprawną strukturę struct_mm i adresy do mmu_notifier_invalidate_range_start/end
. Czy ta funkcja nie działa podczas przepłukiwania tlb?
Ok, tak dosłownie jak skończyłem pisanie tego, sprawdziłem dup_mmap
i zrozumiał, że podstawowym wywołujący copy_page_range
, dup_mmap
(kernel/fork.c), wzywa flush_tlb_mm
. Zgaduję, że powinienem zadzwonić pod flush_cache_range
i flush_tlb_range
przed i po moim kodzie jądra. Czy to jest poprawne? Co dokładnie robi mmu_notifier_invalidate_range_start/end
?
czy możesz wyjaśnić trochę o mmu_notifiers? Utknąłem na tym, czy te haczyki są używane tylko przez jądro do informowania kvm/vmm lub vice versa? czy te haki są używane dla wszystkich stron, czy tylko z tych stron, które są używane przez VMM. jeśli tak, w jaki sposób są one zarejestrowane? – shami