En el kernel de Linux, escribí código que se asemeja a copy_page_range
(mm/memory.c) para copiar memoria de un proceso a otro con optimización COW. Las direcciones de origen y destino pueden ser compensadas por PAGE_SIZE
y COW aún funciona. Noté, sin embargo, que en un programa de usuario cuando copio desde la misma dirección de origen a diferentes direcciones de destino, el TLB no parece ser lavado correctamente. En un nivel alto, mi código de nivel de usuario hace lo siguiente (copio exactamente una página, 0x1000 bytes en mi máquina, a la vez):Linux Kernel Invalidating TLB Entries
SRC = 0x20000000
- Escribir al SRC (llamar al asociado página
page1
). - Syscall para copiar SRC en 0x30000000 en el proceso de destino. Ahora, la dirección del proceso src 0x20000000 y la dirección del proceso de destino 0x30000000 apuntan a la misma página (
page1
). - Escriba algo diferente a SRC (esto debería desencadenar un error de página para manejar el COW). Supongamos que la dirección de origen ahora apunta al
page2
. - Syscall para copiar SRC en 0x30001000 en el proceso de destino.
En este punto, deben existir dos páginas separadas: SRC 0x20000000 page2
DST 0x30000000 page1
DST 0x30001000 page2
Me parece que en el paso 3, cuando escribo algo diferente en src 0x20000000, no hay página la falla se genera. Tras la inspección, las asignaciones de página reales son: SRC 0x20000000 page1
DST 0x30000000 page1
DST 0x30001000 page1
En mi código, si llamo flush_tlb_page
y pasar la dirección de origen, funciona el código de usuario como se esperaba con las asignaciones de página apropiados . Así que estoy convencido de que no estoy manteniendo correctamente el TLB. En copy_page_range
, el kernel llama a mmu_notifier_invalidate_range_start/end
antes y después de que altera las tablas de páginas. Estoy haciendo exactamente lo mismo y he verificado que estoy pasando las direcciones y struct_mm correctas al mmu_notifier_invalidate_range_start/end
. ¿Esta función no maneja el enjuague del tlb?
Ok, por lo que, literalmente, al terminar de escribir esto, he comprobado dup_mmap
y se dio cuenta de que la persona que llama primaria de copy_page_range
, dup_mmap
(kernel/fork.c), llama a flush_tlb_mm
. Supongo que debo llamar al flush_cache_range
y al flush_tlb_range
antes y después de mi código del kernel. ¿Es esto correcto? ¿Qué hace exactamente mmu_notifier_invalidate_range_start/end
?
¿Puedes explicar un poco sobre mmu_notifiers? Estoy atascado en si estos ganchos son utilizados solo por kernel para informar kvm/vmm o viceversa también es cierto? si estos ganchos se usan para todas las páginas o solo aquellas que VMM utiliza. Si es así, ¿cómo están registrados? – shami