共用方式為


強制擱置 I/O 要求

[強制擱置 I/O 要求] 選項會隨機傳回STATUS_PENDING,以回應驅動程式對 IoCallDriver的呼叫。 此選項會測試驅動程式的邏輯,以回應 來自 IoCallDriver的STATUS_PENDING傳回值。

只有 Windows Vista 和更新版本的 Windows 作業系統才支援此選項。

謹慎 除非您已深入瞭解驅動程式的作業,並已確認驅動程式的設計目的是要處理STATUS_PENDING從其所有 IoCallDriver呼叫傳回值,否則請勿在驅動程式上使用此選項。 在未設計來處理所有呼叫STATUS_PENDING的驅動程式上執行此選項可能會導致損毀、記憶體損毀,以及難以偵錯或更正的異常系統行為。

為何要使用強制擱置 I/O 要求?

驅動程式堆疊中的較高層級驅動程式會呼叫 IoCallDriver ,將 IRP 向下傳遞至驅動程式堆疊中的較低層級驅動程式。 接收 IRP 的較低層級驅動程式中的驅動程式分派常式可以立即完成 IRP,或傳回STATUS_PENDING,並在稍後完成 IRP。

一般而言,呼叫端必須準備好處理任一結果。 不過,因為大部分分派常式會立即處理 IRP,所以呼叫端中的STATUS_PENDING邏輯通常不會執行,而且可能不會偵測到嚴重的邏輯錯誤。 [強制擱置 I/O 要求] 選項會攔截 IoCallDriver 的呼叫,並傳回STATUS_PENDING來測試呼叫驅動程式不常使用的邏輯。

何時使用強制擱置 I/O 要求?

執行此測試之前,請先檢閱驅動程式設計和原始程式碼,並確認驅動程式是要從其所有 IoCallDriver 呼叫處理STATUS_PENDING。

許多驅動程式並非設計來處理所有 IoCallDriver呼叫上的STATUS_PENDING。 它們可能會將 IRP 傳送至保證立即完成 IRP 的特定已知驅動程式。 將STATUS_PENDING傳送至未處理的驅動程式可能會導致驅動程式和系統損毀和記憶體損毀。

驅動程式如何處理STATUS_PENDING?

呼叫 IoCallDriver 的高階驅動程式必須處理STATUS_PENDING傳回值,如下所示:

  • 在呼叫 IoCallDriver之前,驅動程式必須呼叫 IoBuildSynchronousFsdRequest 以排列 IRP 的同步處理。

  • 如果 IoCallDriver 傳回STATUS_PENDING,驅動程式必須在指定的事件上呼叫 KeWaitForSingleObject ,等候 IRP 完成。

  • 驅動程式必須預期 IRP 可能會在 I/O 管理員發出事件訊號之前釋放。

  • 呼叫 IoCallDriver之後,呼叫端無法參考 IRP。

哪些錯誤會強制擱置 I/O 要求偵測?

[強制擱置 I/O 要求] 選項會偵測驅動程式中呼叫 IoCallDriver 並接收STATUS_PENDING傳回值的下列錯誤:

  • 驅動程式不會呼叫 IoBuildSynchronousFsdRequest 來排列同步處理。

  • 驅動程式不會呼叫 KeWaitForSingleObject

  • 驅動程式會在呼叫 IoCallDriver之後參考 IRP 結構中的值。 呼叫 IoCallDriver之後,除非已設定完成常式,然後只有在所有較低層級驅動程式都已完成 IRP 時,較高層級的驅動程式才能存取 IRP。 如果釋放 IRP,驅動程式將會當機。

  • 驅動程式不正確地呼叫相關的函式。 例如,驅動程式會呼叫 KeWaitForSingleObject ,並將控制碼傳遞至事件 (做為 Object 參數) ,而不是將指標傳遞至事件物件。

  • 驅動程式會等候錯誤的事件。 例如,驅動程式會呼叫 IoSetCompletionRoutine,但會等候由自己的完成常式發出訊號的內部事件,而不是等候 I/O 管理員在 IRP 完成時發出訊號的 IRP 事件。

強制 Windows 7 中引進的擱置 I/O 要求變更

從 Windows 7 開始,強制擱置 I/O 要求選項在強制執行已驗證驅動程式中的程式碼路徑STATUS_PENDING更有效率。 在舊版的 Windows 中,驅動程式驗證器只會在 IRP 的第一個 IoCompleteRequest 執行時,強制延遲 IRP 完成。 這表示驗證 Driver1 的有效性可以透過來自相同裝置堆疊的 Driver2 行為來減少。 Driver2 可能會在從分派常式傳回 Driver1 之前同步等候完成。 IRP 完成的強制延遲會在 I/O 要求回溯回到完成路徑上的已驗證驅動程式之前進行。 這表示已驗證驅動程式的STATUS_PENDING程式碼路徑確實已練習,且已驗證的驅動程式會察覺完成時的延遲。

啟用此選項

若要啟用強制擱置 I/O 要求,您也必須啟用 I/O 驗證。 您可以使用驅動程式驗證程式管理員或Verifier.exe命令列,為一或多個驅動程式啟用強制擱置 I/O 要求選項。 如需詳細資訊,請參閱 選取驅動程式驗證器選項

只有在 Windows Vista 和更新版本的 Windows 上才支援 [強制擱置 I/O 要求] 選項。

  • 在命令列

    若要啟用強制擱置 I/O 要求,請使用旗標值0x210或將0x210新增至旗標值。 此值會啟動 I/O 驗證 (0x10) ,以及強制擱置 I/O 要求 (0x200) 。

    例如:

    verifier /flags 0x210 /driver MyDriver.sys
    

    下一次開機之後,選項將會處於作用中狀態。

    如果您嘗試只啟用強制擱置 I/O 要求 (驗證程式 /flags 0x200) ,驅動程式驗證器會自動啟用強制擱置 I/O 要求 (0x200) 和 I/O 驗證

    您也可以將 /volatile 參數新增至 命令,以啟動和停用強制擱置 I/O 要求,而不重新開機電腦。 例如:

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

    此設定會立即生效,但當您關閉或重新開機電腦時遺失。 如需詳細資訊,請參閱 使用變動性設定

  • 使用驅動程式驗證器管理員

    1. 啟動驅動程式驗證器管理員。 在 [命令提示字元] 視窗中輸入 驗證程式
    2. 選取 [為程式碼開發人員建立自訂設定] () ,然後按 [ 下一步]。
    3. 從完整清單中選取 [選取個別設定]。
    4. 選取 [I/O 驗證 ] 並強制擱置 I/O 要求。

    如果您只選取 [強制擱置的 I/O 要求],驅動程式驗證器管理員會提醒您需要 I/O 驗證 ,並提供來為您啟用它。

檢視結果

若要檢視強制擱置 I/O 要求測試的結果,請使用 !verifier 偵錯工具延伸模組搭配旗標值0x40。

如需!verifier的相關資訊,請參閱Windows 偵錯工具檔中的!verifier主題。

如果測試電腦因強制擱置 I/O 要求測試而損毀,您可以使用 !verifier 40 命令來尋找原因。 在目前的堆疊追蹤中,尋找您驅動程式最近使用的 IRP 位址。 例如,如果您使用 kP 命令來顯示執行緒的堆疊框架,您可以在目前堆疊追蹤的函式參數中找到 IRP 位址。 然後,執行 !verifier 40 並尋找 IRP 的位址。 最新的強制擱置堆疊追蹤會出現在顯示器頂端。

例如,下列Pci.sys堆疊追蹤會顯示對強制擱置 I/O 要求的回應。 測試不會顯示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。