Дедупликация страницы исполняемого кода драйверов OC Windows (1187398), страница 4
Текст из файла (страница 4)
Этот общий - "нулевой" набор страницсоздается при загрузке в систему первого драйвера, после того как происходитсканирование и выбор подходящий его страниц.Таким образом, сначала нужно объединить наборы страниц. См. Рис. 2.16Рис2. Слияние страниц при загрузке.Таким образом, драйвер перестает ссылаться на свои собственные страницы,которые возвращаются в систему, и начинает ссылаться на другие, представленныестраницами из общего набора. То есть происходит подмена страниц. Более подробномеханизм подмены страниц драйвера будет описан в пункте про Реализацию иКопирование при записи. Однако, уже здесь, следует уточнить, что речь идет офизических страницах памяти, а не об из виртуальных.
Виртуальные адреса страницдрайвера не изменяются. При подмене страниц нарушается связь между виртуальнымиадресами страниц драйвера и связанными с ними физическими страницами. Этифизические страницы возвращаются позже в систему, а виртуальные адреса начинаютссылаться на новые физические страницы. Таким образом, сам драйвер не замечаетпроизошедшую подмену.2.1.2.3.
Работа системыРассмотрим, как теперь происходит работа с драйвером.Поскольку драйвер не замечает произошедшую подмену страниц, он можетсвободно исполнять или читать их содержимое. Однако, поскольку теперь все экземплярыдрайвера ссылаются на один и тот же набор физических страниц, писать в эти страницы17нельзя. Потому что, запись сделанная одним экземпляром повлияет на работу всехостальных, что может привести к непредсказуемым последствиям.Следовательно, необходимо запретить драйверам писать в страницы из общегонабора.
Поскольку, иногда им все-таки может понадобиться совершить запись в своистраницы кода, необходимо использовать механизм копирования при записи.Рассмотрим на примере, см. Рис. 3. Итак, в системе находятся 2 драйвера, которыессылаются на общий набор физических страниц. Когда драйвер2 хочет произвести записьв какую-то из своих страниц, эта виртуальная страница, то есть ее виртуальный адрес,перестает ссылаться на физическую страницу из общего набора.
Вместе этого для этогодрайвера создается отдельная копия этой страницы, то есть новая физическая страница сидентичным содержимым, доступная только этому экземпляру драйвера. Остальные жеэкземпляры не замечают изменений.В процессе работы многие из экземпляров могут пытаться записать что-то своистраницы. В результате этого им будут выделяться отдельные копии. В итоге, в системебудет находиться один общий набор страниц для всех драйверов, и еще наборы страниц,"свои" для каждого драйвера - наборы тех страниц, в которые он совершил запись.Рис3.
"Отделение" страниц от общего набора при записи.182.1.2.4. Завершение работы одного из драйверовОчень важный момент это отгрузка драйвера. Ведь, если в данной ситуации ничегоне сделать, то когда отгрузится первый драйвер, упадут все остальные (вся система), таккак их страниц будут выгружены. Поэтому необходимо отдельно проработать отгрузкуодного из драйверов.Вот как предлагается это делать. Рассмотрим ситуацию, когда 2 драйвера всистеме, ссылаются на общий набор страниц. См. Рис 4. Допустим, один из них хочетотгрузиться - происходит "разъединение" страниц при отгрузке.
Это значит, что первыйдрайвер, который хотят отгрузить больше не будет ссылаться на общий набор страниц, онбудет ссылаться на другой набор страниц, то есть наборы разъединяются. и он может бытьспокойно отгружен.Рис.4. Отгрузка одного из драйверов.192.1.2.5. Необходимость использования нулевого набораОбоснование необходимости создания общего набора страниц, не принадлежащегони одному из драйверов.Именно в момент отгрузки одного из драйверов становится ясно, зачем былонужно выделять дополнительно память под общий набор, и почему он не создавался наоснове набора страниц какого-либо одного из драйверов.Это связано с тем, что если сделать его, например, на основе набора страницпервого драйвер, то этот драйвер можно будет отгружать лишь последним, (а кроме того,возникнут проблемы, если он захочет что-то записать в свои страницы). Или же, если онотгрузится придется перемапировать ВСЕ остальные драйверы на какой-то из оставшихся.И так каждый раз при отгрузке такого "главного" драйвера.
(Опять же остается проблема,если у этого "следующего" часть страниц уже с записями. В этом случае можно потерятьнеизмененные страницы.)А в случае с никому не принадлежащим общим набором страниц какой бы издрайверов мы не попытались отгрузить, это не повлияет на работу остальных.2.1.2.6. Итоговый алгоритм решенияТеперь, когда рассмотрены основополагающие моменты решения, можнопредставить итоговый алгоритм решения данной задачи. Более подробное описаниекаждого из приведенных ниже пунктов будет в пункте 2.2. "Реализация".Алгоритм:•Отслеживание загрузки и отгрузки каждого экземпляра драйвера.•Загрузка первого экземпляра драйвера:•–Анализ секций исполняемого файла, поиск «executable» страниц.–Создание общего набора страниц.–Встройка в обработчик исключения Page Fault.Загрузка второго и последующих экземпляров:20–Проверка идентичности экземпляров–Подмена страниц драйвера страницами общего набора.–Возвращение в систему неиспользуемых страниц драйверов.–Writable страницы сделать Copy On Write.•Работа системы:–•При попытке записи - исключение Page Fault и «разъединение» страниц.Выгрузка одного из экземпляров:–«Разъединение» страниц.Итак, вот как это работает:1) Отслеживание загрузки и отгрузки каждого экземпляра драйвера.2) Загрузка первого экземпляра драйвера:Во время загрузки первого экземпляра драйвера, происходит:Анализ секций исполняемого файла, поиск «executable» страниц.
То есть, страницкода. Это связано с тем, что все-таки операции записи в страницы кода встречаютсягораздо реже, чем операции записи в страницы с данными; а значит, данный механизмслияния страниц может быть полезен потому, что, если каждый драйвер будет писать всвои страниц данных, например, различные значения, то получится, что нам простонечего объединять.Создание общего набора страниц. Как было уже сказано выше, это набор страницдолжен создаваться именно отдельно, сам по себе, и не принадлежать ни одному издрайверов, чтобы не было проблем с отгрузкой.Встройка в обработчик исключения Page Fault.
Это необходимо для того, чтобыотслеживать попытки записи в Copy On Write страницы и правильно их обрабатывать.Изначально в Windows нет такого механизма для пула неподкачиваемой памяти. Однако,он был создан в процессе работы.На данном этапе мы получаем уже практически готовую работающую систему.213) Во время загрузки второго и последующих экземпляров, происходит:Проверка идентичности экземпляров. Это нужно для того, чтобы ни в коем случаене попал драйвер, например, с этим же названием, но другой версии, который будет иметьдругие страницы кода.Подмена страниц драйвера страницами общего набора.
В пункте про реализациюбудет пояснено, как это сделано. На данном этапе можно считать, что страницы драйвераподменяются страницами из общего набора, и драйвер ссылается на страницы из общегонабора, а про свои страницы он "забывает", хотя они все еще находятся в системе.Возвращение в систему неиспользуемых страниц драйверов.Кроме того, те страницы из общего набора, которые изначально были помеченыWritable , необходимо сделать Copy On Write.4) Когда все загружено, объединено и готово к работе - рассмотрим работусистемы:При попытке записи происходит исключение Page Fault, (так как, запись встраницы помеченные Copy On Write запрещена,) и, поскольку мы встроились вобработчик исключения Page Fault и сделали там свой обработчик, происходит«разъединение» страниц.
"Разъединение=отделение" от общего набора той единственнойстраницы, в которую велась запись. Драйвер перестает ссылать на такую страниц изобщего набора, для него создается копия этой страниц, уже доступная для записи. Дальшеуже исключения не происходят, потому что это его страница.Система работает таким образом, некоторые страницы разъединяются, некоторыенет. У каждого драйвер есть свой набор "разъединенных" страниц, а так же он обращаетсяко всем остальным своим страниц, которые находятся в общем наборе.5) При выгрузке одного из экземпляров, происходит:«Разъединение» наборов страниц.
Это означает, что те страницы драйвера, которыедо сих пор ссылались на страницы из общего набора, "отделяются" от них, и больше этивиртуальные адреса на них не ссылаются. Теперь, отгрузка этого экземпляра драйвераобычным системным способом не повлияет на все остальные загруженные экземпляры.Для корректной отгрузки драйвера, этого пока недостаточно, ведь виртуальныеадреса его страниц вообще ни на что не ссылаются. Можно было бы выделить ему новые22страницы, специально для отгрузки.
Но это бы привело к слишком большой нагрузке наподсистему памяти (а возможно, и дефициту страниц) при массовой отгрузке такихдрайверов, например, при резком выключении. В связи с этим, в данной работе этотспособ не используется. Вместо него используется способ аналогичный работе сDiscardable секциями драйверов. Страницы (их виртуальные адреса) драйвера, ранеессылавшиесянафизическиестраницыизобщегонаборапомечаются"ужеотгруженными", и после этого, драйвер может быть корректно отгружен системнымисредствами самой ОС. Более подробно см. в пункте про Реализацию.232.2.