В ядре Linux я написал код, похожий на copy_page_range
(mm / memory.c), поэтому копируйте память из одного процесса в другой с помощью оптимизации COW.Адреса адресата и источника могут быть смещены на PAGE_SIZE
, и COW все еще работает.Однако я заметил, что в пользовательской программе, когда я копирую с одного и того же исходного адреса на разные адреса назначения, TLB, похоже, не очищается должным образом.На высоком уровне мой код уровня пользователя выполняет следующее (я копирую ровно одну страницу, 0x1000 байт на своем компьютере, за раз):
SRC = 0x20000000
- Запись вSRC (вызовите соответствующую страницу
page1
). - Syscall для копирования SRC в 0x30000000 в процессе назначения.Теперь адрес процесса src 0x20000000 и адрес процесса назначения 0x30000000 указывают на одну и ту же страницу (
page1
). - Запись чего-то другого, отличного от SRC (это должно вызвать ошибку страницы для обработки COW).Предположим, что адрес источника теперь указывает на
page2
. - Syscall для копирования SRC в 0x30001000 в процессе назначения.
На этом этапе должны существовать две отдельные страницы: SRC 0x20000000 page2
DST 0x30000000 page1
DST 0x30001000 page2
Я обнаружил, что на шаге 3, когда я записываю что-то другое в src 0x20000000, ошибка страницы не генерируется.После проверки фактические отображения страниц: SRC 0x20000000 page1
DST 0x30000000 page1
DST 0x30001000 page1
В моем коде, если я позвоню flush_tlb_page
и передам адрес источника, код пользователя работаеткак и ожидалось с правильными отображениями страниц.Поэтому я убежден, что неправильно поддерживаю TLB.В copy_page_range
ядро вызывает mmu_notifier_invalidate_range_start/end
до и после изменения таблиц страниц.Я делаю то же самое и дважды проверил, я действительно передаю правильный struct_mm и адреса в mmu_notifier_invalidate_range_start/end
.Разве эта функция не обрабатывает сброс tlb?
Хорошо, поэтому буквально, когда я закончил набирать это, я проверил dup_mmap
и понял, что основной вызывающий объект copy_page_range
, dup_mmap
(kernel / fork.c), звонки flush_tlb_mm
.Я предполагаю, что мне следует вызывать flush_cache_range
и flush_tlb_range
до и после кода моего ядра.Это правильно?Что именно делает mmu_notifier_invalidate_range_start/end
?