Gestione delle richieste di paging PnP

Un driver di filtro di archiviazione deve gestire le richieste di paging PnP (IRP_MJ_PNP con IRP_MN_DEVICE_USAGE_NOTIFICATION e Parameters.UsageNotification.Type impostato su DeviceUsageTypePaging) se il driver di funzione che sta filtrando gestisce questo IRP.

Gli elementi seguenti devono essere aggiunti all'oggetto DeviceExtension di Filter DO:

ULONG PagingCount;

KEVENT PagingCountEvent;

Quando si ricevono richieste di paging PnP, un driver del filtro di archiviazione deve aggiornare sia pagingCount che l'impostazione del bit DO_POWER_PAGABLE in Filtro DO. L'intervallo dell'aggiornamento del bit DO_POWER_PAGABLE dipende dal fatto che il bit sia impostato o cancellato. Se l'IRP indica che il bit deve essere impostato, il driver di filtro deve impostarlo prima di inoltrare l'IRP nello stack di driver. Tuttavia, se l'IRP indica che il bit deve essere cancellato, il driver di filtro non deve cancellare immediatamente il bit. Deve prima inoltrare l'IRP, quindi attendere che i driver inferiori restituiscano lo stato e cancellano il bit solo se i driver inferiori restituiscono STATUS_SUCCESS.

Di seguito viene tracciato il flusso delle azioni eseguite dal driver del filtro di archiviazione. Fare riferimento all'esempio di pseudocodice immediatamente sotto la struttura per visualizzare una rappresentazione di questa struttura nel codice C:

A. Verificare che il dispositivo sia stato avviato. In caso contrario, eseguire l'operazione con STATUS_DEVICE_NOT_READY.

B. Eseguire la sincronizzazione in PagingCountEvent (KeWaitForSingleObject( PagingCountEvent, ...)).

C. Se si rimuove l'ultimo dispositivo di paging ( (! Parameters.UsageNotification.InPath && (PagingCount == 1) )

  1. Impostare un valore booleano locale su TRUE e

  2. Se il bit DO_POWER_INRUSH non è impostato in Filtro DO, impostare il bit DO_POWER_PAGABLE .

    Di seguito viene illustrato il motivo per cui il bit di DO_POWER_PAGABLE deve essere impostato sulla strada verso il basso e non sulla strada verso l'alto:

    I requisiti di alimentazione dichiarano che se un oggetto dispositivo inferiore imposta il bit DO_POWER_PAGABLE , tutti i driver di livello superiore devono eseguire la stessa operazione. Se il driver di filtro non riesce a impostare il bit di DO_POWER_PAGABLE prima di inviare la richiesta di paging IRP nello stack, potrebbe violare questa condizione come indicato di seguito:

    Si supponga che il driver di filtro non imposti il bit di DO_POWER_PAGABLE nel filtro DO prima di inoltrare l'IRP della richiesta di paging ai driver sottostanti nello stack di driver. Si supponga quindi che un driver inferiore imposti il bit di DO_POWER_PAGABLE nel proprio DO. Infine, si supponga che prima del completamento dell'IRP da parte del driver di filtro venga generata un'alimentazione IRP. A questo punto, il bit di DO_POWER_PAGABLE verrebbe cancellato in Filtro DO, ma verrebbe impostato nell'operazione do del driver di livello inferiore, causando un arresto anomalo del sistema.

    È possibile impostare il bit di DO_POWER_PAGABLE prima di inoltrare una richiesta di paging verso il basso nello stack, perché non è più presente un file di paging attivo nel dispositivo del driver di filtro e quindi non verranno eseguite altre operazioni di I/O di paging. Se la richiesta di rimozione di questo file di paging ha esito positivo, verrà eseguito il driver di filtro. Se la richiesta ha esito negativo, il driver di filtro può ripristinare lo stato originale dei flag semplicemente cancellando il bit DO_POWER_PAGABLE prima di completare l'IRP. Poiché le richieste di file di paging vengono serializzate, non c'è pericolo che un altro thread abbia modificato questo bit perché il driver di filtro l'ha modificato per ultimo.

D. Inoltrare in modo sincrono l'IRP ai driver inferiori.

E. Se l'IRP viene completato correttamente,

  1. Chiamare IoAdjustPagingPathCount(&PagingCount, Parameters.UsageNotification.InPath) per incrementare o decrementare pagingCount. IoAdjustPagingPathCount esegue un interlockedIncrement o InterlockedDecrement di PagingCount a seconda del valore in Parameters.UsageNotification.InPath. Un valore TRUE indica che viene aggiunto un file di paging, quindi incrementare pagingCount; Un valore FALSE indica che un file di paging viene rimosso, quindi decrementa pagingCount.

  2. Se Parameters.UsageNotification.InPath è TRUE, viene aggiunto un file di paging, quindi cancellare il bit DO_POWER_PAGABLE .

F. In caso contrario, se l'IRP ha esito negativo,

  1. Controllare il valore booleano locale per verificare se DO_POWER_PAGABLE è stato impostato in Filtro DO sulla strada verso il basso.Check the local Boolean to see if DO_POWER_PAGABLE was set in the Filter DO on the way down.

  2. Se DO_POWER_PAGABLE è stato impostato sulla strada verso il basso, cancellarlo.

G. Sincronizzazione di fine (KeSetEvent(PagingCountEvent, ...)).

Esempio di pseudocodice

Le sezioni contrassegnate da lettere (//A, //B e così via) nell'esempio di codice seguente eseguono il mapping alle lettere della struttura precedente.

case DeviceUsageTypePaging: { 
    BOOLEAN setPageable = FALSE; 
    BOOLEAN addPageFile = irpStack -> 
                          Parameters.UsageNotification.InPath; 
 
 // A 
    if((addPageFile) && 
        (extension -> CurrentPnpState != 
        IRP_MN_START_DEVICE)) { 
            status = STATUS_DEVICE_NOT_READY; 
            break; 
        } 
 // B 
    KeWaitForSingleObject(&commonExtension -> PagingCountEvent, 
                                    Executive, KernelMode, 
                                    FALSE, NULL); 
 // C 
    if (!addPageFile && commonExtension -> PagingCount == 1 ) { 
        // The last paging file is no longer active.
        // Set the DO_POWER_PAGABLE bit before 
        // forwarding the paging request down the 
        // stack.
        if (!(DeviceObject->Flags & DO_POWER_INRUSH)) { 
            DeviceObject->Flags |=             DO_POWER_PAGABLE; 
            setPageable = TRUE; 
        ) 
    ) 
 // D 
        status = ForwardIrpSynchronous(commonExtension, Irp); 
 // E
        if (NT_SUCCESS(status)) { 
            IoAdjustPagingPathCount(&commonExtension -> PagingCount, 
                                    addPageFile); 
        if (addPageFile && commonExtension -> PagingCount == 1) { 
            // Once the lower device objects have 
            // succeeded the addition of the paging 
            // file, it is illegal to fail the 
            // request. It is also the time to 
            // clear the Filter DO's 
            //DO_POWER_PAGABLE flag.
 
            DeviceObject->Flags &= ~DO_POWER_PAGABLE; 
            } 
        } else { 
 // F 
        if (setPageable == TRUE) { 
            DeviceObject->Flags &= ~DO_POWER_PAGABLE; 
            setPageable = FALSE; 
        } 
    } 
 // G 
        KeSetEvent(&commonExtension->PagingCountEvent, 
                                    IO_NO_INCREMENT, FALSE); 
                                    break;
    } *Do not use or delete the last paragraph mark. It maintains the template setup and formats.