Linux Kernel Invalidating TLB Entries

В ядре linux я написал код, похожий на copy_page_range (mm/memory.c), чтобы копировать память из одного процесса в другой с оптимизацией COW. Адреса назначения и источника могут быть смещены на PAGE_SIZE и COW все еще работает. Однако я заметил, что в пользовательской программе при копировании с одного и того же адреса источника на разные адреса назначения TLB не очищается должным образом. На высоком уровне мой пользовательский код делает следующее (я копирую ровно одну страницу, 0x1000 байт на моей машине, за раз):

SRC=0x20000000

  1. Запись в SRC (вызов связанной страницы page1).
  2. Вызов системы для копирования SRC в 0x30000000 в процессе назначения. Теперь адрес процесса src 0x20000000 и адрес процесса назначения 0x30000000 указывают на одну и ту же страницу (page1).
  3. Запишите что-нибудь другое в SRC (это должно вызвать страничный сбой для обработки COW). Предположим, что адрес источника теперь указывает на page2.
  4. Вызов системы для копирования 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?

7
задан Some programmer dude 5 December 2011 в 06:32
поделиться