Partager via


Implémentation d’une routine IoCompletion

Lors de l’entrée, une routine IoCompletion reçoit un pointeur de contexte . Lorsqu’une routine de répartition appelle IoSetCompletionRoutine, elle peut fournir un pointeur de contexte . Ce pointeur peut référencer les informations de contexte déterminées par le pilote dont la routine IoCompletion a besoin pour traiter un IRP. La zone de contexte ne peut pas être paginable, car la routine IoCompletion peut être appelée à IRQL = DISPATCH_LEVEL.

Tenez compte des instructions d’implémentation suivantes pour les routines IoCompletion :

  • Une routine IoCompletion peut vérifier le bloc d’état d’E/S d’IRP pour déterminer le résultat de l’opération d’E/S.

  • Si la routine de répartition a alloué l’IRP d’entrée à l’aide d’IoAllocateIrp ou d’IoBuildAsynchronousFsdRequest, la routine IoCompletion doit appeler IoFreeIrp pour libérer cet IRP, de préférence avant de terminer l’IRP d’origine.

    • La routine IoCompletion doit libérer toutes les ressources par IRP que la routine de répartition allouée pour le protocole IRP alloué au pilote, de préférence avant de libérer l’IRP correspondante.

      Par exemple, si la routine de répartition alloue un MDL avec IoAllocateMdl et appelle IoBuildPartialMdl pour un IRP de transfert partiel qu’elle alloue, la routine IoCompletion doit libérer le MDL avec IoFreeMdl. S’il alloue des ressources pour conserver l’état de l’IRP d’origine, il doit libérer ces ressources, de préférence avant d’appeler IoCompleteRequest avec l’IRP d’origine et certainement avant de retourner le contrôle.

      En général, avant de libérer ou de terminer un IRP, la routine IoCompletion doit libérer toutes les ressources par IRP allouées par la routine de distribution. Sinon, le pilote doit maintenir l'état des ressources à libérer avant que sa routine IoCompletion retourne le contrôle après avoir terminé la requête d'origine.

    • Si la routine IoCompletion ne peut pas terminer l’IRP d’origine avec STATUS_SUCCESS, elle doit définir le bloc d’état d’E/S dans l’IRP d’origine sur la valeur retournée dans l’IRP allouée par le pilote qui a provoqué l’échec de la routine IoCompletion pour l’échec de la requête d’origine.

    • Si la routine IoCompletion termine la requête d’origine avec STATUS_PENDING, elle doit appeler IoMarkIrpPending avec l’IRP d’origine avant d’appeler IoCompleteRequest.

    • Si la routine IoCompletion doit faire échouer l'IRP d'origine avec une erreur STATUS_XXX, elle peut enregistrer une erreur. Toutefois, il incombe au pilote de périphérique sous-jacent de consigner les erreurs d’E/S d’appareil qui se produisent, de sorte que les routines IoCompletion ne journalisent généralement pas les erreurs.

    • Lorsque la routine IoCompletion traite et libère l’IRP allouée par le pilote, elle doit retourner le contrôle avec STATUS_MORE_PROCESSING_REQUIRED.

      Retourner STATUS_MORE_PROCESSING_REQUIRED de la routine IoCompletion empêche le traitement d’achèvement d’E/S par le gestionnaire d’E/S pour un IRP que le pilote a alloué et libéré. Un deuxième appel à IoCompleteRequest amène le gestionnaire d’E/S à reprendre l’appel des routines d’achèvement de l’IRP, en commençant par la routine d’achèvement immédiatement au-dessus de la routine qui a retourné STATUS_MORE_PROCESSING_REQUIRED.

  • Si la routine IoCompletion réutilise un IRP entrant pour envoyer une ou plusieurs requêtes à des pilotes inférieurs, ou si la routine retente des opérations ayant échoué, elle doit mettre à jour le contexte dans lequel la routine IoCompletion gère chaque réutilisation ou nouvelle tentative de l’IRP. Ensuite, il peut réinitialiser l’emplacement de la pile d’E/S du pilote immédiatement inférieur, appeler IoSetCompletionRoutine avec son propre point d’entrée et appeler IoCallDriver pour l’IRP.

    • La routine IoCompletion ne doit pas appeler IoMarkIrpPending à chaque réutilisation ou nouvelle tentative de l’IRP.

      La routine de répartition a déjà marqué l’IRP d’origine comme étant en attente. Jusqu’à ce que tous les pilotes de la chaîne terminent l’IRP d’origine avec IoCompleteRequest, il reste en attente.

    • Avant de réessayer une requête, la routine IoCompletion doit réinitialiser le bloc d’état d’E/S avec STATUS_SUCCESS pour l’état et zéro pour les informations, éventuellement après avoir enregistré les informations d’erreur retournées.

      Pour chaque nouvelle tentative, la routine IoCompletion décrémente généralement un nombre de nouvelles tentatives configuré par la routine de distribution. En règle générale, la routine IoCompletion doit appeler IoCompleteRequest pour échouer l’IRP quand un certain nombre limité de nouvelles tentatives ont échoué.

    • La routine IoCompletion doit retourner STATUS_MORE_PROCESSING_REQUIRED après avoir appelé IoSetCompletionRoutine et IoCallDriver avec un IRP qu’elle réutilie ou réessaye.

      Retourner STATUS_MORE_PROCESSING_REQUIRED de la routine IoCompletion empêche le traitement d'achèvement par le gestionnaire d'entrées/sorties d'un IRP réutilisé ou de tentative.

    • Si la routine IoCompletion ne peut pas terminer l’IRP d’origine avec STATUS_SUCCESS, elle doit conserver le bloc d’état d’E/S tel que retourné par les pilotes inférieurs pour l’opération de réutilisation ou de nouvelle tentative, ce qui entraîne l’échec de l’IRP par la routine IoCompletion.

    • Si la routine IoCompletion termine la requête d’origine avec STATUS_PENDING, elle doit appeler IoMarkIrpPending avec l’IRP d’origine avant d’appeler IoCompleteRequest.

    • Si la routine IoCompletion doit échouer l’IRP d’origine avec une erreur STATUS_XXX, elle peut alors consigner une erreur. Toutefois, il incombe au pilote de périphérique sous-jacent de consigner les erreurs d’E/S d’appareil qui se produisent, de sorte que les routines IoCompletion ne journalisent généralement pas les erreurs.

  • Tous les pilotes qui définissent une routine IoCompletion dans un IRP, puis passent l’IRP à un pilote inférieur doivent vérifier l’indicateur IRP-PendingReturned> dans la routine IoCompletion. Si l’indicateur est défini, la routine IoCompletion doit appeler IoMarkIrpPending avec l’IRP. Toutefois, un pilote qui passe l’IRP, puis attend un événement ne doit pas marquer l’IRP en attente. Au lieu de cela, sa routine IoCompletion doit signaler l’événement et retourner STATUS_MORE_PROCESSING_REQUIRED.

  • La routine IoCompletion doit libérer toutes les ressources que la routine de distribution a allouées pour le traitement de l’IRP d’origine, de préférence avant que la routine IoCompletion appelle IoCompleteRequest avec l’IRP d’origine et certainement avant que la routine IoCompletion retourne le contrôle après avoir complété l’IRP d’origine.

Si un pilote de niveau supérieur définit sa routine IoCompletion dans l’IRP d’origine, la routine IoCompletion du pilote n’est pas appelée tant que les routines IoCompletion de tous les pilotes de niveau inférieur n’ont pas été appelées.

Fourniture d’un boost de priorité dans les appels à IoCompleteRequest

Si un pilote de périphérique de niveau le plus bas peut effectuer un IRP dans sa routine de répartition, il appelle IoCompleteRequest avec un PriorityBoost de IO_NO_INCREMENT. Aucune augmentation de priorité au moment de l’exécution n’est nécessaire, car le pilote peut supposer que le demandeur d’origine n’a pas attendu que son opération d’E/S soit terminée.

Dans le cas contraire, le pilote de niveau le plus bas fournit une valeur spécifique au type d’appareil et définie par le système qui améliore la priorité d’exécution du demandeur pour compenser le temps d’attente du demandeur sur sa demande d’E/S d’appareil. Consultez Wdm.h ou Ntddk.h pour connaître les valeurs de boost.

Les pilotes de niveau supérieur appliquent le même PriorityBoost que leurs pilotes de périphériques sous-jacents respectifs lorsqu’ils appellent IoCompleteRequest.

Effet de l’appel d’IoCompleteRequest

Lorsqu’un pilote appelle IoCompleteRequest, le gestionnaire d’E/S remplit l’emplacement de la pile des E/S du pilote avec des zéros avant d’appeler le pilote de niveau supérieur suivant, le cas échéant, qui configure une routine IoCompletion à appeler pour l’IRP.

La routine IoCompletion d’un pilote de niveau supérieur ne peut vérifier que le bloc d’état d’E/S d’IRP pour déterminer comment tous les pilotes inférieurs ont géré la requête.

L'appelant de IoCompleteRequest ne doit pas tenter d'accéder à l'IRP tout juste complété. Une telle tentative est une erreur de programmation qui provoque un blocage du système.