Создание IRP для драйверов Lower-Level

Чтобы выделить IRP для асинхронного запроса, который будет обрабатываться в произвольном контексте потока более низкими драйверами, подпрограмма DispatchReadWrite может вызвать одну из следующих подпрограмм поддержки:

  • IoAllocateIrp, который выделяет IRP и ряд расположений стека ввода-вывода с нуля

    Подпрограмма отправки должна настроить расположение стека ввода-вывода следующего уровня драйвера для недавно выделенного IRP, как правило, путем копирования (возможно измененных) сведений из собственного расположения стека в исходном IRP. Если драйвер более высокого уровня выделяет собственное место в стеке ввода-вывода для недавно выделенного IRP, то процедура отправки может настроить контекстную информацию для каждого запроса там для использования процедурой IoCompletion.

  • IoBuildAsynchronousFsdRequest, который настраивает расположение стека ввода-вывода следующего ниже драйвера для вызывающего объекта в соответствии с указанными вызывающими параметрами.

    Драйверы более высокого уровня могут вызывать эту подпрограмму, чтобы выделить IRP для запросов IRP_MJ_READ, IRP_MJ_WRITE, IRP_MJ_FLUSH_BUFFERS и IRP_MJ_SHUTDOWN.

    Когда подпрограмма IoCompletion вызывается для такого IRP, она может проверить блок состояния ввода-вывода и при необходимости (или возможно) настроить расположение стека ввода-вывода следующего нижнего драйвера в IRP и повторить запрос или повторно использовать его. Однако подпрограмма IoCompletion не имеет локального хранилища контекста для себя в IRP, поэтому драйвер должен поддерживать контекст о исходном запросе в другом месте резидентной памяти.

  • IoMakeAssociatedIrp, который выделяет IRP и ряд расположений стека ввода-вывода нулевой инициализации и связывает IRP с главным IRP.

    Промежуточные драйверы не могут вызывать IoMakeAssociatedIrp для создания IRP для более низких драйверов.

    Любой драйвер высокого уровня, вызывающий IoMakeAssociatedIrp для создания IRPs для более низких драйверов, может вернуть управление диспетчеру операций ввода-вывода после отправки связанных IRPs и вызова IoMarkIrpPending для исходного главного IRP. Драйвер высокого уровня может полагаться на управляющий вводом-выводом, чтобы завершить главный IRP, когда все связанные IRP были завершены драйверами нижнего уровня.

    Драйверы редко задают подпрограмму IoCompletion для связанного IRP. Если драйвер самого высокого уровня вызывает IoSetCompletionRoutine для созданного им связанного IRP, диспетчер ввода-вывода не завершает обработку главного IRP, если драйвер возвращает STATUS_MORE_PROCESSING_REQUIRED из своей подпрограммы IoCompletion. В этих обстоятельствах подпрограмма IoCompletion драйвера должна явно завершить главный IRP вызовом IoCompleteRequest.

Если драйвер выделяет собственное расположение стека ввода-вывода в новом IRP, подпрограмма отправки должна вызывать IoSetNextIrpStackLocation перед вызовом IoGetCurrentIrpStackLocation для настройки контекста в собственном расположении стека ввода-вывода для подпрограммы IoCompletion . Дополнительные сведения см. в разделе об обработке irps в драйвере Intermediate-Level.

Подпрограмма отправки должна вызывать IoMarkIrpPending с исходным IRP, но не с IRP, выделенными драйвером, так как подпрограмма IoCompletion освободит их память.

Если подпрограмма отправки распределяет IRP для частичной передачи, а базовый драйвер устройства может управлять устройством с съемными носителями, подпрограмма отправки должна настроить контекст потока в недавно выделенных IRP, используя значение Tail.Overlay.Thread в исходном IRP.

Внутренний драйвер для съемных носителей может вызывать IoSetHardErrorOrVerifyDevice, которая ссылается на указатель в Irp->Tail.Overlay.Thread для выделенного драйвером IRP. Если драйвер вызывает эту подпрограмму поддержки, драйвер файловой системы может отправить диалоговое окно в соответствующий поток пользователя, который предложит пользователю отменить, повторить или завершить операцию, которую не удалось выполнить драйверу. Дополнительные сведения см. в разделе "Поддержка съемных носителей ".

Подпрограммы отправки должны возвращать STATUS_PENDING после отправки всех выделенных драйвером irPs на более низкие драйверы.

Подпрограмма IoCompletion драйвера должна освободить все выделенные драйвером IRP с IoFreeIrp, прежде чем вызывать IoCompleteRequest для исходного IRP. После завершения исходного IRP подпрограмма IoCompletion должна освободить все выделенные драйвером IRP, прежде чем вернуть управление.

Каждый драйвер более высокого уровня настраивает все выделенные (и повторно используемые) IRPs для нижележащих драйверов таким образом, чтобы базовому драйверу устройства было безразлично, поступает ли данный запрос от промежуточного драйвера или исходит из любого другого источника, например, файловой системы или приложения в пользовательском режиме.

Драйверы высокого уровня могут вызывать IoMakeAssociatedIrp, чтобы выделить IRPs и настроить их для последовательности более низкоуровневых драйверов. Диспетчер ввода-вывода автоматически завершает исходный IRP после завершения всех связанных IRP, если драйвер не вызывает IoSetCompletionRoutine с исходным IRP или с любым из связанных IRP, которые он выделяет. Однако драйверы высокого уровня не должны выделять связанные IRP для любой операции IRP, которая запрашивает буферную операцию ввода-вывода.

Драйвер промежуточного уровня не может выделить IRP для драйверов нижнего уровня путем вызова IoMakeAssociatedIrp. Любой IRP, который получает промежуточный драйвер, может уже быть связанным, и драйвер не может связать с ним другой IRP.

Вместо этого, если промежуточный драйвер создает irPs для более низких драйверов, он должен вызывать IoAllocateIrp, IoBuildDeviceIoControlRequest, IoBuildSynchronousFsdRequest или IoBuildAsynchronousFsdRequest. Однако IoBuildSynchronousFsdRequest можно вызывать только в следующих обстоятельствах:

  • Созданным драйвером потоком для создания IRP для запросов на чтение или запись, так как такой поток может ожидать в контексте непарбитрного потока (собственного) объекта диспетчера, например события, инициализированного драйвером события, переданного IoBuildSynchronousFsdRequest.

  • В контексте системного потока при инициализации или при выгрузке.

  • Для построения IRP для изначально синхронных операций, таких как создание, очистка, завершение работы, закрытие и запросы на управление устройствами

Однако драйвер, скорее всего, вызывает IoBuildDeviceIoControlRequest, чтобы выделить контрольные IRPs устройства, чем IoBuildSynchronousFsdRequest.