Erstellen von IRPs für Lower-Level-Treiber

Um eine IRP für eine asynchrone Anforderung zuzuordnen, die in einem beliebigen Threadkontext von niedrigeren Treibern verarbeitet wird, kann eine DispatchReadWrite-Routine eine der folgenden Supportroutinen aufrufen:

  • IoAllocateIrp, das eine IRP und eine Reihe von null initialisierten E/A-Stapelspeicherorten zuordnet

    Die Dispatchroutine muss den E/A-Stapelspeicherort des nächstniedrigen Treibers für den neu zugeordneten IRP einrichten, in der Regel durch Kopieren (möglicherweise geänderter) Informationen aus dem eigenen Stapelspeicherort in der ursprünglichen IRP. Wenn ein Treiber auf höherer Ebene einen eigenen E/A-Stapelspeicherort für einen neu zugeordneten IRP zuordnet, kann die Dispatchroutine dort Kontextinformationen pro Anforderung für die IoCompletion-Routine einrichten.

  • IoBuildAsynchronousFsdRequest, das den E/A-Stapelspeicherort des nächstniedrigen Treibers für den Aufrufer gemäß den vom Aufrufer angegebenen Parametern einrichtet

    Übergeordnete Treiber können diese Routine aufrufen, um IRPs für IRP_MJ_READ-, IRP_MJ_WRITE-, IRP_MJ_FLUSH_BUFFERS- und IRP_MJ_SHUTDOWN-Anforderungen zuzuweisen.

    Wenn eine IoCompletion-Routine für eine solche IRP aufgerufen wird, kann sie den E/A-status-Block überprüfen und bei Bedarf (oder möglich) den E/A-Stapelspeicherort des nächstniedrigen Treibers im IRP erneut einrichten und die Anforderung wiederholen oder wiederverwenden. Die IoCompletion-Routine verfügt jedoch über keinen lokalen Kontextspeicher im IRP, sodass der Treiber den Kontext zur ursprünglichen Anforderung an anderer Stelle im residenten Speicher beibehalten muss.

  • IoMakeAssociatedIrp, das ein IRP und eine Reihe von null initialisierten E/A-Stapelspeicherorten zuordnet und den IRP einem master IRP zuordnet.

    Zwischentreiber können IoMakeAssociatedIrp nicht aufrufen, um IRPs für niedrigere Treiber zu erstellen.

    Jeder Treiber der obersten Ebene, der IoMakeAssociatedIrp aufruft, um IRPs für niedrigere Treiber zu erstellen, kann die Steuerung an den E/A-Manager zurückgeben, nachdem er die zugeordneten IRPs an gesendet und IoMarkIrpPending für die ursprüngliche, master IRP aufgerufen hat. Ein Treiber der obersten Ebene kann sich auf den E/A-Manager verlassen, um die master IRP abzuschließen, wenn alle zugehörigen IRPs von niedrigeren Treibern abgeschlossen wurden.

    Treiber legen selten eine IoCompletion-Routine für eine zugeordnete IRP fest. Wenn ein Treiber der obersten Ebene IoSetCompletionRoutine für einen zugeordneten IRP aufruft, den er erstellt, führt der E/A-Manager die master IRP nicht aus, wenn der Treiber STATUS_MORE_PROCESSING_REQUIRED aus seiner IoCompletion-Routine zurückgibt. Unter diesen Umständen muss die IoCompletion-Routine des Treibers die master IRP mit IoCompleteRequest explizit abschließen.

Wenn ein Treiber einen eigenen E/A-Stapelspeicherort in einem neuen IRP zuordnet, muss die Dispatchroutine IoSetNextIrpStackLocation aufrufen, bevor IoGetCurrentIrpStackLocation aufgerufen wird , um den Kontext in einem eigenen E/A-Stapelspeicherort für die IoCompletion-Routine einzurichten. Weitere Informationen finden Sie unter Verarbeiten von IRPs in einem Intermediate-Level-Treiber.

Die Dispatchroutine muss IoMarkIrpPending mit dem ursprünglichen IRP aufrufen, jedoch nicht mit treiberseitig zugewiesenen IRPs, da sie von der IoCompletion-Routine freigegeben werden.

Wenn die Dispatchroutine IRPs für Teilübertragungen zuweist und der zugrunde liegende Gerätetreiber möglicherweise ein Wechselmediengerät steuert, muss die Dispatchroutine den Threadkontext in den neu zugeordneten IRPs aus dem Wert bei Tail.Overlay.Thread im ursprünglichen IRP einrichten.

Ein zugrunde liegender Treiber für ein Wechselmediengerät kann IoSetHardErrorOrVerifyDevice aufrufen, der auf den Zeiger auf Irp-Tail.Overlay.Thread> verweist, für eine vom Treiber zugewiesene IRP. Wenn der Treiber diese Supportroutine aufruft, kann der Dateisystemtreiber ein Dialogfeld an den entsprechenden Benutzerthread senden, das den Benutzer auffordert, einen Vorgang abzubrechen, erneut zu wiederholen oder einen Fehler auszuführen, den der Treiber nicht erfüllen konnte. Weitere Informationen finden Sie unter Unterstützen von Wechselmedien .

Dispatchroutinen müssen STATUS_PENDING zurückgeben, nachdem alle vom Treiber zugewiesenen IRPs an niedrigere Treiber gesendet wurden.

Die IoCompletion-Routine eines Treibers sollte alle vom Treiber zugewiesenen IRPs mit IoFreeIrp freigeben, bevor IoCompleteRequest für den ursprünglichen IRP aufgerufen wird. Nach Abschluss des ursprünglichen IRP muss die IoCompletion-Routine alle vom Treiber zugewiesenen IRPs freigeben, bevor sie die Steuerung zurückgibt.

Jeder Treiber auf höherer Ebene richtet alle vom Treiber zugewiesenen (und wiederverwendeten) IRPs für niedrigere Treiber so ein, dass es für den zugrunde liegenden Gerätetreiber unerheblich ist, ob eine bestimmte Anforderung von einem Zwischentreiber stammt oder von einer anderen Quelle stammt, z. B. einem Dateisystem oder einer Benutzermodusanwendung.

Treiber der obersten Ebene können IoMakeAssociatedIrp aufrufen, um IRPs zuzuweisen und für eine Kette niedrigerer Treiber einzurichten. Der E/A-Manager schließt den ursprünglichen IRP automatisch ab, wenn alle zugehörigen IRPs abgeschlossen wurden, sofern der Treiber IoSetCompletionRoutine nicht mit dem ursprünglichen IRP oder mit einem der zugeordneten IRPs aufruft, die er zugeordnet. Treiber der obersten Ebene dürfen jedoch keine zugeordneten IRPs für IRP zuordnen, die einen gepufferten E/A-Vorgang anfordert.

Ein Treiber auf mittlerer Ebene kann keine IRPs für Treiber niedrigerer Ebene zuordnen, indem IoMakeAssociatedIrp aufgerufen wird. Jedes IRP, das ein Zwischentreiber empfängt, kann bereits ein zugeordnetes IRP sein, und ein Treiber kann einem solchen IRP keine andere IRP zuordnen.

Wenn ein Zwischentreiber IRPs für niedrigere Treiber erstellt, sollte er stattdessen IoAllocateIrp, IoBuildDeviceIoControlRequest, IoBuildSynchronousFsdRequest oder IoBuildAsynchronousFsdRequest aufrufen. IoBuildSynchronousFsdRequest kann jedoch nur unter den folgenden Umständen aufgerufen werden:

  • Von einem vom Treiber erstellten Thread, um IRPs für Lese- oder Schreibanforderungen zu erstellen, da ein solcher Thread in einem (eigenen) Threadkontext auf ein Verteilerobjekt warten kann, z. B. ein treiberinitialisiertes Ereignis, das an IoBuildSynchronousFsdRequest übergeben wird

  • Im Systemthreadkontext während der Initialisierung oder beim Entladen

  • So erstellen Sie IRPs für inhärent synchrone Vorgänge wie Erstellen, Leeren, Herunterfahren, Schließen und Gerätesteuerungsanforderungen

Es ist jedoch wahrscheinlicher, dass ein Treiber IoBuildDeviceIoControlRequest aufruft, um Gerätesteuerungs-IRPs zuzuweisen, als IoBuildSynchronousFsdRequest.