Linee guida per il porting dei driver di filtro legacy
Gli sviluppatori sono invitati a convertire i driver di filtro legacy nel modello di gestione filtri per ottenere funzionalità migliori per i driver di filtro e migliorare l'affidabilità del sistema. Gli sviluppatori esperti dovrebbero trovare relativamente facile convertire un driver di filtro legacy in un driver minifiltro. Gli sviluppatori di driver di filtro in Microsoft consigliano l'approccio seguente:
Iniziare con un gruppo di test di regressione affidabile per verificare il comportamento tra il driver di filtro legacy e il driver minifiltro convertito.
Creare una struttura di base per il driver minifiltro e trasferire sistematicamente le funzioni dal driver filtro legacy al driver minifiltro. Ad esempio, fare in modo che l'allegato funzioni e poi portare un'operazione alla volta, testando dopo ogni operazione.
Modificare per ultima la comunicazione in modalità utente/kernel, in modo da poter utilizzare gli strumenti esistenti per testare il driver minifiltro.
Esegui la compilazione con PREfast e testa con l'opzione di verifica del filtro I/O nel Driver Verifier abilitata.
Durante il processo di conversione, è consigliabile esaminare tutto il codice del driver di filtro legacy per sfruttare al meglio le funzionalità di gestione filtri. In particolare, tenere presente quanto segue:
Le operazioni di I/O basate su IRP e quelle veloci possono essere eseguite tramite la stessa operazione, se appropriato, il che aiuta a ridurre la duplicazione del codice.
Quando si esegue la registrazione per le operazioni, un driver minifiltro può scegliere in modo esplicito di ignorare tutte le operazioni di I/O di paging e di I/O memorizzate nella cache, eliminando così la necessità di controllare il codice.
Le notifiche di istanza semplificano notevolmente la logica di collegamento/scollegamento.
Registrati solo per le operazioni che il tuo driver minifiltro deve gestire; è possibile ignorare tutto il resto.
Approfittare del supporto per la gestione del contesto e dei nomi dei filtri.
Sfrutta il supporto del gestore dei filtri per emettere operazioni di I/O non ricorsive.
A differenza dei driver di filtro legacy, i driver minifilter non possono basarsi sulle variabili locali per mantenere il contesto dall'elaborazione preoperatoria all'elaborazione della postoperazione. Valutare la possibilità di allocare un elenco lookaside per archiviare lo stato dell'operazione.
Assicurarsi di rilasciare i riferimenti quando hai terminato di usare un nome o un contesto.
Le porte di completamento in modalità utente aggiungono una tecnica potente per la costruzione di code. Probabilmente sarà necessaria una sola connessione a una singola porta denominata.
Nella tabella seguente sono elencate le operazioni comuni in un driver di filtro legacy e il relativo mapping al modello di gestione filtri.
Modello di driver di filtro legacy | Modello di gestione filtri |
---|---|
Operazione pass-through senza routine di completamento |
Se il driver minifilter non funziona mai per questo tipo di operazione di I/O, non registrare una routine di callback di preoperazione o postoperazione per questa operazione. In caso contrario, restituire FLT_PREOP_SUCCESS_NO_CALLBACK dalla routine di callback di preoperazione registrata per questa operazione. |
Operazione di pass-through con una routine di completamento |
Restituisce FLT_PREOP_SUCCESS_WITH_CALLBACK dalla routine di callback di preoperazione. |
Operazione pend nella routine di callback di preoperazione |
Chiamare FltLockUserBuffer in base alle esigenze per assicurarsi che tutti i buffer utente siano bloccati correttamente in modo che possano essere accessibili in un thread di lavoro. Accodare il lavoro a un thread di lavoro chiamando routine di supporto come FltAllocateDeferredIoWorkItem e FltQueueDeferredIoWorkItem. Restituisce FLT_PREOP_PENDING dalla routine di callback di preoperazione. Quando si è pronti a restituire l'operazione di I/O al gestore filtri, chiamare FltCompletePendedPreOperation. Vedere In sospeso un'operazione di I/O in una routine di callback di preoperazione. |
Operazione di attesa nella routine di callback post-operazione |
Nella routine di callback di preoperazione chiamare FltLockUserBuffer per assicurarsi che i buffer utente siano bloccati correttamente in modo che possano essere accessibili in un thread di lavoro. Accodare il lavoro a un thread di lavoro chiamando routine di supporto come FltAllocateGenericWorkItem e FltQueueGenericWorkItem. Restituisce FLT_POSTOP_MORE_PROCESSING_REQUIRED dalla routine di callback di postoperazione. Quando si è pronti a restituire l'operazione di I/O al gestore dei filtri, chiamare FltCompletePendedPostOperation. Consultare In sospeso un'operazione di I/O in una routine di callback post-operativa. |
Sincronizzare l'operazione |
Restituisce FLT_PREOP_SYNCHRONIZE dalla routine di callback di preoperazione. |
Completare l'operazione nella routine di callback di preoperazione |
Impostare lo stato dell'operazione finale e le informazioni nel membro IoStatus della struttura FLT_CALLBACK_DATA per l'operazione. Restituisce FLT_PREOP_COMPLETE dalla routine di callback di preoperazione. Vedere Completamento di un'operazione di I/O in una routine di callback di preoperazione. |
Completare l'operazione dopo che è stata messa in attesa nella routine di callback di preoperazione |
Impostare lo stato dell'operazione finale e le informazioni nel membro IoStatus della struttura FLT_CALLBACK_DATA per l'operazione. Chiamare FltCompletePendedPreOperation dal thread di lavoro che elabora l'operazione di I/O passando FLT_PREOP_COMPLETE come parametro CallbackStatus . Vedere Completamento di un'operazione di I/O in una routine di callback di preoperazione. |
Eseguire tutte le operazioni di completamento nella routine di completamento |
Restituisce FLT_POSTOP_FINISHED_PROCESSING dalla routine di callback di postoperazione. Consultare Scrittura di routine di callback postoperazione. |
Eseguire il lavoro di completamento in IRQL sicuro |
Chiamare FltDoCompletionProcessingWhenSafe dalla routine di callback di postoperation. Consultare Assicurarsi che l'elaborazione del completamento venga eseguita a IRQL sicuro. |
Segnalare un evento nella routine di completamento |
Restituisce FLT_PREOP_SYNCHRONIZE dalla routine di callback di preoperazione per questa operazione. Il gestore dei filtri chiama la routine di callback di postoperazione nello stesso contesto del thread della routine di callback di preoperazione, in IRQL <= APC_LEVEL. |
Esito negativo di un'operazione di creazione riuscita |
Chiamare FltCancelFileOpen dalla routine di callback di postoperation per l'operazione di creazione. Impostare un valore NTSTATUS di errore appropriato nel membro IoStatus della struttura FLT_CALLBACK_DATA per l'operazione. Restituire FLT_POSTOP_FINISHED_PROCESSING. Fare riferimento a Errore in un'operazione di I/O in una routine di callback post-operazione. |
Non consentire l'I/O tramite il percorso di I/O rapido per un'operazione di I/O |
Restituire FLT_STATUS_DISALLOW_FAST_IO dalla routine di callback di preoperazione per l'operazione. |
Modificare i parametri per un'operazione di I/O |
Impostare i valori dei parametri modificati nel membro Iopb della struttura FLT_CALLBACK_DATA per l'operazione. Contrassegnare la struttura FLT_CALLBACK_DATA come dirty chiamando FltSetCallbackDataDirty, tranne quando è stato modificato il contenuto del membro IoStatus della struttura FLT_CALLBACK_DATA. |
Bloccare il buffer utente per l'operazione |
Usare le tecniche e le linee guida descritte in Accesso ai buffer utente per un'operazione di I/O. |