Ausstehende E/A-Anforderungen erzwingen

Die Option Ausstehende E/A-Anforderungen erzwingen gibt zufällig STATUS_PENDING als Reaktion auf Aufrufe eines Treibers an IoCallDriver zurück. Mit dieser Option wird die Logik des Treibers getestet, um auf STATUS_PENDING Rückgabewerte von IoCallDriver zu reagieren.

Diese Option wird nur unter Windows Vista und höheren Versionen des Windows-Betriebssystems unterstützt.

Vorsicht Verwenden Sie diese Option nicht für einen Treiber, es sei denn, Sie haben detaillierte Kenntnisse über den Betrieb des Treibers und haben überprüft, ob der Treiber für die Verarbeitung STATUS_PENDING Rückgabewerte aller Aufrufe von IoCallDriver konzipiert ist. Die Ausführung dieser Option auf einem Treiber, der nicht für die Verarbeitung von STATUS_PENDING von allen Aufrufen konzipiert ist, kann zu Abstürze, Speicherbeschädigungen und ungewöhnlichem Systemverhalten führen, das schwer zu debuggen oder zu korrigieren ist.

Warum ausstehende E/A-Anforderungen erzwingen?

Übergeordnete Treiber in einem Treiberstapel rufen IoCallDriver auf, um ein IRP an Treiber auf niedrigerer Ebene im Treiberstapel zu übergeben. Die Treiberverteilungsroutine im Treiber auf niedrigerer Ebene, der die IRP empfängt, kann den IRP entweder sofort abschließen oder STATUS_PENDING zurückgeben und die IRP zu einem späteren Zeitpunkt abschließen.

In der Regel muss der Aufrufer darauf vorbereitet sein, beide Ergebnisse zu verarbeiten. Da die meisten Dispatchroutinen die IRP jedoch sofort verarbeiten, wird die STATUS_PENDING Logik im Aufrufer nicht häufig ausgeführt, und schwerwiegende Logikfehler werden möglicherweise nicht erkannt. Die Option Ausstehende E/A-Anforderungen erzwingen fängt Aufrufe an IoCallDriver ab und gibt STATUS_PENDING zurück, um die selten verwendete Logik des aufrufenden Treibers zu testen.

Wann verwenden Sie ausstehende E/A-Anforderungen erzwingen?

Überprüfen Sie vor dem Ausführen dieses Tests den Treiberentwurf und den Quellcode, und vergewissern Sie sich, dass der Treiber STATUS_PENDING aller IoCallDriver-Aufrufe verarbeiten soll.

Viele Treiber sind nicht für die Verarbeitung von STATUS_PENDING bei allen Aufrufen von IoCallDriver konzipiert. Möglicherweise senden sie das IRP an einen bestimmten bekannten Treiber, der garantiert den IRP sofort abschließt. Das Senden STATUS_PENDING an einen Treiber, der dies nicht verarbeitet, kann zu Treiber- und Systemabstürzen und Speicherbeschädigung führen.

Wie sollten Treiber mit STATUS_PENDING umgehen?

Der Treiber auf höherer Ebene, der IoCallDriver aufruft, muss einen STATUS_PENDING Rückgabewert wie folgt verarbeiten:

  • Vor dem Aufrufen von IoCallDriver muss der Treiber IoBuildSynchronousFsdRequest aufrufen, um die synchrone Verarbeitung des IRP zu ermöglichen.

  • Wenn IoCallDriver STATUS_PENDING zurückgibt, muss der Treiber auf den Abschluss des IRP warten, indem Er KeWaitForSingleObject für das angegebene Ereignis aufruft.

  • Der Treiber muss damit rechnen, dass das IRP möglicherweise freigegeben wird, bevor der E/A-Manager das Ereignis signalisiert.

  • Nach dem Aufruf von IoCallDriver kann der Aufrufer nicht auf die IRP verweisen.

Welche Fehler werden ausstehende E/A-Anforderung erzwingen?

Die Option Ausstehende E/A-Anforderung erzwingen erkennt die folgenden Fehler im Treiber, der IoCallDriver aufruft, und erhält einen STATUS_PENDING Rückgabewert:

  • Der Treiber ruft IoBuildSynchronousFsdRequest nicht auf, um die synchrone Verarbeitung anzuordnen.

  • Der Treiber ruft KeWaitForSingleObject nicht auf.

  • Der Treiber verweist nach dem Aufruf von IoCallDriver auf einen Wert in der IRP-Struktur. Nach dem Aufrufen von IoCallDriver kann der Treiber auf höherer Ebene nicht auf die IRP zugreifen, es sei denn, er hat eine Abschlussroutine festgelegt und dann nur dann, wenn alle Treiber der niedrigeren Ebene das IRP abgeschlossen haben. Wenn das IRP freigegeben wird, stürzt der Treiber ab.

  • Der Treiber ruft eine zugehörige Funktion falsch auf. Beispielsweise ruft der Treiber KeWaitForSingleObject auf und übergibt ein Handle an das Ereignis (als Object-Parameter ), anstatt einen Zeiger auf ein Ereignisobjekt zu übergeben.

  • Der Treiber wartet auf das falsche Ereignis. Beispielsweise ruft der Treiber IoSetCompletionRoutine auf, wartet aber auf ein internes Ereignis, das von seiner eigenen Abschlussroutine signalisiert wird, anstatt auf das IRP-Ereignis zu warten, das vom E/A-Manager signalisiert wird, wenn das IRP abgeschlossen ist.

Erzwingen ausstehender E/A-Anforderungen, die in Windows 7 eingeführt wurden

Ab Windows 7 ist die Option Ausstehende E/A-Anforderungen erzwingen effektiver, um die Ausübung der STATUS_PENDING Codepfade in überprüften Treibern zu erzwingen. In früheren Windows-Versionen hat die Treiberüberprüfung erzwungen, dass ein IRP-Abschluss nur verzögert wird, wenn die erste IoCompleteRequest für dieses IRP ausgeführt wird. Dies bedeutet, dass die Effektivität der Überprüfung von Driver1 durch das Verhalten von Driver2 aus demselben Gerätestapel reduziert werden kann. Driver2 wartet möglicherweise synchron auf den Abschluss, bevor er von seiner Dispatchroutine zu Driver1 zurückkehrt. Die erzwungene Verzögerung des IRP-Abschlusses tritt genau auf, bevor die E/A-Anforderung wieder in den überprüften Treiber auf dem Abschlusspfad zurückgerollt wird. Dies bedeutet, dass der STATUS_PENDING Codepfad des verifizierten Treibers tatsächlich ausgeübt wird und der verifizierte Treiber eine Verzögerung bei der Fertigstellung erkennt.

Aktivieren dieser Option

Um ausstehende E/A-Anforderungen zu aktivieren, müssen Sie auch die E/A-Überprüfung aktivieren. Sie können die Option Ausstehende E/A-Anforderungen erzwingen für einen oder mehrere Treiber aktivieren, indem Sie den Treiberüberprüfungs-Manager oder die befehlszeile Verifier.exe verwenden. Weitere Informationen finden Sie unter Auswählen von Treiberüberprüfungsoptionen.

Die Option Ausstehende E/A-Anforderungen erzwingen wird nur unter Windows Vista und höheren Versionen von Windows unterstützt.

  • Über die Befehlszeile

    Um ausstehende E/A-Anforderungen erzwingen zu aktivieren, verwenden Sie den Flagwert 0x210, oder fügen Sie dem Flagwert 0x210 hinzu. Dieser Wert aktiviert die E/A-Überprüfung (0x10) und ausstehende E/A-Anforderungen erzwingen (0x200).

    Beispiel:

    verifier /flags 0x210 /driver MyDriver.sys
    

    Die Option ist nach dem nächsten Start aktiv.

    Wenn Sie versuchen, nur ausstehende E/A-Anforderungen erzwingen (Verifier /flags 0x200) zu aktivieren, aktiviert die Treiberüberprüfung automatisch sowohl ausstehende E/A-Anforderungen erzwingen (0x200) als auch E/A-Überprüfung.

    Sie können auch ausstehende E/A-Anforderungen erzwingen aktivieren und deaktivieren, ohne den Computer neu zu starten, indem Sie dem Befehl den Parameter /volatile hinzufügen. Beispiel:

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

    Diese Einstellung wird sofort wirksam, geht aber verloren, wenn Sie den Computer herunterfahren oder neu starten. Weitere Informationen finden Sie unter Verwenden von flüchtigen Einstellungen.

  • Verwenden des Treiberüberprüfungs-Managers

    1. Starten Sie den Treiberüberprüfungs-Manager. Geben Sie Verifier in ein Eingabeaufforderungsfenster ein.
    2. Wählen Sie Benutzerdefinierte Einstellungen erstellen (für Codeentwickler) aus, und klicken Sie dann auf Weiter.
    3. Wählen Sie Einzelne Einstellungen aus einer vollständigen Liste auswählen aus.
    4. Wählen Sie E/A-Überprüfung und Ausstehende E/A-Anforderungen erzwingen aus.

    Wenn Sie nur ausstehende E/A-Anforderungen erzwingen auswählen, erinnert Sie der Treiberüberprüfungs-Manager daran, dass die E/A-Überprüfung erforderlich ist, und bietet an, sie für Sie zu aktivieren.

Anzeigen der Ergebnisse

Um die Ergebnisse des Tests "Ausstehende E/A-Anforderungen erzwingen" anzuzeigen, verwenden Sie die Debuggererweiterung !verifier mit dem Flagwert 0x40.

Informationen zu !verifier finden Sie im Thema !verifier in der Dokumentation Debugtools für Windows .

Wenn der Testcomputer aufgrund des Tests "Ausstehende E/A-Anforderungen erzwingen" abstürzt, können Sie den Befehl !verifier 40 verwenden, um die Ursache zu ermitteln. Suchen Sie in einer aktuellen Stapelablaufverfolgung die Adresse des IRP, das kürzlich von Ihrem Treiber verwendet wurde. Wenn Sie beispielsweise den kP-Befehl verwenden, der den Stapelrahmen für einen Thread anzeigt, finden Sie die IRP-Adresse unter den Funktionsparametern der aktuellen Stapelüberwachung. Führen Sie dann !verifier 40 aus, und suchen Sie nach der Adresse des IRP. Die zuletzt erzwungenen ausstehenden Stapelüberwachungen werden oben auf der Anzeige angezeigt.

Die folgende Stapelablaufverfolgung von Pci.sys zeigt beispielsweise die Antwort auf Ausstehende E/A-Anforderungen erzwingen. Der Test zeigt keine Fehler in der logik der 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

Die Stapelablaufverfolgung zeigt, dass Acpi.sys versucht hat, IRP 8f84ef00 abzuschließen. Der Treiberprüfer hat einen verzögerten Abschluss erzwungen, sodass Acpi.sys STATUS_PENDING an pci zurückgegeben! PciCallDownIrpStack. Wenn dieser Aufruf zu einem Absturz geführt hätte, müsste der Treiberbesitzer den Quellcode für pci! PciCallDownIrpStack und überarbeiten Sie es, um die STATUS_PENDING ordnungsgemäß zu verarbeiten.