Принудительное выполнение ожидающих запросов ввода-вывода

Параметр Force Pending I/O Requests (Принудительное ожидание запросов ввода-вывода) случайным образом возвращает STATUS_PENDING в ответ на вызовы драйвера к IoCallDriver. Этот параметр проверяет логику драйвера для ответа на STATUS_PENDING возвращаемые значения из IoCallDriver.

Этот параметр поддерживается только в Windows Vista и более поздних версиях операционной системы Windows.

Осторожностью Не используйте этот параметр для драйвера, если у вас нет подробных знаний о работе драйвера и вы не убедились, что драйвер предназначен для обработки STATUS_PENDING возвращаемых значений из всех вызовов IoCallDriver. Запуск этого параметра в драйвере, который не предназначен для обработки STATUS_PENDING из всех вызовов, может привести к сбоям, повреждениям памяти и необычному поведению системы, которое может быть трудно отладить или исправить.

Зачем использовать принудительные ожидающие запросы ввода-вывода?

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

Как правило, вызывающий объект должен быть готов к обработке любого из результатов. Однако поскольку большинство подпрограмм диспетчеризации обрабатывают IRP немедленно, логика STATUS_PENDING в вызывающем объекте не часто выполняется, и серьезные логические ошибки могут не обнаруживаться. Параметр Force Pending I/O Requests перехватывает вызовы IoCallDriver и возвращает STATUS_PENDING для проверки редко используемой логики вызывающего драйвера.

Когда используется принудительное ожидание запросов ввода-вывода?

Перед выполнением этого теста просмотрите структуру драйвера и исходный код и убедитесь, что драйвер предназначен для обработки STATUS_PENDING из всех вызовов IoCallDriver .

Многие драйверы не предназначены для обработки STATUS_PENDING во всех вызовах IoCallDriver. Они могут отправлять IRP определенному хорошо известному драйверу, который гарантированно завершит IRP немедленно. Отправка STATUS_PENDING в драйвер, который не обрабатывает его, может привести к сбоям драйвера и системы и повреждению памяти.

Как водители должны обрабатывать STATUS_PENDING?

Драйвер более высокого уровня, вызывающий IoCallDriver , должен обрабатывать возвращаемое значение STATUS_PENDING следующим образом:

  • Перед вызовом IoCallDriver драйвер должен вызвать IoBuildSynchronousFsdRequest , чтобы организовать синхронную обработку IRP.

  • Если IoCallDriver возвращает STATUS_PENDING, драйвер должен дождаться завершения IRP, вызвав KeWaitForSingleObject для указанного события.

  • Драйвер должен предвидеть, что IRP может быть освобожден, прежде чем диспетчер ввода-вывода сигнализирует о событии.

  • После вызова IoCallDriver вызывающий объект не может ссылаться на IRP.

Какие ошибки обнаруживает принудительно ожидающий запрос ввода-вывода?

Параметр Принудительное ожидание запроса ввода-вывода обнаруживает следующие ошибки в драйвере, который вызывает IoCallDriver и получает STATUS_PENDING возвращаемое значение:

  • Драйвер не вызывает IoBuildSynchronousFsdRequest для упорядочения синхронной обработки.

  • Драйвер не вызывает KeWaitForSingleObject.

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

  • Драйвер неправильно вызывает связанную функцию. Например, драйвер вызывает KeWaitForSingleObject и передает дескриптор событию (в качестве параметра Object ) вместо передачи указателя на объект события.

  • Драйвер ожидает неправильного события. Например, драйвер вызывает IoSetCompletionRoutine, но ожидает внутреннего события, которое сигнализируется собственной подпрограммой завершения, а не ожидает события IRP, которое диспетчер ввода-вывода сигнализирует о завершении IRP.

Изменения в ожидающих запросах ввода-вывода принудительного выполнения, представленные в Windows 7

Начиная с Windows 7 параметр Принудительное ожидание запросов ввода-вывода более эффективен при принудительном выполнении путей кода STATUS_PENDING в проверенных драйверах. В более ранних версиях Windows средство проверки драйверов принудительно задерживало завершение IRP только при выполнении первого IoCompleteRequest для этой IRP. Это означает, что эффективность проверки Driver1 может быть снижена поведением Driver2 из того же стека устройств. Драйвер2 может синхронно ждать завершения, прежде чем вернуться из подпрограммы отправки в Driver1. Принудительная задержка завершения IRP происходит именно перед тем, как запрос ввода-вывода откатывается обратно в проверенный драйвер на пути завершения. Это означает, что STATUS_PENDING пути кода проверенного драйвера действительно выполняется, и проверенный драйвер воспринимает задержку в завершении.

Активация этого параметра

Чтобы активировать принудительные ожидающие запросы ввода-вывода, необходимо также активировать проверку ввода-вывода. Вы можете активировать параметр Принудительное ожидание запросов ввода-вывода для одного или нескольких драйверов с помощью диспетчера проверки драйверов или командной строки Verifier.exe. Дополнительные сведения см. в разделе Выбор параметров средства проверки драйверов.

Параметр Принудительное ожидание запросов ввода-вывода поддерживается только в Windows Vista и более поздних версиях Windows.

  • В командной строке

    Чтобы активировать принудительно ожидающие запросы ввода-вывода, используйте значение флага 0x210 или добавьте 0x210 к значению флага. Это значение активирует проверку ввода-вывода (0x10) и принудительное ожидание запросов ввода-вывода (0x200).

    Пример:

    verifier /flags 0x210 /driver MyDriver.sys
    

    Параметр будет активен после следующей загрузки.

    Если вы попытаетесь активировать только принудительные ожидающие запросы ввода-вывода (проверяющий /flags 0x200), средство проверки драйверов автоматически включает как принудительно ожидающие запросы ввода-вывода (0x200), так и проверку ввода-вывода.

    Вы также можете активировать и отключить принудительно ожидающие запросы ввода-вывода без перезагрузки компьютера, добавив параметр /volatile в команду . Пример:

    verifier /volatile /flags 0x210 /adddriver MyDriver.sys
    

    Этот параметр вступает в силу немедленно, но теряется при завершении работы или перезагрузке компьютера. Дополнительные сведения см. в разделе Использование переменных параметров.

  • Использование диспетчера проверки драйверов

    1. Запустите диспетчер проверки драйверов. Введите Verifier в окне командной строки.
    2. Выберите Создать пользовательские параметры (для разработчиков кода) и нажмите кнопку Далее.
    3. Выберите Выбрать отдельные параметры из полного списка.
    4. Выберите Проверка ввода-вывода и Принудительное выполнение ожидающих запросов ввода-вывода.

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

Просмотр результатов

Чтобы просмотреть результаты теста Принудительное ожидание запросов ввода-вывода, используйте расширение отладчика !verifier со значением флага 0x40.

Сведения о !verifier см. в разделе !verifier документации по средствам отладки для Windows .

Если тестовый компьютер аварийно завершает работу в результате выполнения теста Принудительное ожидание запросов ввода-вывода, вы можете найти причину с помощью команды !verifier 40 . В текущей трассировке стека найдите адрес IRP, который недавно использовался драйвером. Например, если вы используете команду kP , которая отображает кадр стека для потока, адрес IRP можно найти среди параметров функции текущей трассировки стека. Затем запустите !verifier 40 и найдите адрес IRP. Последние трассировки стека принудительного ожидания отображаются в верхней части экрана.

Например, следующая трассировка стека Pci.sys показывает ответ на запросы принудительного ожидания ввода-вывода. Тест не обнаруживает ошибок в логике Pci.sys.

kd> !verifier 40
# Size of the log is 0x40
========================================================
IRP: 8f84ef00 - forced pending from stack trace:

     817b21e4 nt!IovpLocalCompletionRoutine+0xb2
     81422478 nt!IopfCompleteRequest+0x15c
     817b2838 nt!IovCompleteRequest+0x9c
     84d747df acpi!ACPIBusIrpDeviceUsageNotification+0xf5
     84d2d36c acpi!ACPIDispatchIrp+0xe8
     817b258f nt!IovCallDriver+0x19d
     8142218e nt!IofCallDriver+0x1c
     817c6a9d nt!ViFilterDispatchPnp+0xe9
     817b258f nt!IovCallDriver+0x19d
     8142218e nt!IofCallDriver+0x1c
     84fed489 pci!PciCallDownIrpStack+0xbf
     84fde1cb pci!PciDispatchPnpPower+0xdf
     817b258f nt!IovCallDriver+0x19d
     8142218e nt!IofCallDriver+0x1c
     817c6a9d nt!ViFilterDispatchPnp+0xe9
     817b258f nt!IovCallDriver+0x19d
     8142218e nt!IofCallDriver+0x1c
     84ff2ff5 pci!PciSendPnpIrp+0xbd
 84fec820 pci!PciDevice_DeviceUsageNotification+0x6e
     84fde1f8 pci!PciDispatchPnpPower+0x10c
 817b258f nt!IovCallDriver+0x19d
     8142218e nt!IofCallDriver+0x1c
     84d76ce2 acpi!ACPIFilterIrpDeviceUsageNotification+0x96
     84d2d36c acpi!ACPIDispatchIrp+0xe8
     817b258f nt!IovCallDriver+0x19d
     8142218e nt!IofCallDriver+0x1c
     84f7f16c PCIIDEX!PortWdmForwardIrpSynchronous+0x8e
     84f7b2b3 PCIIDEX!GenPnpFdoUsageNotification+0xcb
     84f7d301 PCIIDEX!PciIdeDispatchPnp+0x45
     817b258f nt!IovCallDriver+0x19d
     8142218e nt!IofCallDriver+0x1c

Трассировка стека показывает, что Acpi.sys пытался завершить IRP 8f84ef00. Средство проверки драйверов заставило выполнить отложенное завершение, поэтому Acpi.sys вернул STATUS_PENDING в pci! PciCallDownIrpStack. Если этот вызов вызвал сбой, владельцу драйвера потребуется просмотреть исходный код pci! PciCallDownIrpStack и изменить его для правильной обработки STATUS_PENDING.