Ядро Linux делает недействительными записи TLB - PullRequest
7 голосов
/ 05 декабря 2011

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

SRC = 0x20000000

  1. Запись вSRC (вызовите соответствующую страницу page1).
  2. Syscall для копирования SRC в 0x30000000 в процессе назначения.Теперь адрес процесса src 0x20000000 и адрес процесса назначения 0x30000000 указывают на одну и ту же страницу (page1).
  3. Запись чего-то другого, отличного от SRC (это должно вызвать ошибку страницы для обработки COW).Предположим, что адрес источника теперь указывает на page2.
  4. Syscall для копирования SRC в 0x30001000 в процессе назначения.

На этом этапе должны существовать две отдельные страницы: SRC 0x20000000 page2DST 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?

1 Ответ

9 голосов
/ 05 декабря 2011

Да, если вы делаете что-то, что изменяет таблицы страниц, вам нужно убедиться, что TLB признан недействительным, как требуется.

mmu_notifier_invalidate_range_start/end просто вызывают ловушки уведомлений MMU; эти перехватчики существуют только для того, чтобы другой код ядра мог быть сообщен, когда происходит аннулирование TLB. Единственные места, в которых установлены уведомители MMU - это

  • KVM (аппаратная виртуализация) использует их для обработки подкачки страниц; он должен знать о недействительности TLB хоста, чтобы синхронизировать виртуальный гостевой MMU с хостом.
  • GRU (драйвер для специализированного оборудования в огромных системах SGI) использует уведомители MMU для синхронизации таблиц сопоставления в оборудовании GRU с MMU ЦП.

Но практически в любом месте, где вы вызываете ловушки уведомлений MMU, вы должны также вызывать функции сброса TLB, если ядро ​​еще не делает это для вас.

...