Freigeben über


Schreiben von Rückrufroutinen vor dem Vorgang

Ein Minifiltertreiber verwendet eine oder mehrere Rückrufroutinen vor dem Vorgang , um E/A-Vorgänge zu filtern. Rückrufroutinen vor dem Vorgang ähneln den Dispatchroutinen, die im Legacyfiltermodell verwendet werden.

Ein Minifilter registriert eine Rückrufroutine vor dem Vorgang für einen bestimmten E/A-Vorgangstyp, indem der Einstiegspunkt der Rückrufroutine im Member OperationRegistration der FLT_REGISTRATION-Struktur gespeichert wird. Der Minifilter übergibt diesen Member an FltMgr als Parameter an FltRegisterFilter in seiner DriverEntry-Routine .

Minifilter empfangen nur die Typen von E/A-Vorgängen, für die sie eine Rückrufroutine vor oder nach dem Vorgang registriert haben. Ein Minifilter kann eine Rückrufroutine vor dem Vorgang für einen bestimmten E/A-Vorgangstyp registrieren, ohne eine Rückrufroutine nach dem Vorgang zu registrieren und umgekehrt.

Jede Rückrufroutine vor dem Vorgang wird wie folgt definiert:

typedef FLT_PREOP_CALLBACK_STATUS 
(*PFLT_PRE_OPERATION_CALLBACK) ( 
    IN OUT PFLT_CALLBACK_DATA Data, 
    IN PCFLT_RELATED_OBJECTS FltObjects, 
    OUT PVOID *CompletionContext 
    ); 

Wenn FltMgr die Rückrufroutine eines Minifilters vor dem Vorgang für einen bestimmten E/A-Vorgang aufruft, steuert der Minifilter vorübergehend den E/A-Vorgang. Der Minifilter behält dieses Steuerelement bei, bis folgendes gilt:

  • Gibt einen anderen status Wert als FLT_PREOP_PENDING aus der Rückrufroutine vor dem Vorgang zurück.

  • Ruft FltCompletePendedPreOperation aus einer Arbeitsroutine auf, die einen Vorgang verarbeitet hat, der zuvor in der Rückrufroutine vor dem Vorgang enthalten war.

In der folgenden Tabelle sind einige mögliche Verwendungsszenarien der Rückrufroutine vor dem Vorgang eines Minifilters aufgeführt. Außerdem werden Implementierungsdetails und der Rückgabewert für jedes Szenario bereitgestellt.

Verwendungsszenario Implementierung Zurückgegebener Wert
Die Routine ist für den Vorgang nicht relevant und erfordert keine endgültige status des Vorgangs, oder es gibt keinen Rückruf nach dem Vorgang. Übergeben Sie den E/A-Vorgang, und weisen Sie FltMgr an, den Rückruf nach dem Vorgang des Minifilters bei Abschluss nicht aufzurufen. FLT_PREOP_SUCCESS_NO_CALLBACK
Die Routine erfordert die endgültige status des Vorgangs. Übergeben Sie den Vorgang, und weisen Sie FltMgr an, die Rückrufroutine des Minifilters nach dem Vorgang aufzurufen. FLT_PREOP_SUCCESS_WITH_CALLBACK
Der Minifilter muss diesen Vorgang in Zukunft abschließen oder fortsetzen. Versetzen Sie den Vorgang in den Status Ausstehend. Verwenden Sie FltCompletePendedPreOperation , um den Vorgang später abzuschließen. Zwischen der Voroperationsroutine, die FLT_PREOP_PENDING zurückgibt, und dem Aufruf von FltCompletePendingOperation kann ein akzeptables Rennen bestehen. FltMgr verarbeitet dieses Szenario ohne Eingabe vom Treiber. FLT_PREOP_PENDING
Die Verarbeitung nach dem Vorgang muss im Kontext desselben Threads erfolgen, den die Dispatchroutine aufgerufen hat. Diese Bedingung stellt eine konsistente IRQL-Instanz sicher und behält ihren lokalen Variablenzustand bei. Synchronisieren Sie den Vorgang mit dem Nachvorgang. FLT_PREOP_SYNCHRONIZE
Die Rückrufroutine vor dem Vorgang muss den Vorgang abschließen. Beenden Sie die Verarbeitung für den Vorgang, und weisen Sie den endgültigen NTSTATUS-Wert zu. FLT_PREOP_COMPLETE

IRQL- und Pre-Operation-Rückrufroutinen

FltMgr hat keine Möglichkeit, zu wissen, was ein Minifilter in seinem Rückruf vor dem Vorgang (oder einem Rückruf) tun könnte. Daher hat FltMgr keine Möglichkeit, zu wissen, ob ein Aufruf des Pre-Op-Rückrufs des Miniports ein Problem verursachen könnte. (Es gibt Dinge, die Sie mit erhöhten IRQL-Rechten sicher tun können, und Dinge, die Sie nicht können). Daher liegt es an dem Minifilter, IRQL zu kennen und es angemessen zu behandeln. Ein Minifilter kann KeGetCurrentIRQL sicher und kostengünstig für Situationen aufrufen, in denen er den IRQL kennen muss, zu dem er aufgerufen wurde.

Die folgenden Informationen zur Rückrufroutine irQL vor dem Vorgang eines Minifilters sind hilfreich:

  • Ein Rückruf vor dem Vorgang kann unter IRQL = PASSIVE_LEVEL oder IRQL = APC_LEVEL aufgerufen werden. Die meisten Rückrufe vor dem Vorgang werden unter IRQL = PASSIVE_LEVEL im Kontext des Threads aufgerufen, der von der E/A-Anforderung stammt. Unter IRQL = APC_LEVEL können nur eine Handvoll Rückrufe vor dem Vorgang aufgerufen werden.

  • Bei IRP-basierten Vorgängen kann der Pre-Operation-Rückruf eines Minifilters im Kontext eines Systemarbeitsthreads aufgerufen werden, wenn ein höherer Filter- oder Minifiltertreiber den Vorgang zur Verarbeitung durch den Workerthread angibt. Ein Rückruf vor dem Vorgang entspricht der Dispatchroutine eines Legacyfilters. Daher kann es hilfreich sein, den IRQL- und Threadkontext der Dispatchroutine eines Legacyfilters zu kennen.

  • Kontextobjekte können in Post-Operation-Routinen am IRQL-APC_LEVEL > nicht abgerufen werden. Stattdessen rufen Sie das Kontextobjekt während einer Routine vor dem Vorgang ab und übergeben es an die Routine nach dem Vorgang, oder führen Sie die Verarbeitung nach dem Vorgang unter IRQL <= APC_LEVEL aus. Weitere Informationen zu Kontexten finden Sie unter Verwalten von Kontexten.

Übergeben eines E/A-Vorgangs nach unten im Minifilterinstanzstapel

Abschließen eines E/A-Vorgangs in einer Rückrufroutine vor der Operation

Aufheben der Allokation eines schnellen E/A-Vorgangs in einer Preoperation-Rückrufroutine

Ausstehende E/A-Vorgänge in einer Rückrufroutine vor der Operation