Share via


Gestion des demandes de pagination PnP

Un pilote de filtre de stockage doit gérer les demandes de pagination PnP (IRP_MJ_PNP avec IRP_MN_DEVICE_USAGE_NOTIFICATION et Parameters.UsageNotification.Type défini sur DeviceUsageTypePaging) si le pilote de fonction qu’il filtre gère cette IRP.

Les éléments suivants doivent être ajoutés à l’objet DeviceExtension du filtre DO :

ULONG PagingCount ;

KEVENT PagingCountEvent ;

Lors de la réception de demandes de pagination PnP, un pilote de filtre de stockage doit mettre à jour pagingCount et le paramètre du bit DO_POWER_PAGABLE dans le filtre DO. Le minutage de la mise à jour du bit DO_POWER_PAGABLE dépend de la définition ou de l’effacement du bit. Si l’IRP indique que le bit doit être défini, le pilote de filtre doit le définir avant de transférer l’IRP vers le bas de la pile des pilotes. Mais si l’IRP indique que le bit doit être effacé, le pilote de filtre ne doit pas effacer le bit immédiatement. Il doit d’abord avancer l’IRP, puis attendre que les conducteurs inférieurs retournent leur status et effacer le bit uniquement si les pilotes inférieurs retournent STATUS_SUCCESS.

L’exemple suivant trace le flux des actions effectuées par le pilote de filtre de stockage. Reportez-vous à l’exemple de pseudocode immédiatement sous le plan pour voir une représentation de ce plan dans le code C :

R. Vérifiez que l’appareil a été démarré. Si ce n’est pas le cas, échouez avec STATUS_DEVICE_NOT_READY.

B. Synchroniser sur pagingCountEvent (KeWaitForSingleObject( PagingCountEvent, ...)).

C. Si vous supprimez le dernier périphérique de pagination ( ( ! Parameters.UsageNotification.InPath && (PagingCount == 1) ) puis

  1. Définissez une valeur booléenne locale sur TRUE, et

  2. Si le bit DO_POWER_INRUSH n’est pas défini dans le filtre DO, définissez le bit DO_POWER_PAGABLE .

    L’exemple suivant explique pourquoi le bit DO_POWER_PAGABLE doit être défini sur le chemin vers le bas et non sur le chemin vers le haut :

    Les exigences en matière d’alimentation indiquent que si un objet de périphérique inférieur définit le bit DO_POWER_PAGABLE , tous les pilotes de niveau supérieur doivent faire de même. Si le pilote de filtre ne parvient pas à définir le bit DO_POWER_PAGABLE avant d’envoyer l’IRP de la demande de pagination dans la pile, il peut violer cette condition comme suit :

    Supposons que le pilote de filtre ne définit pas le bit DO_POWER_PAGABLE dans son filtre DO avant de transférer l’IRP de la demande de pagination aux pilotes situés en dessous dans la pile des pilotes. Supposons ensuite qu’un pilote inférieur définit le DO_POWER_PAGABLE bit dans son propre do. Enfin, supposons qu’avant l’achèvement de l’IRP par le pilote de filtre, une IRP d’alimentation se produit. À ce stade, le bit DO_POWER_PAGABLE serait effacé dans le do de filtre, mais serait défini dans le do du pilote de niveau inférieur, provoquant un plantage du système.

    Il est prudent de définir le DO_POWER_PAGABLE bit avant de transférer une demande de pagination vers le bas de la pile, car il n’y a plus de fichier de pagination actif sur le périphérique du pilote de filtre, et par conséquent, plus d’E/S de pagination ne se produit dessus. Si la demande de suppression de ce fichier de pagination réussit, le pilote de filtre est terminé. Si la requête échoue, le pilote de filtre peut restaurer l’état d’origine de ses indicateurs en effaçant simplement le bit DO_POWER_PAGABLE avant de terminer l’IRP. Étant donné que les demandes de fichier de pagination sont sérialisées, il n’y a aucun risque qu’un autre thread ait modifié ce bit depuis que le pilote de filtre l’a modifié pour la dernière fois.

D. Transférer de façon synchrone l’IRP vers les pilotes inférieurs.

E. Si l’IRP se termine correctement, alors

  1. Appelez IoAdjustPagingPathCount(&PagingCount, Parameters.UsageNotification.InPath) pour incrémenter ou décrémenter le PagingCount. IoAdjustPagingPathCount effectue une opération InterlockedIncrement ou InterlockedDecrement du PagingCount en fonction de la valeur dans Parameters.UsageNotification.InPath. La valeur TRUE indique qu’un fichier de pagination est ajouté. Par conséquent, incrémentez pagingCount ; La valeur FALSE indique qu’un fichier de pagination est en cours de suppression. Par conséquent, décrémentez pagingCount.

  2. Si Parameters.UsageNotification.InPath a la valeur TRUE, un fichier de pagination est ajouté, donc effacez le bit DO_POWER_PAGABLE .

F. Sinon, si l’IRP échoue, alors

  1. Vérifiez la valeur booléenne locale pour voir si DO_POWER_PAGABLE a été défini dans le filtre DO sur le chemin vers le bas.

  2. Si DO_POWER_PAGABLE a été défini sur le chemin vers le bas, effacez-le.

G. Fin de la synchronisation (KeSetEvent(PagingCountEvent, ...)).

Exemple de pseudocode

Les sections marquées par des lettres (//A, //B, etc.) dans l’exemple de code suivant correspondent aux lettres du plan ci-dessus.

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.