Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
На рисунке, иллюстрированном открытии объекта файла, отображается IRP с двумя расположениями стека ввода-вывода, но iRP может иметь любое количество расположений стека ввода-вывода в зависимости от количества многоуровневых драйверов, обрабатывающих данный запрос.
На следующем рисунке более подробно иллюстрируется, как драйверы на рисунке Открытия объекта файла используют подпрограммы поддержки ввода-вывода (подпрограммы IoXxx) для обработки IRP при запросе на чтение или запись.
Диспетчер ввода-вывода вызывает драйвер файловой системы (FSD) с IRP, выделенным для запроса подсистемы на чтение и запись. FSD обращается к расположению стека ввода-вывода в IRP, чтобы определить, какая операция должна выполняться.
FSD может разбить исходный запрос на меньшие запросы (возможно, для нескольких драйверов устройств), вызвав подпрограмму поддержки ввода-вывода (IoAllocateIrp) один или несколько раз для выделения дополнительных IRP. Дополнительные запросы IRP передаются в FSD с заполненными нулями позициями в стеке ввода-вывода для драйверов нижнего уровня. По своему усмотрению FSD может повторно использовать исходный IRP, а не выделять дополнительные IRP, как показано на предыдущем рисунке, путем настройки расположения стека ввода-вывода следующего ниже драйвера в исходном IRP и передачи его на более низкие драйверы.
Для каждого выделенного драйвера IRP FSD на предыдущем рисунке вызывает подпрограмму поддержки ввода-вывода для регистрации подпрограммы завершения, предоставленной FSD; В подпрограмме завершения FSD может определить, удовлетворены ли более низкие драйверы запросом и могут освободить каждый выделенный драйвер IRP, когда более низкие драйверы завершили его. Диспетчер ввода-вывода вызовет подпрограмму завершения, предоставленную FSD, независимо от того, было ли каждое выделенное драйвером IRP успешно завершено, завершено со статусом ошибки или отменено. Драйвер более высокого уровня отвечает за освобождение всех выделенных ИРВ и настройку от собственного имени для драйверов нижнего уровня. Менеджер ввода-вывода освобождает IRPs, которые он выделяет, после того как все драйверы их завершили.
Затем FSD вызывает подпрограмму поддержки ввода-вывода (IoGetNextIrpStackLocation), чтобы получить доступ к расположению стека ввода-вывода драйвера следующего уровня, чтобы настроить запрос для следующего нижнего драйвера. (На предыдущем рисунке следующий нижний драйвер будет самым низким драйвером.) FSD затем вызывает подпрограмму поддержки ввода-вывода (IoCallDriver), чтобы передать этот IRP в следующий нижний драйвер.
При вызове с помощью IRP драйвер нижнего уровня проверяет расположение стека ввода-вывода, чтобы определить, какая операция (указана в коде функции IRP_MJ_XXXX) должна выполняться на целевом устройстве. Целевое устройство представлено объектом устройства в указанном расположении стека ввода-вывода и передается с запросом ввода-вывода (IRP) драйверу. Драйвер нижнего уровня может предположить, что диспетчер ввода-вывода перенаправил IRP в точку входа, определяемую драйвером для операции IRP_MJ_XXXX (здесь IRP_MJ_READ или IRP_MJ_WRITE), и что драйвер более высокого уровня проверил допустимость других параметров запроса.
Если драйвера более высокого уровня не было, драйвер нижнего уровня будет проверять, допустимы ли входные параметры для операции IRP_MJ_XXXX. Если это так, драйвер обычно вызывает вспомогательные подпрограммы ввода-вывода, чтобы сообщить диспетчеру ввода-вывода о том, что операция устройства ожидается в IRP, и о необходимости либо поставить IRP в очередь, либо передать его другой подпрограмме, предоставляемой драйвером, которая обращается к целевому устройству (здесь, физическое или логическое устройство: диск или раздел на диске).
Диспетчер ввода-вывода определяет, занят ли драйвер уже обработкой другого IRP для целевого устройства, ставит IRP в очередь, если он занят, и завершает выполнение. В противном случае диспетчер ввода-вывода направляет IRP в подпрограмму, предоставляемую драйвером, которая запускает операцию ввода-вывода на своем устройстве. (На этом этапе оба драйвера на предыдущем рисунке и диспетчер ввода-вывода возвращают управление.)
Когда устройство генерирует прерывание, обработчик прерываний драйвера (ISR) выполняет только те функции, которые необходимы для остановки прерывания устройства и сохранения необходимого контекста операции. Затем ISR вызывает подпрограмму поддержки ввода-вывода (IoRequestDpc) с IRP для постановки в очередь подпрограммы DPC (отложенного вызова процедуры) для выполнения запрошенной операции с более низким приоритетом оборудования, чем у ISR.
Когда DPC драйвера получает контроль, он использует контекст (переданный как аргумент в вызове ISR в IoRequestDpc) для завершения операции ввода-вывода. DPC вызывает подпрограмму поддержки для выгрузки из очереди следующего IRP (если таковой имеется) и передачи IRP в подпрограмму, предоставленную драйвером, которая начинает операции ввода-вывода на устройстве (см. шаг 5). Затем DPC устанавливает состояние только что завершенной операции в блоке состояния ввода-вывода IRP и возвращает его диспетчеру ввода-вывода с помощью IoCompleteRequest.
Диспетчер операций ввода-вывода обнуляет позицию в стеке ввода-вывода на самом низком уровне в IRP и вызывает зарегистрированную процедуру завершения файловой системы (см. шаг 3) с IRP, выделенной FSD. Эта подпрограмма завершения проверяет блок состояния ввода-вывода, чтобы определить, следует ли повторить запрос, обновить внутреннее состояние, связанное с исходным запросом, или освободить IRP, выделенный драйвером. Файловая система может собирать сведения о состоянии для всех IRP, выделенных драйвером, которые она отправляет драйверам нижнего уровня, чтобы установить состояние ввода-вывода и завершить исходный IRP. Когда файловая система завершит исходный IRP, диспетчер ввода-вывода возвращает значение NTSTATUS исходному запросчику (родная функция подсистемы) операции ввода-вывода.
Как и драйвер файловой системы, показанный на рисунке Обработка IRP в многослойных драйверах, любой новый драйвер, добавленный в цепочку существующих драйверов, может выполнять все следующие действия:
Задайте собственную подпрограмму завершения в IRP. Подпрограмма IoCompletion проверяет блок состояния ввода-вывода, чтобы определить, завершили ли нижестоящие драйверы IRP успешно, отменили его и/или завершили с ошибкой. Подпрограмма завершения также может обновить любое состояние IRP, которое мог сохранить драйвер, освободить ресурсы, относящиеся к конкретной операции, которые драйвер мог выделить, и тому подобное, прежде чем завершить IRP. Кроме того, подпрограмма завершения может отложить завершение IRP (уведомив диспетчера ввода-вывода, что для IRP требуется дополнительная обработка), и может отправить еще один запрос на следующий нижний уровень драйвера, прежде чем разрешить IRP завершить.
Настройте расположение стека ввода-вывода драйвера следующего нижнего уровня в IRP, которые вы выделяете, и отправляйте запросы следующему нижнему уровню драйвера.
Передайте все входящие запросы на более низкие драйверы, настроив расположение стека ввода-вывода следующего уровня драйвера в каждом IRP и вызвав IoCallDriver. (Обратите внимание, что для irPs с основным кодом функции IRP_MJ_POWER драйверы должны использовать PoCallDriver.)
Каждый созданный драйвером объект устройства представляет физическое, логическое или виртуальное устройство, для которого конкретный драйвер выполняет запросы ввода-вывода. Подробные сведения о создании и настройке объекта устройства см. в разделе "Объекты устройств" и "Стеки устройств".
Как показано на рисунке "Обработка IRP в многоуровневых драйверах", большинство драйверов обрабатывают каждый IRP поэтапно, используя набор стандартных процедур, определенных системой и предоставляемых драйвером. Однако драйверы на разных уровнях в цепочке обязательно имеют разные стандартные процедуры. Например, только драйверы низкого уровня обрабатывают прерывания с физического устройства, поэтому только драйвер низкого уровня будет иметь ISR и DPC, который завершает операции ввода-вывода на основе прерываний. С другой стороны, поскольку такой драйвер знает, что операции ввода-вывода завершены при получении прерывания с устройства, у него нет необходимости в подпрограмме завершения. Только драйвер более высокого уровня будет иметь одну или несколько подпрограмм завершения, таких как FSD на этом рисунке.