Richtlinien für das Portieren von Legacyfiltertreibern
Entwickler werden ermutigt, ältere Filtertreiber auf das Filter-Manager-Modell zu portieren, um eine bessere Funktionalität für ihre Filtertreiber zu erhalten und die Systemzu zuverlässigkeit zu verbessern. Erfahrene Entwickler sollten es relativ einfach finden, einen Legacyfiltertreiber auf einen Minifiltertreiber zu portieren. Filtertreiberentwickler bei Microsoft empfehlen den folgenden Ansatz:
Beginnen Sie mit einer zuverlässigen Regressionstestsuite, um das Verhalten zwischen dem Legacyfiltertreiber und dem portierten Minifiltertreiber zu überprüfen.
Erstellen Sie eine Minifiltertreibershell, und verschieben Sie die Funktionalität systematisch vom Legacyfiltertreiber in den Minifiltertreiber. Sie können z. B. die Anlage zum Arbeiten bringen und dann einen Vorgang gleichzeitig portieren und nach jedem Vorgang testen.
Ändern Sie zuletzt die Kommunikation zwischen Benutzermodus und Kernelmodus, sodass Sie vorhandene Tools verwenden können, um den Minifiltertreiber zu testen.
Kompilieren Sie mit PREfast, und testen Sie mit aktivierter Option Filter Verifier E/A-Überprüfung in der Treiberüberprüfung.
Während des Portierungsprozesses sollten Sie den gesamten Legacy-Filtertreibercode überprüfen, um die Funktionen des Filter-Managers in vollem Umfang zu nutzen. Beachten Sie insbesondere Folgendes:
IRP-basierte E/A-Vorgänge und schnelle E/A-Vorgänge können bei Bedarf denselben Vorgang durchlaufen, was zur Verringerung von Codeduplizierungen beiträgt.
Bei der Registrierung für Vorgänge kann ein Minifiltertreiber explizit auswählen, dass er alle aus Paging-E/A und zwischengespeicherten E/A-Vorgänge ignoriert, sodass kein Code mehr erforderlich ist, um diese zu überprüfen.
Instanzbenachrichtigungen vereinfachen die Logik zum Anfügen/Trennen erheblich.
Registrieren Sie sich nur für Vorgänge, die Ihr Minifiltertreiber verarbeiten muss. Sie können alles andere ignorieren.
Nutzen Sie die Unterstützung für den Kontext und die Namensverwaltung des Filter-Managers.
Nutzen Sie die Filter-Manager-Unterstützung für die Ausgabe nicht rekursiver E/A.
Im Gegensatz zu Legacyfiltertreibern können Minifiltertreiber nicht auf lokale Variablen angewiesen sein, um den Kontext von der Präoperationsverarbeitung bis zur Postoperationsverarbeitung beizubehalten. Erwägen Sie, eine Suchliste zuzuweisen, um den Vorgangsstatus zu speichern.
Stellen Sie sicher, dass Verweise freigegeben werden, wenn sie mit einem Namen oder Kontext abgeschlossen sind.
Vervollständigungsports im Benutzermodus fügen eine leistungsfähige Technik zum Erstellen von Warteschlangen hinzu. Sie benötigen wahrscheinlich nur eine einzelne Verbindung mit einem einzelnen benannten Port.
In der folgenden Tabelle sind allgemeine Vorgänge in einem Legacyfiltertreiber und deren Zuordnung zum Filter-Manager-Modell aufgeführt.
Legacy-Filtertreibermodell | Filter-Managermodell |
---|---|
Passthrough-Vorgang ohne Vervollständigungsroutine |
Wenn Ihr Minifiltertreiber für diese Art von E/A-Vorgängen nie funktioniert, registrieren Sie keine Preoperation- oder Postoperation-Rückrufroutine für diesen Vorgang. Andernfalls geben Sie FLT_PREOP_SUCCESS_NO_CALLBACK aus der für diesen Vorgang registrierten Rückrufroutine vor der Operation zurück. Weitere Informationen finden Sie unter Zurückgeben von FLT_PREOP_SUCCESS_NO_CALLBACK. |
Passthrough-Vorgang mit einer Vervollständigungsroutine |
Gibt FLT_PREOP_SUCCESS_WITH_CALLBACK aus der Rückrufroutine vor der Operation zurück. Weitere Informationen finden Sie unter Zurückgeben von FLT_PREOP_SUCCESS_WITH_CALLBACK. |
Pend-Vorgang in der Rückrufroutine vor der Operation |
Rufen Sie FltLockUserBuffer nach Bedarf auf, um sicherzustellen, dass alle Benutzerpuffer ordnungsgemäß gesperrt sind, sodass in einem Workerthread darauf zugegriffen werden kann. Stellen Sie die Arbeit in eine Warteschlange für einen Workerthread ein, indem Sie Supportroutinen wie FltAllocateDeferredIoWorkItem und FltQueueDeferredIoWorkItem aufrufen. Gibt FLT_PREOP_PENDING aus der Rückrufroutine vor der Operation zurück. Wenn Sie bereit sind, den E/A-Vorgang an den Filter-Manager zurückzugeben, rufen Sie FltCompletePendedPreOperation auf. Weitere Informationen finden Sie unter Ausstehen eines E/A-Vorgangs in einer Rückrufroutine vor der Operation. |
Pend-Vorgang in der Rückrufroutine nach der Operation |
Rufen Sie in der Rückrufroutine vor der Operation FltLockUserBuffer auf, um sicherzustellen, dass Benutzerpuffer ordnungsgemäß gesperrt sind, sodass in einem Workerthread darauf zugegriffen werden kann. Stellen Sie die Arbeit an einem Workerthread in eine Warteschlange, indem Sie Supportroutinen wie FltAllocateGenericWorkItem und FltQueueGenericWorkItem aufrufen. Gibt FLT_POSTOP_MORE_PROCESSING_REQUIRED aus der Rückrufroutine nach der Operation zurück. Wenn Sie bereit sind, den E/A-Vorgang an den Filter-Manager zurückzugeben, rufen Sie FltCompletePendedPostOperation auf. Weitere Informationen finden Sie unter Ausstehen eines E/A-Vorgangs in einer Postoperation-Rückrufroutine. |
Synchronisieren des Vorgangs |
Gibt FLT_PREOP_SYNCHRONIZE aus der Rückrufroutine vor der Operation zurück. Weitere Informationen finden Sie unter Zurückgeben von FLT_PREOP_SYNCHRONIZE. |
Abschließen des Vorgangs in der Rückrufroutine vor der Operation |
Legen Sie den endgültigen Vorgang status und Informationen im IoStatus-Member der FLT_CALLBACK_DATA-Struktur für den Vorgang fest. Gibt FLT_PREOP_COMPLETE aus der Rückrufroutine vor der Operation zurück. Weitere Informationen finden Sie unter Abschließen eines E/A-Vorgangs in einer Rückrufroutine vor der Operation. |
Schließen Sie den Vorgang ab, nachdem er in der Rückrufroutine vor der Operation geschrieben wurde. |
Legen Sie den endgültigen Vorgang status und Informationen im IoStatus-Member der FLT_CALLBACK_DATA-Struktur für den Vorgang fest. Rufen Sie FltCompletePendedPreOperation aus dem Workerthread auf, der den E/A-Vorgang verarbeitet, und übergeben Sie FLT_PREOP_COMPLETE als CallbackStatus-Parameter . Weitere Informationen finden Sie unter Abschließen eines E/A-Vorgangs in einer Rückrufroutine vor der Operation. |
Ausführen aller Vervollständigungsarbeiten in der Vervollständigungsroutine |
Gibt FLT_POSTOP_FINISHED_PROCESSING aus der Rückrufroutine nach der Operation zurück. Weitere Informationen finden Sie unter Schreiben von Postoperation-Rückrufroutinen. |
Ausführen von Vervollständigungsarbeiten bei sicherem IRQL |
Rufen Sie FltDoCompletionProcessingWhenSafe aus der Rückrufroutine postoperation auf. Weitere Informationen finden Sie unter Sicherstellen, dass die Vervollständigungsverarbeitung am sicheren IRQL ausgeführt wird. |
Signalisieren eines Ereignisses aus der Abschlussroutine |
Gibt FLT_PREOP_SYNCHRONIZE aus der Rückrufroutine vor der Operation für diesen Vorgang zurück. Der Filter-Manager ruft die Postoperation-Rückrufroutine im gleichen Threadkontext wie die Preoperation-Rückrufroutine unter IRQL <= APC_LEVEL auf. Weitere Informationen finden Sie unter Zurückgeben von FLT_PREOP_SYNCHRONIZE. |
Fehler bei einem erfolgreichen Erstellungsvorgang |
Rufen Sie FltCancelFileOpen aus der Rückrufroutine postoperation für den Erstellungsvorgang auf. Legen Sie einen entsprechenden NTSTATUS-Fehlerwert im IoStatus-Member der FLT_CALLBACK_DATA-Struktur für den Vorgang fest. Gibt FLT_POSTOP_FINISHED_PROCESSING zurück. Weitere Informationen finden Sie unter Fehler bei einem E/A-Vorgang in einer Postoperation-Rückrufroutine. |
E/A über den schnellen E/A-Pfad für einen E/A-Vorgang nicht zulassen |
Gibt FLT_STATUS_DISALLOW_FAST_IO aus der Rückrufroutine für den Vorgang vor der Operation zurück. Weitere Informationen finden Sie unter Aufheben der Zuordnung eines schnellen E/A-Vorgangs in einer Rückrufroutine vor der Operation. |
Ändern der Parameter für einen E/A-Vorgang |
Legen Sie die geänderten Parameterwerte im Iopb-Member der FLT_CALLBACK_DATA-Struktur für den Vorgang fest. Markieren Sie die FLT_CALLBACK_DATA-Struktur als modifiziert, indem Sie FltSetCallbackDataDirty aufrufen, es sei denn, Sie haben den Inhalt des IoStatus-Members der FLT_CALLBACK_DATA-Struktur geändert. Weitere Informationen finden Sie unter Ändern der Parameter für einen E/A-Vorgang. |
Sperren des Benutzerpuffers für den Vorgang |
Verwenden Sie die Unter Zugreifen auf benutzerpuffer für einen E/A-Vorgang beschriebenen Techniken und Richtlinien. |