Garantindo o progresso das operações de E/S
Alguns drivers, como drivers de armazenamento para o dispositivo de paginação do sistema, devem executar pelo menos algumas de suas operações de E/S com suporte sem falha, para evitar a perda de dados críticos do sistema. Uma possível causa de uma falha de driver é uma situação de baixa memória. Se a estrutura ou o driver não puder alocar memória suficiente para lidar com uma solicitação de E/S, um ou outro poderá ter que falhar na solicitação de E/S concluindo-a com um valor de status de erro.
Em versões do KMDF anteriores à versão 1.9, a estrutura sempre falhará em uma solicitação de E/S se não puder alocar um objeto de solicitação de estrutura para um IRP (pacote de solicitação de E/S) que o gerente de E/S enviou ao driver. Para fornecer aos drivers a capacidade de processar solicitações de E/S durante situações de baixa memória, as versões 1.9 e posteriores da estrutura fornecem uma funcionalidade de progresso de encaminhamento garantida para filas de E/S.
Essa funcionalidade permite que a estrutura e o driver pré-aloquem memória para conjuntos de objetos de solicitação e buffers de contexto de driver relacionados à solicitação, respectivamente. A estrutura e o driver usam essa memória pré-alocada somente quando a quantidade de memória do sistema é baixa.
Recursos do progresso futuro garantido
Usando o progresso de encaminhamento garantido da estrutura para filas de E/S, um driver pode:
Peça à estrutura para pré-alocar um conjunto de objetos de solicitação a serem usados com uma fila de E/S específica durante situações de baixa memória.
Forneça uma função de retorno de chamada que pré-aloca recursos específicos de solicitação que o driver pode usar quando recebe objetos de solicitação pré-alocados da estrutura durante situações de baixa memória.
Forneça outra função de retorno de chamada que aloca recursos específicos do driver para uma solicitação de E/S quando uma situação de baixa memória não for detectada. Se a alocação dessa função de retorno de chamada falhar devido a uma situação de memória baixa, ela poderá indicar se a estrutura deve usar um de seus objetos de solicitação pré-alocados.
Especifique quais solicitações de E/S exigem o uso de objetos de solicitação pré-alocados. As opções incluem o uso de objetos pré-alocados para todos os IRPs, usá-los somente se uma operação de E/S de paginação estiver em andamento ou fazer com que uma função de retorno de chamada de driver adicional examine cada IRP para determinar se deseja usar um objeto pré-alocado.
Se o driver implementar o progresso de encaminhamento garantido para uma ou mais de suas filas de E/S, o driver poderá processar solicitações de E/S com êxito durante situações de baixa memória. Você pode implementar o progresso de encaminhamento garantido para a fila de E/S padrão de um dispositivo e para qualquer fila de E/S configurada pelo driver chamando WdfDeviceConfigureRequestDispatching.
A funcionalidade de progresso futuro garantida da estrutura funcionará para o driver somente se o driver e os destinos de E/S do driver implementarem o progresso de encaminhamento garantido. Em outras palavras, se um driver implementar o progresso futuro garantido para um dispositivo, todos os drivers de nível inferior na pilha de driver do dispositivo também deverão implementar o progresso futuro garantido.
Habilitando o progresso de encaminhamento garantido para uma fila de E/S
Para habilitar o progresso de encaminhamento garantido para uma fila de E/S, o driver inicializa uma estrutura WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY e chama o método WdfIoQueueAssignForwardProgressPolicy . Se o driver chamar WdfDeviceConfigureRequestDispatching para configurar uma fila de E/S, ele deverá fazer isso antes de chamar WdfIoQueueAssignForwardProgressPolicy.
Quando o driver chama WdfIoQueueAssignForwardProgressPolicy, ele pode especificar as três funções de retorno de chamada de evento a seguir, todas opcionais:
EvtIoAllocateResourcesForReservedRequest
A função de retorno de chamada EvtIoAllocateResourcesForReservedRequest de um driver aloca e armazena recursos específicos de solicitação para objetos de solicitação que a estrutura está reservando para situações de baixa memória.
A estrutura chama essa função de retorno de chamada sempre que cria um objeto de solicitação reservada. O driver deve alocar recursos específicos de solicitação para uma solicitação de E/S, normalmente usando o espaço de contexto do objeto de solicitação reservada.
EvtIoAllocateRequestResources
A função de retorno de chamada EvtIoAllocateRequestResources de um driver aloca recursos específicos da solicitação para uso imediato. Ele é chamado imediatamente após a estrutura ter recebido um IRP e criado um objeto de solicitação para o IRP.
Se a tentativa da função de retorno de chamada de alocar recursos falhar, a função de retorno de chamada retornará um valor de status de erro. Em seguida, a estrutura exclui o objeto de solicitação recém-criado e usa um de seus objetos de solicitação reservados. Por sua vez, o manipulador de solicitação do driver usa recursos específicos de solicitação que sua função de retorno de chamada EvtIoAllocateRequestResources alocou anteriormente.
EvtIoWdmIrpForForwardProgress
A função de retorno de chamada EvtIoWdmIrpForForwardProgress de um driver examina um IRP e informa à estrutura se deseja usar um objeto de solicitação reservado para o IRP ou para falhar na solicitação de E/S concluindo-a com um valor de status de erro.
A estrutura chamará essa função de retorno de chamada somente se a estrutura não puder criar um novo objeto de solicitação e você tiver indicado (definindo um sinalizador na estrutura de WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY do driver) que você deseja que o driver examine IRPs durante situações de baixa memória. Em outras palavras, seu driver pode avaliar cada IRP e decidir se ele é aquele que deve ser processado mesmo durante situações de memória baixa.
Quando o driver chama WdfIoQueueAssignForwardProgressPolicy, ele também especifica o número de objetos de solicitação reservados que você deseja que a estrutura pré-aloque para situações de baixa memória. Você pode escolher o número de objetos de solicitação apropriados para seu dispositivo e driver. Para evitar a redução do desempenho, o driver normalmente deve especificar um número que aproxima o número de solicitações de E/S que o driver e o dispositivo podem manipular em paralelo.
No entanto, se a chamada do driver para a função de retorno de chamada WdfIoQueueAssignForwardProgressPolicy e sua função de retorno de chamada EvtIoAllocateResourcesForReservedRequest pré-alocar muitos objetos de solicitação reservados ou muita memória de recurso específica da solicitação, seu driver poderá realmente contribuir para as situações de baixa memória que você está tentando lidar. Você deve testar o desempenho do driver e do dispositivo e incluir simulações de memória baixa para determinar os melhores números a serem escolhidos.
Antes que WdfIoQueueAssignForwardProgressPolicy retorne, a estrutura cria e reserva o número de objetos de solicitação especificados pelo driver. Sempre que reserva um objeto de solicitação, a estrutura chama imediatamente a função de retorno de chamada EvtIoAllocateResourcesForReservedRequest do driver para que o driver possa alocar e salvar recursos específicos da solicitação, caso a estrutura realmente use os objetos de solicitação reservados.
Quando um dos manipuladores de solicitação do driver recebe uma solicitação de E/S da fila de E/S, ele pode chamar o método WdfRequestIsReserved para determinar se o objeto de solicitação é aquele que a estrutura pré-alocada para situações de memória baixa. Se esse método retornar TRUE, o driver deverá usar recursos reservados para sua função de retorno de chamada EvtIoAllocateResourcesForReservedRequest .
Se a estrutura usar um de seus objetos de solicitação reservada, ela retornará o objeto ao conjunto de objetos reservados após o driver concluir a solicitação. A estrutura salva o objeto de solicitação e qualquer espaço de contexto que o driver criou chamando WdfDeviceInitSetRequestAttributes ou WdfObjectAllocateContext, para reutilização se ocorrer outra situação de baixa memória.
Como a estrutura e o driver dão suporte ao progresso futuro garantido
A seguir estão as etapas que o driver e a estrutura executam para dar suporte ao progresso de encaminhamento garantido para uma fila de E/S:
O driver chama WdfIoQueueAssignForwardProgressPolicy.
Em resposta, a estrutura aloca e armazena o número de objetos de solicitação especificados pelo driver. Se o driver anteriormente chamado WdfDeviceInitSetRequestAttributes, cada alocação incluirá espaço de contexto especificado por WdfDeviceInitSetRequestAttributes .
Além disso, se o driver tiver fornecido uma função de retorno de chamada EvtIoAllocateResourcesForReservedRequest , a estrutura chamará a função de retorno de chamada sempre que alocar e armazenar um objeto de solicitação.
A estrutura recebe um IRP (pacote de solicitação de E/S) que o gerente de E/S está enviando para o driver.
A estrutura tenta alocar um objeto de solicitação para o IRP. Se a fila de E/S criada pelo driver para o tipo de solicitação der suporte ao progresso futuro garantido, a próxima etapa dependerá se a alocação for bem-sucedida ou falhar:
A alocação de objeto de solicitação é bem-sucedida.
Se o driver forneceu uma função de retorno de chamada EvtIoAllocateRequestResources , a estrutura a chamará. Se a função de retorno de chamada retornar STATUS_SUCCESS, a estrutura adicionará a solicitação à fila de E/S. Se a função de retorno de chamada retornar um valor de status de erro, a estrutura excluirá o objeto de solicitação que acabou de criar e usará um de seus objetos de solicitação pré-alocados. Quando o manipulador de solicitação do driver recebe o objeto de solicitação, ele determina se o objeto de solicitação foi pré-alocado e, portanto, se ele deve usar os recursos pré-alocados do driver.
Se o driver não forneceu uma função de retorno de chamada EvtIoAllocateRequestResources , a estrutura adicionará a solicitação à fila de E/S, como se o driver não tivesse habilitado o progresso de encaminhamento garantido.
Falha na alocação do objeto de solicitação.
O que a estrutura faz em seguida depende do valor que o driver forneceu para o membro ForwardProgressReservedPolicy da estrutura WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY . Esse membro informa a estrutura quando usar uma solicitação reservada: sempre, somente se a solicitação de E/S for uma operação de E/S de paginação ou somente se a função de retorno de chamada EvtIoWdmIrpForForwardProgress indicar que uma solicitação reservada deve ser usada.
Em todos os casos, os manipuladores de solicitação do driver podem chamar WdfRequestIsReserved para determinar se a estrutura usou um objeto de solicitação reservada. Nesse caso, o driver deve usar os recursos de solicitação alocados pela função de retorno de chamada EvtIoAllocateResourcesForReservedRequest .
Cenário de progresso futuro garantido
Você está escrevendo um driver para um dispositivo de armazenamento que pode conter o arquivo de paginação do sistema. É importante que as operações de leitura e gravação no arquivo de paginação tenham êxito.
Você decide criar filas de E/S separadas para operações de leitura e gravação e habilitar o progresso de encaminhamento garantido para ambas as filas de E/S. Você decide criar uma terceira fila de E/S para todos os outros tipos de solicitação sem habilitar o progresso de encaminhamento garantido.
A pilha de driver e o dispositivo são capazes de processar quatro operações de gravação em paralelo, portanto, você define o membro TotalForwardProgressRequests da estrutura WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY como 4 antes de chamar WdfIoQueueAssignForwardProgressPolicy.
Você decide que garantir o progresso do encaminhamento só será importante se o dispositivo do driver for o dispositivo de paginação, portanto, o driver definirá o membro ForwardProgressReservedPolicy da estrutura WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY para WdfIoForwardProgressReservedPolicyPagingIO.
Como o driver requer um objeto de memória de estrutura para cada solicitação de leitura e cada solicitação de gravação, você decide que seu driver deve pré-alocar alguns objetos de memória a serem usados para suas chamadas para WdfIoTargetFormatRequestForRead e WdfIoTargetFormatRequestForWrite em situações de memória baixa.
Portanto, o driver fornece uma função de retorno de chamada EvtIoAllocateResourcesForReservedRequest para a fila de leitura e outra para a fila de gravação. Sempre que a estrutura chama uma dessas funções de retorno de chamada, a função de retorno de chamada chama WdfMemoryCreate e salva o identificador de objeto retornado para situações de memória baixa. Como a função de retorno de chamada recebe um identificador para um objeto de solicitação pré-alocado, ela pode ser pai do objeto de memória para o objeto de solicitação. (Um driver para um dispositivo DMA também pode pré-alocar objetos DMA da estrutura.)
Os manipuladores de solicitação para as filas de leitura e gravação devem determinar se cada objeto de solicitação recebida é aquele que a estrutura reservada para situações de memória baixa. Um manipulador de solicitação pode chamar WdfRequestIsReserved ou pode comparar o identificador de objeto de solicitação com aquele que a função de retorno de chamada EvtIoAllocateResourcesForReservedRequest recebeu anteriormente.
O driver também fornece uma função de retorno de chamada EvtIoAllocateRequestResources para a fila de leitura e outra para a fila de gravação. A estrutura chama uma dessas funções de retorno de chamada quando recebe uma solicitação de leitura ou gravação do gerenciador de E/S e cria com êxito um objeto de solicitação. Cada uma dessas funções de retorno de chamada chama WdfMemoryCreate para alocar um objeto de memória para uma solicitação. Se a alocação falhar, a função de retorno de chamada retornará um valor de status de erro para notificar a estrutura de que uma situação de memória baixa acabou de ocorrer. A estrutura, detectando o valor retornado do erro, exclui o objeto de solicitação que acabou de criar e usa um de seus objetos pré-alocados.
Esse driver não fornece uma função de retorno de chamada EvtIoWdmIrpForForwardProgress , pois não precisa examinar IRPs de leitura ou gravação individuais antes que a estrutura os adicione a uma fila de E/S.
Lembre-se de que quando um driver implementa o progresso de encaminhamento garantido para um dispositivo, todos os drivers de nível inferior na pilha de driver do dispositivo também devem implementar o progresso de encaminhamento garantido.