Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Na entrada, uma rotina IoCompletion recebe um Context pointer. Quando uma rotina de despacho chama IoSetCompletionRoutine, ela pode fornecer um ponteiro Context. Esse ponteiro pode fazer referência a qualquer informação de contexto determinada pelo driver que a rotina do IoCompletion exija para processar um IRP. A área de contexto não pode ser paginável porque a rotina IoCompletion pode ser chamada em IRQL = DISPATCH_LEVEL.
Considere as seguintes diretrizes de implementação para as rotinas do IoComplete:
Uma rotina IoCompletion pode verificar o bloco de status de E/S do IRP para determinar o resultado da operação de E/S.
Se a rotina de despacho alocou o IRP de entrada usando IoAllocateIrp ou IoBuildAsynchronousFsdRequest, a rotina IoCompletion deve chamar IoFreeIrp para liberar esse IRP, de preferência antes de concluir o IRP original.
A rotina IoCompletion deve liberar quaisquer recursos de cada IRP que a rotina de despacho alocou para o IRP alocado pelo driver, de preferência antes de liberar o IRP correspondente.
Por exemplo, se a rotina de despacho aloca um MDL com IoAllocateMdl e chama IoBuildPartialMdl para um IRP de transferência parcial que ele aloca, a rotina IoCompletion deve liberar o MDL com IoFreeMdl. Se ele aloca recursos para manter o estado sobre o IRP original, ele deve liberar esses recursos, de preferência antes de chamar IoCompleteRequest com o IRP original e definitivamente antes de retornar o controle.
Em geral, antes de liberar ou completar um IRP, a rotina IoCompletion deve liberar quaisquer recursos por IRP alocados pela rotina de expedição. Caso contrário, o driver deve manter o estado sobre os recursos a serem liberados antes que sua rotina IoCompletion retorne o controle da conclusão da solicitação original.
Se a rotina IoCompletion não puder concluir o IRP original com STATUS_SUCCESS, ela deverá definir o bloco de status de E/S no IRP original para o valor retornado no IRP alocado pelo driver que fez com que a rotina IoCompletion falhasse na solicitação original.
Se a rotina IoCompletion concluir a solicitação original com STATUS_PENDING, ela deverá chamar IoMarkIrpPending com o IRP original antes de chamar IoCompleteRequest.
Se a rotina IoCompletion falhar no IRP original com um erro STATUS_XXX, ele poderá registrar um erro. No entanto, é responsabilidade do driver de dispositivo subjacente registrar quaisquer erros de E/S de dispositivo que ocorram, portanto, as rotinas do IoCompletion geralmente não registram erros.
Quando a rotina IoCompletion processa e libera o IRP alocado pelo driver, ele deve retornar o controle com STATUS_MORE_PROCESSING_REQUIRED.
O retorno de STATUS_MORE_PROCESSING_REQUIRED da rotina IoCompletion impede o processamento de conclusão pelo gerenciador de E/S para um IRP alocado e liberado pelo driver. Uma segunda chamada para IoCompleteRequest faz com que o gerente de E/S volte a chamar as rotinas de conclusão do IRP, começando com a rotina de conclusão imediatamente acima da rotina que retornou STATUS_MORE_PROCESSING_REQUIRED.
Se a rotina IoCompletion reutilizar um IRP de entrada para enviar uma ou mais solicitações a drivers inferiores, ou se a rotina repetir operações com falha, ela deverá atualizar qualquer contexto que a rotina IoCompletion mantenha sobre cada reutilização ou nova tentativa do IRP. Em seguida, ele pode configurar o local da pilha de E/S do próximo driver inferior novamente, chamar IoSetCompletionRoutine com seu próprio ponto de entrada e chamar IoCallDriver para o IRP.
A rotina IoCompletion não deve chamar IoMarkIrpPending a cada reutilização ou nova tentativa do IRP.
A rotina de despacho já marcava o IRP original como pendente. Até que todos os drivers da cadeia completem o IRP original com IoCompleteRequest, ele permanece pendente.
Antes de tentar novamente uma solicitação, a rotina IoCompletion deve redefinir o bloco de status de E/S com STATUS_SUCCESS para Status e zero para Informações, possivelmente depois de salvar as informações de erro retornadas.
Para cada nova tentativa, a rotina IoCompletion geralmente diminui uma contagem de tentativas configurada pela rotina de expedição. Normalmente, a rotina IoCompletion deve chamar IoCompleteRequest para indicar falha no IRP quando um número limitado de tentativas tiver falhado.
A rotina IoCompletion deve retornar STATUS_MORE_PROCESSING_REQUIRED depois de chamar IoSetCompletionRoutine e IoCallDriver com um IRP que está reutilizando ou tentando novamente.
O retorno de STATUS_MORE_PROCESSING_REQUIRED da rotina IoCompletion evita o processamento de conclusão de um IRP reutilizado ou repetido pelo gerente de E/S.
Se a rotina IoCompletion não puder concluir o IRP original com STATUS_SUCCESS, ela deverá deixar o bloco de status de E/S conforme retornado por drivers inferiores para a operação de reutilização ou repetição que faz com que a rotina IoCompletion falhe no IRP.
Se a rotina IoCompletion concluir a solicitação original com STATUS_PENDING, ela deverá chamar IoMarkIrpPending com o IRP original antes de chamar IoCompleteRequest.
Se a rotina IoCompletion falhar no IRP original com um erro STATUS_XXX, ele poderá registrar um erro. No entanto, é responsabilidade do driver de dispositivo subjacente registrar quaisquer erros de E/S de dispositivo que ocorram, portanto, as rotinas do IoCompletion geralmente não registram erros.
Qualquer driver que defina uma rotina IoCompletion num IRP e, em seguida, passe o IRP para um driver de nível inferior deve verificar o sinalizador IRP-PendingReturned> na rotina IoCompletion. Se o sinalizador estiver definido, a rotina IoCompletion deverá chamar IoMarkIrpPending com o IRP. No entanto, um driver que transmite o IRP e depois aguarda por um evento não deve marcar o IRP como pendente. Em vez disso, sua rotina IoCompletion deve sinalizar o evento e retornar STATUS_MORE_PROCESSING_REQUIRED.
A rotina IoCompletion deve liberar todos os recursos alocados pela rotina de despacho para processar o IRP original, de preferência antes que a rotina IoCompletion chame IoCompleteRequest com o IRP original e definitivamente antes que a rotina IoCompletion retorne o controle da conclusão do IRP original.
Se algum driver de nível superior definir sua rotina IoCompletion no IRP original, a rotina IoCompletion desse driver não será chamada até que as rotinas IoCompletion de todos os drivers de nível inferior tenham sido chamadas.
Realizar um aumento de prioridade nas chamadas para IoCompleteRequest
Se um driver de dispositivo de nível mais baixo puder concluir um IRP em sua rotina de despacho, ele chamará IoCompleteRequest com um PriorityBoost de IO_NO_INCREMENT. Nenhum aumento de prioridade de tempo de execução é necessário porque o driver pode presumir que o solicitante original não esperou que sua operação de E/S fosse concluída.
Caso contrário, o driver de nível mais baixo fornece um valor definido pelo sistema e específico do tipo de dispositivo que aumenta a prioridade de tempo de execução do solicitante para compensar o tempo que o solicitante esperou pela sua solicitação de E/S do dispositivo. Consulte Wdm.h ou Ntddk.h para obter os valores de aumento.
Os drivers de nível superior aplicam o mesmo PriorityBoost que os seus respetivos drivers de dispositivos subjacentes quando chamam IoCompleteRequest.
Efeito de chamar IoCompleteRequest
Quando um driver chama IoCompleteRequest, o gestor de E/S preenche a localização da pilha de E/S desse driver com zeros antes de chamar o próximo driver de nível superior, se houver, que configurou uma rotina IoCompletion para ser executada para o IRP.
A rotina IoCompletion de um driver de nível superior pode verificar apenas o bloco de status de E/S do IRP para determinar como todos os drivers inferiores lidaram com a solicitação.
O chamador de IoCompleteRequest não deve tentar aceder ao IRP recém-concluído. Tal tentativa é um erro de programação que causa uma falha do sistema.