Garantie de la progression des opérations d’E/S
Certains pilotes, tels que les pilotes de stockage pour le périphérique de pagination du système, doivent effectuer au moins certaines de leurs opérations d’E/S prises en charge sans échec, afin d’éviter de perdre des données système critiques. Une cause potentielle de défaillance d’un pilote est une situation de mémoire insuffisante. Si l’infrastructure ou le pilote ne parvient pas à allouer suffisamment de mémoire pour gérer une demande d’E/S, l’un ou l’autre peut avoir à faire échouer la demande d’E/S en la terminant avec une valeur d’état d’erreur.
Dans les versions de KMDF antérieures à la version 1.9, le framework échoue toujours à une demande d’E/S s’il ne peut pas allouer un objet de demande d’infrastructure pour un paquet de demandes d’E/S (IRP) que le gestionnaire d’E/S a envoyé au pilote. Pour permettre aux pilotes de traiter les demandes d’E/S en cas de mémoire insuffisante, les versions 1.9 et ultérieures de l’infrastructure offrent une fonctionnalité de progression avant garantie pour les files d’attente d’E/S.
Cette fonctionnalité permet au framework et au pilote de préallouer de la mémoire pour des ensembles d’objets de requête et des mémoires tampons de contexte de pilote liées à la requête, respectivement. L’infrastructure et le pilote utilisent cette mémoire pré-allouée uniquement lorsque la quantité de mémoire système est faible.
Fonctionnalités de la progression vers l’avant garantie
En utilisant la progression avancée garantie de l’infrastructure pour les files d’attente d’E/S, un pilote peut :
Demandez à l’infrastructure de préallouer un ensemble d’objets de requête à utiliser avec une file d’attente d’E/S spécifique dans des situations de mémoire insuffisante.
Fournissez une fonction de rappel qui pré-alloue des ressources spécifiques à la demande que le pilote peut utiliser lorsqu’il reçoit des objets de requête pré-alloués de l’infrastructure dans des situations de mémoire insuffisante.
Fournissez une autre fonction de rappel qui alloue des ressources spécifiques au pilote pour une demande d’E/S lorsqu’une situation de mémoire insuffisante n’a pas été détectée. Si l’allocation de cette fonction de rappel échoue en raison d’une situation de mémoire insuffisante, elle peut indiquer si l’infrastructure doit utiliser l’un de ses objets de requête pré-alloués.
Spécifiez les demandes d’E/S qui nécessitent l’utilisation d’objets de requête pré-alloués. Les options incluent l’utilisation d’objets pré-alloués pour tous les IRP, leur utilisation uniquement si une opération d’E/S de pagination est en cours, ou le fait qu’une fonction de rappel de pilote supplémentaire examine chaque IRP pour déterminer s’il faut utiliser un objet pré-alloué.
Si votre pilote implémente une progression vers l’avant garantie pour une ou plusieurs de ses files d’attente d’E/S, il sera mieux en mesure de traiter correctement les demandes d’E/ S dans les situations de mémoire insuffisante. Vous pouvez implémenter la progression de progression garantie pour la file d’attente d’E/S par défaut d’un appareil et pour toute file d’attente d’E/S configurée par votre pilote en appelant WdfDeviceConfigureRequestDispatching.
La fonctionnalité de progression vers l’avant garantie de l’infrastructure fonctionne pour votre pilote uniquement si votre pilote et les cibles d’E/S du pilote implémentent la progression avancée garantie. En d’autres termes, si un pilote implémente une progression vers l’avant garantie pour un appareil, tous les pilotes de niveau inférieur de la pile de pilotes de l’appareil doivent également implémenter la progression vers l’avant garantie.
Activation de la progression vers l’avant garantie pour une file d’attente d’E/S
Pour activer la progression vers l’avant garantie pour une file d’attente d’E/S, votre pilote initialise une structure WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY , puis appelle la méthode WdfIoQueueAssignForwardProgressPolicy . Si le pilote appelle WdfDeviceConfigureRequestDispatching pour configurer une file d’attente d’E/S, il doit le faire avant d’appeler WdfIoQueueAssignForwardProgressPolicy.
Lorsque le pilote appelle WdfIoQueueAssignForwardProgressPolicy, il peut spécifier les trois fonctions de rappel d’événement suivantes, qui sont toutes facultatives :
EvtIoAllocateResourcesForReservedRequest
La fonction de rappel EvtIoAllocateResourcesForReservedRequest d’un pilote alloue et stocke des ressources spécifiques à la requête pour les objets de requête que l’infrastructure réserve aux situations de mémoire insuffisante.
Le framework appelle cette fonction de rappel chaque fois qu’il crée un objet de requête réservé. Le pilote doit allouer des ressources spécifiques à la requête pour une demande d’E/S, généralement à l’aide de l’espace contextuel de l’objet de requête réservé.
EvtIoAllocateRequestResources
La fonction de rappel EvtIoAllocateRequestResources d’un pilote alloue des ressources spécifiques à la requête pour une utilisation immédiate. Il est appelé immédiatement après que l’infrastructure a reçu un IRP et créé un objet de demande pour l’IRP.
Si la tentative d’allocation de ressources de la fonction de rappel échoue, la fonction de rappel retourne une valeur d’état d’erreur. L’infrastructure supprime ensuite l’objet de requête nouvellement créé et utilise l’un de ses objets de requête réservés. À son tour, le gestionnaire de requêtes du pilote utilise des ressources spécifiques à la requête que sa fonction de rappel EvtIoAllocateRequestResources a précédemment allouées.
EvtIoWdmIrpForForwardProgress
La fonction de rappel EvtIoWdmIrpForForwardProgress d’un pilote examine un IRP et indique à l’infrastructure s’il faut utiliser un objet de requête réservé pour l’IRP ou échouer la demande d’E/S en la terminant avec une valeur d’état d’erreur.
L’infrastructure appelle cette fonction de rappel uniquement si l’infrastructure ne parvient pas à créer un nouvel objet de requête et que vous avez indiqué (en définissant un indicateur dans la structure de WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY du pilote) que vous souhaitez que le pilote examine les IRP dans les situations de mémoire insuffisante. En d’autres termes, votre pilote peut évaluer chaque IRP et décider s’il doit être traité même dans les situations de mémoire insuffisante.
Lorsque votre pilote appelle WdfIoQueueAssignForwardProgressPolicy, il spécifie également le nombre d’objets de requête réservés que vous souhaitez que l’infrastructure préalloue pour les situations de mémoire insuffisante. Vous pouvez choisir le nombre d’objets de requête appropriés pour votre périphérique et votre pilote. Pour éviter une baisse des performances, votre pilote doit généralement spécifier un nombre qui se rapproche du nombre de demandes d’E/S que le pilote et le périphérique peuvent gérer en parallèle.
Toutefois, si l’appel de votre pilote à WdfIoQueueAssignForwardProgressPolicy et sa fonction de rappel EvtIoAllocateResourcesForReservedRequest pré-allouent trop d’objets de requête réservés ou trop de mémoire de ressource spécifique à la requête, votre pilote peut en fait contribuer aux situations de mémoire insuffisante que vous essayez de gérer. Vous devez tester les performances de votre pilote et de votre appareil, et inclure des simulations à mémoire faible pour déterminer les meilleurs nombres à choisir.
Avant que WdfIoQueueAssignForwardProgressPolicy ne retourne, l’infrastructure crée et réserve le nombre d’objets de requête que le pilote a spécifiés. Chaque fois qu’il réserve un objet de requête, l’infrastructure appelle immédiatement la fonction de rappel EvtIoAllocateResourcesForReservedRequest du pilote afin que le pilote puisse allouer et enregistrer des ressources spécifiques à la demande, au cas où l’infrastructure utilise réellement les objets de requête réservés.
Quand l’un des gestionnaires de requêtes du pilote reçoit une demande d’E/S de la file d’attente d’E/S, il peut appeler la méthode WdfRequestIsReserved pour déterminer si l’objet de requête est un objet que le framework a préalloué pour les situations de mémoire insuffisante. Si cette méthode retourne TRUE, le pilote doit utiliser les ressources réservées par sa fonction de rappel EvtIoAllocateResourcesForReservedRequest .
Si l’infrastructure utilise l’un de ses objets de requête réservés, elle retourne l’objet à son ensemble d’objets réservés une fois que le pilote a terminé la requête. L’infrastructure enregistre l’objet de requête et tout espace de contexte créé par le pilote en appelant WdfDeviceInitSetRequestAttributes ou WdfObjectAllocateContext, à réutiliser si une autre situation de mémoire insuffisante se produit.
Comment le framework et le pilote prennent en charge la progression garantie
Voici les étapes que le pilote et l’infrastructure effectuent pour prendre en charge la progression garantie d’une file d’attente d’E/S :
Le pilote appelle WdfIoQueueAssignForwardProgressPolicy.
En réponse, l’infrastructure alloue et stocke le nombre d’objets de requête spécifiés par le pilote. Si le pilote a précédemment appelé WdfDeviceInitSetRequestAttributes, chaque allocation inclut l’espace de contexte spécifié par WdfDeviceInitSetRequestAttributes .
En outre, si le pilote a fourni une fonction de rappel EvtIoAllocateResourcesForReservedRequest , l’infrastructure appelle la fonction de rappel chaque fois qu’elle alloue et stocke un objet de requête.
L’infrastructure reçoit un paquet de demandes d’E/S (IRP) que le gestionnaire d’E/S envoie au pilote.
L’infrastructure tente d’allouer un objet de requête pour l’IRP. Si la file d’attente d’E/S créée par le pilote pour le type de requête prend en charge la progression garantie, l’étape suivante dépend de la réussite ou de l’échec de l’allocation :
L’allocation d’objets de requête réussit.
Si le pilote a fourni une fonction de rappel EvtIoAllocateRequestResources , l’infrastructure l’appelle. Si la fonction de rappel retourne STATUS_SUCCESS, l’infrastructure ajoute la requête à la file d’attente d’E/S. Si la fonction de rappel retourne une valeur d’état d’erreur, l’infrastructure supprime l’objet de requête qu’elle vient de créer et utilise l’un de ses objets de requête pré-alloués. Lorsque le gestionnaire de requêtes du pilote reçoit l’objet de requête, il détermine si l’objet de requête a été pré-alloué et, par conséquent, s’il doit utiliser les ressources pré-allouées du pilote.
Si le pilote n’a pas fourni de fonction de rappel EvtIoAllocateRequestResources , l’infrastructure ajoute la requête à la file d’attente d’E/S, comme si le pilote n’avait pas activé la progression de transfert garantie.
L’allocation d’objets de requête échoue.
L’action suivante de l’infrastructure dépend de la valeur fournie par le pilote pour le membre ForwardProgressReservedPolicy de la structure WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY . Ce membre informe l’infrastructure quand utiliser une demande réservée : toujours, uniquement si la demande d’E/S est une opération d’E/S de pagination, ou uniquement si la fonction de rappel EvtIoWdmIrpForForwardProgress indique qu’une demande réservée doit être utilisée.
Dans tous les cas, les gestionnaires de requêtes du pilote peuvent appeler WdfRequestIsReserved pour déterminer si l’infrastructure a utilisé un objet de requête réservé. Si c’est le cas, le pilote doit utiliser les ressources de requête que sa fonction de rappel EvtIoAllocateResourcesForReservedRequest a allouées .
Scénario de progression vers l’avant garantie
Vous écrivez un pilote pour un périphérique de stockage qui peut contenir le fichier de pagination du système. Il est important que les opérations de lecture et d’écriture dans le fichier de pagination réussissent.
Vous décidez de créer des files d’attente d’E/S distinctes pour les opérations de lecture et d’écriture, et d’activer la progression garantie pour ces deux files d’attente d’E/S. Vous décidez de créer une troisième file d’attente d’E/S pour tous les autres types de requêtes sans activer la progression garantie.
Votre pile de pilotes et votre périphérique étant capables de traiter quatre opérations d’écriture en parallèle, vous définissez le membre TotalForwardProgressRequests de la structure WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY sur 4 avant d’appeler WdfIoQueueAssignForwardProgressPolicy.
Vous décidez que la garantie de la progression n’est importante que si l’appareil de votre pilote est le périphérique de pagination. Par conséquent, votre pilote définit le membre ForwardProgressReservedPolicy de la structure WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY sur WdfIoForwardProgressReservedPolicyPagingIO.
Étant donné que votre pilote nécessite un objet de mémoire d’infrastructure pour chaque demande de lecture et chaque demande d’écriture, vous décidez que votre pilote doit préallouer certains objets mémoire à utiliser pour ses appels à WdfIoTargetFormatRequestForRead et WdfIoTargetFormatRequestForWrite dans les situations de mémoire insuffisante.
Par conséquent, le pilote fournit une fonction de rappel EvtIoAllocateResourcesForReservedRequest pour la file d’attente de lecture et une autre pour la file d’attente d’écriture. Chaque fois que l’infrastructure appelle l’une de ces fonctions de rappel, la fonction de rappel appelle WdfMemoryCreate et enregistre le handle d’objet retourné pour les situations de mémoire insuffisante. Étant donné que la fonction de rappel reçoit un handle pour un objet de requête pré-alloué, elle peut parenter l’objet mémoire avec l’objet de requête. (Un pilote pour un appareil DMA peut également pré-allouer des objets DMA de framework.)
Les gestionnaires de requêtes pour les files d’attente de lecture et d’écriture doivent déterminer si chaque objet de requête reçu est un objet réservé par l’infrastructure aux situations de mémoire insuffisante. Un gestionnaire de demandes peut appeler WdfRequestIsReserved, ou il peut comparer le handle d’objet de requête avec ceux que la fonction de rappel EvtIoAllocateResourcesForReservedRequest a reçues précédemment.
Le pilote fournit également une fonction de rappel EvtIoAllocateRequestResources pour la file d’attente de lecture et une autre pour la file d’attente d’écriture. L’infrastructure appelle l’une de ces fonctions de rappel lorsqu’elle reçoit une demande de lecture ou d’écriture du gestionnaire d’E/S et crée correctement un objet de requête. Chacune de ces fonctions de rappel appelle WdfMemoryCreate pour allouer un objet mémoire à une requête. Si l’allocation échoue, la fonction de rappel retourne une valeur d’état d’erreur pour informer l’infrastructure qu’une situation de mémoire insuffisante vient de se produire. L’infrastructure, en détectant la valeur de retour d’erreur, supprime l’objet de demande qu’elle vient de créer et utilise l’un de ses objets pré-alloués.
Ce pilote ne fournit pas de fonction de rappel EvtIoWdmIrpForForForwardProgress , car il n’a pas besoin d’examiner des irps individuels en lecture ou en écriture avant que le framework les ajoute à une file d’attente d’E/S.
N’oubliez pas que lorsqu’un pilote implémente une progression vers l’avant garantie pour un appareil, tous les pilotes de niveau inférieur dans la pile de pilotes de l’appareil doivent également implémenter la progression vers l’avant garantie.