Garanzia dello stato di avanzamento delle operazioni di I/O
Alcuni driver, ad esempio i driver di archiviazione per il dispositivo di paging del sistema, devono eseguire almeno alcune delle operazioni di I/O supportate senza errori, per evitare di perdere i dati critici del sistema. Una possibile causa di un errore del driver è una situazione di memoria insufficiente. Se il framework o il driver non può allocare memoria sufficiente per gestire una richiesta di I/O, una o l'altra potrebbe dover non riuscire la richiesta di I/O completandola con un valore di stato di errore.
Nelle versioni di KMDF precedenti alla versione 1.9, il framework ha sempre esito negativo una richiesta di I/O se non è in grado di allocare un oggetto richiesta framework per un pacchetto di richiesta I/O (IRP) inviato dal gestore di I/O al driver. Per offrire ai driver la possibilità di elaborare le richieste di I/O durante situazioni di memoria insufficiente, le versioni 1.9 e successive del framework offrono una funzionalità di avanzamento avanzata garantita per le code di I/O.
Questa funzionalità consente al framework e al driver di pre-allocare memoria per set di oggetti richiesta e buffer di contesto del driver correlati alla richiesta, rispettivamente. Il framework e il driver usano questa memoria preallocata solo quando la quantità di memoria di sistema è bassa.
Caratteristiche dello stato d'avanzamento garantito
Usando lo stato di avanzamento garantito del framework per le code di I/O, un driver può:
Chiedere al framework di pre-allocare un set di oggetti richiesta da usare con una coda di I/O specifica durante situazioni di memoria insufficiente.
Fornire una funzione di callback che prealloca le risorse specifiche della richiesta che il driver può usare quando riceve oggetti richiesta pre-allocati dal framework durante situazioni di memoria insufficiente.
Specificare un'altra funzione di callback che alloca risorse specifiche del driver per una richiesta di I/O quando non è stata rilevata una situazione di memoria insufficiente. Se l'allocazione di questa funzione di callback ha esito negativo a causa di una situazione di memoria insufficiente, può indicare se il framework deve usare uno degli oggetti richiesta pre-allocati.
Specificare le richieste di I/O che richiedono l'uso di oggetti richiesta pre-allocati. Le opzioni includono l'uso di oggetti preallocati per tutti i provider di integrazione, usandoli solo se è in corso un'operazione di I/O di paging o se è in corso un'ulteriore funzione di callback del driver per determinare se usare un oggetto preallocato.
Se il driver implementa lo stato di avanzamento garantito per una o più code di I/O, il driver sarà in grado di elaborare correttamente le richieste di I/O durante situazioni di memoria insufficiente. È possibile implementare lo stato di avanzamento garantito per la coda di I/O predefinita di un dispositivo e per qualsiasi coda di I/O configurata dal driver chiamando WdfDeviceConfigureRequestDispatching.
La funzionalità di avanzamento in avanti garantita del framework funziona per il driver solo se sia il driver che gli obiettivi di I/O del driver implementano lo stato di avanzamento garantito. In altre parole, se un driver implementa lo stato di avanzamento garantito per un dispositivo, tutti i driver di livello inferiore nello stack di driver del dispositivo devono implementare anche lo stato di avanzamento di avanzamento garantito.
Abilitazione dello stato di avanzamento garantito per una coda di I/O
Per abilitare lo stato di avanzamento garantito per una coda di I/O, il driver inizializza una struttura WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY e quindi chiama il metodo WdfIoQueueAssignForwardProgressPolicy . Se il driver chiama WdfDeviceConfigureRequestDispatching per configurare una coda di I/O, deve farlo prima di chiamare WdfIoQueueAssignForwardProgressPolicy.
Quando il driver chiama WdfIoQueueAssignForwardProgressPolicy, può specificare le tre funzioni di callback eventi seguenti, tutte facoltative:
EvtIoAllocateResourcesForReservedRequest
La funzione di callback EvtIoAllocateResourcesForReservedRequest di un driver alloca e archivia le risorse specifiche della richiesta per gli oggetti richiesta che il framework riserva per situazioni di memoria insufficiente.
Il framework chiama questa funzione di callback ogni volta che crea un oggetto richiesta riservata. Il driver deve allocare risorse specifiche della richiesta per una richiesta di I/O, in genere usando lo spazio di contesto dell'oggetto richiesta riservata.
EvtIoAllocateRequestResources
La funzione di callback EvtIoAllocateRequestResources di un driver alloca risorse specifiche della richiesta per l'uso immediato. Viene chiamato immediatamente dopo che il framework ha ricevuto un IRP e creato un oggetto richiesta per l'IRP.
Se il tentativo della funzione di callback di allocare le risorse ha esito negativo, la funzione di callback restituisce un valore di stato di errore. Il framework elimina quindi l'oggetto richiesta appena creato e usa uno degli oggetti richiesta riservati. A sua volta, il gestore delle richieste del driver usa risorse specifiche della richiesta allocate in precedenza dalla funzione di callback EvtIoAllocateRequestResources .
EvtIoWdmIrpForForWardProgress
La funzione di callback EvtIoWdmIrpForForWardProgress di un driver esamina un IRP e indica al framework se usare un oggetto richiesta riservata per l'IRP o se non riesce la richiesta di I/O completandola con un valore di stato di errore.
Il framework chiama questa funzione di callback solo se il framework non è in grado di creare un nuovo oggetto richiesta ed è stato indicato (impostando un flag nella struttura WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY del driver) che si desidera che il driver esamini i runtime di integrazione durante situazioni di memoria insufficiente. In altre parole, il driver può valutare ogni IRP e decidere se è uno che deve essere elaborato anche durante situazioni di memoria insufficiente.
Quando il driver chiama WdfIoQueueAssignForwardProgressPolicy, specifica anche il numero di oggetti di richiesta riservata che si vuole preassegnare il framework per situazioni di memoria insufficiente. È possibile scegliere il numero di oggetti richiesta appropriati per il dispositivo e il driver. Per evitare prestazioni ridotte, il driver deve in genere specificare un numero che approssima il numero di richieste di I/O che il driver e il dispositivo possono gestire in parallelo.
Tuttavia, se la chiamata del driver a WdfIoQueueAssignForwardProgressPolicy e alla relativa funzione di callback EvtIoAllocateResourcesForReservedRequest preallocano troppi oggetti richiesta riservati o una quantità eccessiva di memoria di risorse specifica della richiesta, il driver può effettivamente contribuire alle situazioni di memoria insufficiente che si sta tentando di gestire. È consigliabile testare le prestazioni del driver e del dispositivo e includere simulazioni a memoria insufficiente per determinare i numeri migliori da scegliere.
Prima che WdfIoQueueAssignForwardProgressPolicy restituisca, il framework crea e riserva il numero di oggetti richiesta specificati dal driver. Ogni volta che riserva un oggetto richiesta, il framework chiama immediatamente la funzione di callback EvtIoAllocateResourcesForReservedRequest del driver in modo che il driver possa allocare e salvare risorse specifiche della richiesta, nel caso in cui il framework usi effettivamente gli oggetti richiesta riservati.
Quando uno dei gestori di richieste del driver riceve una richiesta di I/O dalla coda di I/O, può chiamare il metodo WdfRequestIsReserved per determinare se l'oggetto richiesta è quello preallocato dal framework per situazioni di memoria insufficiente. Se questo metodo restituisce TRUE, il driver deve usare le risorse riservate per la funzione di callback EvtIoAllocateResourcesForReservedRequest .
Se il framework usa uno dei relativi oggetti di richiesta riservata, restituisce l'oggetto al set di oggetti riservati dopo che il driver completa la richiesta. Il framework salva l'oggetto richiesta e qualsiasi spazio di contesto creato dal driver chiamando WdfDeviceInitSetRequestAttributes o WdfObjectAllocateContext, per riutilizzarlo se si verifica un'altra situazione di memoria insufficiente.
Come il framework e il driver supportano lo stato di avanzamento garantito
Di seguito sono riportati i passaggi eseguiti dal driver e dal framework per supportare lo stato di avanzamento garantito per una coda di I/O:
Il driver chiama WdfIoQueueAssignForwardProgressPolicy.
In risposta, il framework alloca e archivia il numero di oggetti richiesta specificati dal driver. Se il driver precedentemente denominato WdfDeviceInitSetRequestAttributes, ogni allocazione include lo spazio di contesto specificato da WdfDeviceInitSetRequestAttributes .
Inoltre, se il driver ha fornito una funzione di callback EvtIoAllocateResourcesForReservedRequest , il framework chiama la funzione di callback ogni volta che alloca e archivia un oggetto richiesta.
Il framework riceve un pacchetto di richiesta di I/O che il gestore di I/O invia al driver.
Il framework tenta di allocare un oggetto richiesta per l'IRP. Se la coda di I/O creata dal driver per il tipo di richiesta supporta lo stato di avanzamento garantito, il passaggio successivo dipende dal fatto che l'allocazione abbia esito positivo o negativo:
L'allocazione dell'oggetto richiesta ha esito positivo.
Se il driver ha fornito una funzione di callback EvtIoAllocateRequestResources , il framework lo chiama. Se la funzione di callback restituisce STATUS_SUCCESS, il framework aggiunge la richiesta alla coda di I/O. Se la funzione di callback restituisce un valore di stato di errore, il framework elimina l'oggetto richiesta appena creato e usa uno degli oggetti richiesta pre-allocati. Quando il gestore della richiesta del driver riceve l'oggetto richiesta, determina se l'oggetto richiesta è stato pre-allocato e quindi se deve usare le risorse preallocate del driver.
Se il driver non ha fornito una funzione di callback EvtIoAllocateRequestResources , il framework aggiunge la richiesta alla coda di I/O, come se il driver non avesse abilitato lo stato di avanzamento in avanti garantito.
L'allocazione dell'oggetto richiesta ha esito negativo.
L'operazione successiva del framework dipende dal valore fornito dal driver per il membro ForwardProgressReservedPolicy della struttura WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY . Questo membro informa il framework quando usare una richiesta riservata: sempre, solo se la richiesta di I/O è un'operazione di I/O di paging o solo se la funzione di callback EvtIoWdmIrpForWardProgress indica che deve essere usata una richiesta riservata.
In tutti i casi, i gestori di richieste del driver possono chiamare WdfRequestIsReserved per determinare se il framework ha usato un oggetto richiesta riservata. In tal caso, il driver deve usare le risorse di richiesta allocate dalla funzione di callback EvtIoAllocateResourcesForReservedRequest .
Scenario di avanzamento di avanzamento garantito
Si sta scrivendo un driver per un dispositivo di archiviazione che potrebbe contenere il file di paging del sistema. È importante che le operazioni di lettura e scrittura nel file di paging abbiano esito positivo.
Si decide di creare code di I/O separate per le operazioni di lettura e scrittura e di abilitare lo stato di avanzamento in avanti garantito per entrambe le code di I/O. Si decide di creare una terza coda di I/O per tutti gli altri tipi di richiesta senza abilitare lo stato di avanzamento dell'inoltro garantito.
Lo stack di driver e il dispositivo sono in grado di elaborare quattro operazioni di scrittura in parallelo, quindi si imposta il membro TotalForwardProgressRequests della struttura WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY su 4 prima di chiamare WdfIoQueueAssignForwardProgressPolicy.
Si decide che garantire lo stato di avanzamento è importante solo se il dispositivo del driver è il dispositivo di paging, quindi il driver imposta il membro ForwardProgressReservedPolicy della struttura WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY su WdfIoForwardProgressReservedPolicyPagingIO.
Poiché il driver richiede un oggetto memoria framework per ogni richiesta di lettura e ogni richiesta di scrittura, si decide che il driver deve pre-allocare alcuni oggetti memoria da usare per le chiamate a WdfIoTargetFormatRequestForRead e WdfIoTargetFormatRequestForWrite in situazioni di memoria insufficiente.
Di conseguenza, il driver fornisce una funzione di callback EvtIoAllocateResourcesForReservedRequest per la coda di lettura e un'altra per la coda di scrittura. Ogni volta che il framework chiama una di queste funzioni di callback, la funzione di callback chiama WdfMemoryCreate e salva l'handle oggetto restituito per situazioni di memoria insufficiente. Poiché la funzione di callback riceve un handle per un oggetto richiesta preallocato, può padre l'oggetto memory all'oggetto richiesta. Un driver per un dispositivo DMA potrebbe anche pre-allocare oggetti DMA del framework.
I gestori di richieste per le code di lettura e scrittura devono determinare se ogni oggetto richiesta ricevuto è uno riservato al framework per situazioni di memoria insufficiente. Un gestore di richieste può chiamare WdfRequestIsReserved oppure può confrontare l'handle dell'oggetto richiesta con quelli ricevuti in precedenza dalla funzione di callback EvtIoAllocateResourcesForReservedRequest .
Il driver fornisce anche una funzione di callback EvtIoAllocateRequestResources per la coda di lettura e un'altra per la coda di scrittura. Il framework chiama una di queste funzioni di callback quando riceve una richiesta di lettura o scrittura dal gestore di I/O e crea correttamente un oggetto richiesta. Ognuna di queste funzioni di callback chiama WdfMemoryCreate per allocare un oggetto memoria per una richiesta. Se l'allocazione non riesce, la funzione di callback restituisce un valore di stato di errore per notificare al framework che si è appena verificata una situazione di memoria insufficiente. Il framework, rilevando il valore restituito dell'errore, elimina l'oggetto richiesta appena creato e usa uno degli oggetti preallocati.
Questo driver non fornisce una funzione di callback EvtIoWdmIrpForForwardProgress , perché non è necessario esaminare singoli runtime di integrazione di lettura o scrittura prima che il framework li aggiaggiu a una coda di I/O.
Tenere presente che quando un driver implementa lo stato di avanzamento garantito per un dispositivo, tutti i driver di livello inferiore nello stack di driver del dispositivo devono implementare anche lo stato di avanzamento di avanzamento garantito.