Implementazione di una routine IoCompletion
Nella voce, una routine IoCompletion riceve un puntatore Context . Quando una routine dispatch chiama IoSetCompletionRoutine, può fornire un puntatore context . Questo puntatore può fare riferimento a qualsiasi informazione del contesto determinata dal driver richiesta dalla routine IoCompletion per elaborare un IRP. Si noti che l'area di contesto non può essere impaginabile perché la routine IoCompletion può essere chiamata in IRQL = DISPATCH_LEVEL.
Considerare le linee guida di implementazione seguenti per le routine IoCompletion:
Una routine IoCompletion può controllare il blocco di stato I/O di I/O di IRP per determinare il risultato dell'operazione di I/O.
Se l'IRP di input è stato allocato dalla routine dispatch usando IoAllocateIrp o IoBuildAsynchronousFsdRequest, la routine IoCompletion deve chiamare IoFreeIrp per rilasciare tale IRP, preferibilmente prima di completare l'IRP originale.
La routine IoCompletion deve rilasciare qualsiasi risorsa per IRP la routine dispatch allocata per l'IRP allocata dal driver, preferibilmente prima di liberare l'IRP corrispondente.
Ad esempio, se la routine dispatch alloca un MDL con IoAllocateMdl e chiama IoBuildPartialMdl per un IRP di trasferimento parziale allocato, la routine IoCompletion deve rilasciare MDL con IoFreeMdl. Se alloca le risorse per mantenere lo stato relativo all'IRP originale, deve liberare tali risorse, preferibilmente prima di chiamare IoCompleteRequest con l'IRP originale e sicuramente prima che restituisca il controllo.
In generale, prima di liberare o completare un IRP, la routine IoCompletion deve liberare tutte le risorse per IRP allocate dalla routine Dispatch. In caso contrario, il driver deve mantenere lo stato delle risorse da liberare prima che la routine IoCompletion restituisca il controllo dal completamento della richiesta originale.
Se la routine IoCompletion non può completare l'IRP originale con STATUS_SUCCESS, deve impostare il blocco di stato di I/O nell'IRP originale sul valore restituito nell'IRP allocato dal driver che ha causato l'esito negativo della richiesta originale.
Se la routine IoCompletion completerà la richiesta originale con STATUS_PENDING, deve chiamare IoMarkIrpPending con l'IRP originale prima di chiamare IoCompleteRequest.
Se la routine IoCompletion deve non riuscire l'IRP originale con un errore STATUS_XXX, può registrare un errore. Tuttavia, è responsabilità del driver di dispositivo sottostante registrare eventuali errori di I/O del dispositivo che si verificano, pertanto le routine IoCompletion in genere non registrano errori.
Quando la routine IoCompletion è stata elaborata e liberata l'IRP allocata dal driver, la routine deve restituire il controllo con STATUS_MORE_PROCESSING_REQUIRED.
La restituzione di STATUS_MORE_PROCESSING_REQUIRED dalla routine IoCompletion impedisce l'elaborazione del completamento del gestore di I/O per un IRP allocato e liberato dal driver. Una seconda chiamata a IoCompleteRequest fa sì che il gestore di I/O riprenda a chiamare le routine di completamento di IRP, a partire dalla routine di completamento immediatamente sopra la routine che ha restituito STATUS_MORE_PROCESSING_REQUIRED.
Se la routine IoCompletion riutilizza un IRP in ingresso per inviare una o più richieste a driver inferiori o se la routine ritenta le operazioni non riuscite, è necessario aggiornare il contesto gestito dalla routine IoCompletion per ogni riutilizzo o nuovo tentativo di IRP. Può quindi configurare di nuovo la posizione dello stack di I/O del driver inferiore successivo, chiamare IoSetCompletionRoutine con il proprio punto di ingresso e chiamare IoCallDriver per L'IRP.
La routine IoCompletion non deve chiamare IoMarkIrpPending a ogni riutilizzo o nuovo tentativo di IRP.
La routine dispatch ha già contrassegnato l'IRP originale come in sospeso. Fino a quando tutti i driver della catena completano l'IRP originale con IoCompleteRequest, rimane in sospeso.
Prima di ritentare una richiesta, la routine IoCompletion deve reimpostare il blocco di stato di I/O con STATUS_SUCCESS per Stato e zero per Informazioni, eventualmente dopo aver salvato le informazioni sull'errore restituite.
Per ogni nuovo tentativo, la routine IoCompletion in genere decrementa un numero di tentativi configurato dalla routine Dispatch. In genere, la routine IoCompletion deve chiamare IoCompleteRequest per eseguire l'errore di IRP quando un numero limitato di tentativi non è riuscito.
La routine IoCompletion deve restituire STATUS_MORE_PROCESSING_REQUIRED dopo aver chiamato IoSetCompletionRoutine e IoCallDriver con un IRP riutilizzato o ritentato.
La restituzione di STATUS_MORE_PROCESSING_REQUIRED dalla routine IoCompletion impedisce il completamento dell'elaborazione del gestore di I/O di un IRP riutilizzato o ritentato.
Se la routine IoCompletion non può completare l'IRP originale con STATUS_SUCCESS, deve lasciare il blocco di stato di I/O restituito da driver inferiori per l'operazione di riutilizzo o ripetizione dei tentativi che causa l'esito negativo della routine IoCompletion .
Se la routine IoCompletion completerà la richiesta originale con STATUS_PENDING, deve chiamare IoMarkIrpPending con l'IRP originale prima di chiamare IoCompleteRequest.
Se la routine IoCompletion deve non riuscire l'IRP originale con un errore STATUS_XXX, può registrare un errore. Tuttavia, è responsabilità del driver di dispositivo sottostante registrare eventuali errori di I/O del dispositivo che si verificano, pertanto le routine IoCompletion in genere non registrano errori.
Qualsiasi driver che imposta una routine IoCompletion in un IRP e quindi passa l'IRP a un driver inferiore deve controllare il flag IRP-PendingReturned> nella routine IoCompletion. Se il flag è impostato, la routine IoCompletion deve chiamare IoMarkIrpPending con IRP. Si noti, tuttavia, che un driver che passa l'IRP e quindi attende un evento non deve contrassegnare l'IRP in sospeso. Al contrario, la routine IoCompletion deve segnalare l'evento e restituire STATUS_MORE_PROCESSING_REQUIRED.
La routine IoCompletion deve rilasciare tutte le risorse allocate dalla routine dispatch per l'elaborazione dell'IRP originale, preferibilmente prima che la routine IoCompletion chiami IoCompleteRequest con l'IRP originale e sicuramente prima che la routine IoCompletion restituisca il controllo dal completamento dell'IRP originale.
Se un driver di livello superiore ha impostato la routine IoCompletion nell'IRP originale, la routine IoCompletion del driver non viene chiamata finché non vengono chiamate le routine IoCompletion di tutti i driver di livello inferiore.
Fornitura di un boost di priorità nelle chiamate a IoCompleteRequest
Se un driver di dispositivo di livello più basso può completare un IRP nella routine dispatch, chiama IoCompleteRequest con priorityBoost di IO_NO_INCREMENT. Non è necessario alcun aumento della priorità di runtime perché il driver può presupporre che il richiedente originale non abbia aspettato il completamento dell'operazione di I/O.
In caso contrario, il driver di livello più basso fornisce un valore specifico del tipo di dispositivo e definito dal sistema che aumenta la priorità di runtime del richiedente per compensare il tempo di attesa del richiedente sulla richiesta di I/O del dispositivo. Per i valori di boost, vedere Wdm.h o Ntddk.h.
I driver di livello superiore applicano lo stesso priorityBoost dei rispettivi driver di dispositivo sottostanti quando chiamano IoCompleteRequest.
Effetto della chiamata A IoCompleteRequest
Quando un driver chiama IoCompleteRequest, il gestore di I/O riempie la posizione dello stack di I/O del driver con zeri prima di chiamare il driver di livello superiore successivo, se presente, che ha configurato una routine IoCompletion da chiamare per l'IRP.
Una routine IoCompletion del driver di livello superiore può controllare solo il blocco di stato di I/O di I/O di IRP per determinare come tutti i driver inferiori hanno gestito la richiesta.
Il chiamante di IoCompleteRequest non deve tentare di accedere all'IRP appena completato. Un tentativo di questo tipo è un errore di programmazione che causa un arresto anomalo del sistema.