Внутреннее устройство Microsoft Windows (гл. 12-14) - [6]

Шрифт
Интервал

создает IRP типа IRPMJREAD и посылает его драйверу файловой системы, в которой находится файл. NtReadFile получает объект FSD, хранящийся в объекте «файл», и вызывает IoCallDriver. Диспетчер ввода-вывода находит FSD с помощью объекта FSD и передает IRP этому драйверу файловой системы.

Если считываемый файл может быть кэширован (т. е. при открытии файла в функцию CreateFile не передан флаг FILE_FLAG_NO_BUFFERING), FSD проверяет, инициировано ли кэширование для этого объекта «файл». Если да, поле PrivateCacheMap объекта «файл» указывает на структуру закрытой карты кэша (см. главу 11). B ином случае поле PrivateCacheMap будет пустым. Кэширование объекта «файл» инициируется FSD при первой операции записи или чтения над этим объектом, для чего FSD вызывает функцию CcIni-tializeCacheMap диспетчера кэша, и диспетчер кэша создает закрытую и общую карты кэша, а также объект «раздел» (если это еще не сделано).

Убедившись, что кэширование файла разрешено, FSD копирует данные запрошенного файла из виртуальной памяти диспетчера кэша в буфер, указатель на который передан функции ReadFile вызывающим потоком. Файловая система выполняет копирование в рамках блока try/except, что позволяет перехватывать все ошибки, которые могут возникнуть, если приложение указало неверный буфер. Для копирования файловая система использует функцию CcCopyRead диспетчера кэша, которая принимает в качестве параметров объект «файл», смещение внутри файла и длину данных.

Диспетчер кэша, выполняя CcCopyRead, получает указатель на общую карту кэша, хранящуюся в объекте «файл». Вспомните из главы 11, что эта карта хранит указатели на блоки управления виртуальными адресами (VACB) и что один элемент VACB соответствует 256-килобайтному блоку файла. Если VACB-указатель для считываемой части файла пуст, CcCopyRead создает VACB, резервируя в виртуальном адресном пространстве диспетчера кэша 256-ки-лобайтное представление, и проецирует на это представление указанную порцию файла (с помощью MmMapViewInSystemCacbe). Затем CcCopyRead просто копирует данные файла из спроецированного представления в переданный ей буфер (буфер, изначально переданный в ReadFile). Если файловых данных в физической памяти нет, операция копирования вызывает ошибки страниц, обслуживаемые MmAccessFault.

Когда возникает ошибка страницы, MmAccessFault изучает виртуальный адрес, вызвавший ошибку, и находит дескриптор виртуального адреса (VAD) в дереве VAD вызвавшего ошибку процесса (подробнее о дереве VAD см. главу 7). B данном случае VAD описывает представление считываемого файла, проецируемое диспетчером кэша, поэтому для обработки ошибки страницы, вызванной действительным виртуальным адресом, MmAccessFault вызывает MiDispatcbFault, которая сначала находит область управления (на нее указывает VAD) и уже через нее отыскивает объект «файл», представляющий открытый файл. (Если файл открывался более чем один раз, возможно наличие списка объектов «файл», связанных указателями в закрытых картах кэша.)

Найдя объект «файл», MiDispatcbFault вызывает функцию IoPageRead диспетчера ввода-вывода, чтобы создать IRP (типа IRP_MJ_READ), и посылает этот IRP к FSD, владеющему объектом «устройство», на который указывает объект «файл». Таким образом, осуществляется повторный вход в файловую систему для чтения данных, запрошенных через CcCopyRead, но на этот раз в IRP присутствует флаг, который сообщает о необходимости некэшируемого и связанного с подкачкой ввода-вывода. Этот флаг сигнализирует FSD, что он должен извлечь данные непосредственно с диска, и тот так и поступает, определяя, какие кластеры диска содержат запрошенные данные, и посылая соответствующие IRP диспетчеру томов, владеющему объектом тома, на котором находится файл. Поле блока параметров тома (VPB) объекта FSD указывает на объект тома.

Диспетчер виртуальной памяти ждет, когда FSD завершит чтение, а потом возвращает управление диспетчеру кэша, который продолжает операцию копирования, прерванную ошибкой страницы. По окончании работы CcCopyRead драйвер файловой системы возвращает управление потоку, вызвавшему NtReadFile; на этот момент данные из запрошенного файла уже скопированы в буфер потока.

WriteFile работает аналогичным образом с тем исключением, что системный сервис NtWriteFile генерирует IRP типа IRP_MJ_WRITE, a FSD вызывает не CcCopyRead, a CcCopyWrite. Последняя, как и CcCopyRead, проверяет, спроецированы ли на кэш части записываемого файла, и копирует в кэш содержимое буфера, переданного в WriteFile.

Если файловые данные уже хранятся в системном рабочем наборе, вышеописанный сценарий немного меняется. Если файловые данные находятся в кэше, CcCopyRead не вызывает ошибки страниц. Кроме того, в определенных обстоятельствах NtReadFile и NtWriteFile — вместо того чтобы немедленно создать IRP и послать его FSD — вызывают в FSD точку входа для быстрого ввода-вывода. Вот некоторые из этих обстоятельств: считываемая часть файла должна находиться в первых 4 Гб файла, в файле не должно быть блокировок, а считываемая или записываемая часть файла не должна выходить за пределы его текущей длины.


Еще от автора Марк Руссинович
Внутреннее устройство Microsoft Windows (гл. 1-4)

Книга посвящена внутреннему устройству и алгоритмам работы основных компонентов операционной системы Microsoft Windows — Windows Server 2003, Windows XP и Windows 2000 — и файловой системы NTFS. Детально рассмотрены системные механизмы: диспетчеризация ловушек и прерываний, DPC, APC, LPC, RPC, синхронизация, системные рабочие потоки, глобальные флаги и др. Также описываются все этапы загрузки операционной системы и завершения ее работы. B четвертом издании книги больше внимания уделяется глубокому анализу и устранению проблем, из-за которых происходит крах операционной системы или из-за которых ее не удается загрузить.


Внутреннее устройство Microsoft Windows (гл. 5-7)

Продолжение книги "Внутреннее устройство Microsoft Windows" — 5 и 7 главы.


Внутреннее устройство Microsoft Windows (гл. 8-11)

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.