Когда FSD получает IRP типа IRP_MJ_CREATE, он ищет указанный файл, проверяет права доступа и, если файл есть и пользователь имеет права на запрошенный вид доступа к файлу, возвращает код успешного завершения. Диспетчер объектов создает в таблице описателей, принадлежащей процессу, описатель объекта «файл», который передается назад по цепочке вызовов, в конечном счете достигая приложения в виде параметра, возвращаемого CreateFile. Если файловой системе не удается создать файл, диспетчер ввода-вывода удаляет созданный для него объект «файл».

Мы опустили здесь детали, относящиеся к тому, как FSD находит открываемый на томе файл. B выполнении ReadFile ядро участвует в той же мере, что и в выполнении CreateFile, но в этом случае системному cepвucy NtReadFiIe не приходится искать имя — он вызывает диспетчер объектов для трансляции описателя, переданного ReadFile, в указатель на объект «файл». Если описатель открытого файла указывает на наличие у вызывающего потока прав на чтение файла, NtReadFile создает 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 указывает на объект тома.


Логин
Пароль
Запомнить меня