Criando IRPs para drivers de Lower-Level

Para alocar um IRP para uma solicitação assíncrona, que será processada em um contexto de thread arbitrário por drivers inferiores, uma rotina DispatchReadWrite pode chamar uma das seguintes rotinas de suporte:

  • IoAllocateIrp, que aloca um IRP e vários locais de pilha de E/S inicializados sem inicialização

    A rotina de expedição deve configurar o local da pilha de E/S do driver mais baixo para o IRP recém-alocado, geralmente copiando informações (possivelmente modificadas) de seu próprio local de pilha no IRP original. Se um driver de nível superior alocar um local de pilha de E/S próprio para um IRP recém-alocado, a rotina de expedição poderá configurar informações de contexto por solicitação para a rotina IoCompletion a ser usada.

  • IoBuildAsynchronousFsdRequest, que configura o local de pilha de E/S do próximo driver inferior para o chamador, de acordo com parâmetros especificados pelo chamador

    Drivers de nível superior podem chamar essa rotina para alocar IRPs para solicitações de IRP_MJ_READ, IRP_MJ_WRITE, IRP_MJ_FLUSH_BUFFERS e IRP_MJ_SHUTDOWN .

    Quando uma rotina IoCompletion é chamada para esse IRP, ela pode marcar bloco de E/S status e, se necessário (ou possível), configurar o local da pilha de E/S do driver mais baixo no IRP novamente e repetir a solicitação ou reutilizá-la. No entanto, a rotina IoCompletion não tem armazenamento de contexto local para si mesma no IRP, portanto, o driver deve manter o contexto sobre a solicitação original em outro lugar na memória residente.

  • IoMakeAssociatedIrp, que aloca um IRP e vários locais de pilha de E/S inicializados sem inicialização e associa o IRP a um IRP master.

    Os drivers intermediários não podem chamar IoMakeAssociatedIrp para criar IRPs para drivers inferiores.

    Qualquer driver de nível mais alto que chama IoMakeAssociatedIrp para criar IRPs para drivers inferiores pode retornar o controle para o gerente de E/S depois de enviar seus IRPs associados e chamar IoMarkIrpPending para o IRP original master. Um driver de nível mais alto pode contar com o gerente de E/S para concluir a master IRP quando todos os IRPs associados tiverem sido concluídos por drivers inferiores.

    Os drivers raramente definem uma rotina IoCompletion para um IRP associado. Se um driver de nível mais alto chamar IoSetCompletionRoutine para um IRP associado criado, o gerente de E/S não concluirá o master IRP se o driver retornar STATUS_MORE_PROCESSING_REQUIRED de sua rotina de IoCompletion. Nessas circunstâncias, a rotina IoCompletion do driver deve concluir explicitamente a master IRP com IoCompleteRequest.

Se um driver alocar um local de pilha de E/S próprio em um novo IRP, a rotina de expedição deverá chamar IoSetNextIrpStackLocation antes de chamar IoGetCurrentIrpStackLocation para configurar o contexto em seu próprio local de pilha de E/S para a rotina IoCompletion . Para obter mais informações, consulte Processando IRPs em um driver de Intermediate-Level.

A rotina de expedição deve chamar IoMarkIrpPending com o IRP original, mas não com nenhum IRPs alocado pelo driver porque a rotina IoCompletion os liberará.

Se a rotina de expedição estiver alocando IRPs para transferências parciais e o driver de dispositivo subjacente puder controlar um dispositivo de mídia removível, a rotina de expedição deverá configurar o contexto de thread em seus IRPs recém-alocados do valor em Tail.Overlay.Thread no IRP original.

Um driver subjacente para um dispositivo de mídia removível pode chamar IoSetHardErrorOrVerifyDevice, que faz referência ao ponteiro em Irp-Tail.Overlay.Thread>, para um IRP alocado pelo driver. Se o driver chamar essa rotina de suporte, o driver do sistema de arquivos poderá enviar uma caixa de diálogo para o thread de usuário apropriado que solicita que o usuário cancele, tente novamente ou falhe uma operação que o driver não pôde atender. Consulte Suporte à mídia removível para obter mais informações.

As rotinas de expedição devem retornar STATUS_PENDING depois de enviar todos os IRPs alocados pelo driver para drivers inferiores.

A rotina de IoCompletion de um driver deve liberar todos os IRPs alocados por driver com IoFreeIrp antes de chamar IoCompleteRequest para o IRP original. Quando ele conclui o IRP original, a rotina IoCompletion deve liberar todos os IRPs alocados por driver antes de retornar o controle.

Cada driver de nível superior configura todos os IRPs alocados (e reutilizados) alocados por driver para drivers inferiores de forma que seja imaterial para o driver de dispositivo subjacente, seja uma determinada solicitação proveniente de um driver intermediário ou proveniente de qualquer outra fonte, como um sistema de arquivos ou um aplicativo no modo de usuário.

Os drivers de nível mais alto podem chamar IoMakeAssociatedIrp para alocar IRPs e configurá-los para uma cadeia de drivers inferiores. O gerenciador de E/S conclui automaticamente o IRP original quando todos os SEUS IRPs associados tiverem sido concluídos, desde que o driver não chame IoSetCompletionRoutine com o IRP original ou com qualquer um dos IRPs associados alocados. No entanto, os drivers de nível mais alto não devem alocar IRPs associados para qualquer IRP que solicite uma operação de E/S em buffer.

Um driver de nível intermediário não pode alocar IRPs para drivers de nível inferior chamando IoMakeAssociatedIrp. Qualquer IRP que um driver intermediário recebe pode já ser um IRP associado e um driver não pode associar outro IRP a esse IRP.

Em vez disso, se um driver intermediário criar IRPs para drivers inferiores, ele deverá chamar IoAllocateIrp, IoBuildDeviceIoControlRequest, IoBuildSynchronousFsdRequest ou IoBuildAsynchronousFsdRequest. No entanto, IoBuildSynchronousFsdRequest só pode ser chamado nas seguintes circunstâncias:

  • Por um thread criado pelo driver para criar IRPs para solicitações de leitura ou gravação, porque esse thread pode aguardar em um contexto de thread nonarbitrary (seu próprio) em um objeto dispatcher, como um Evento inicializado pelo driver passado para IoBuildSynchronousFsdRequest

  • No contexto de thread do sistema durante a inicialização ou durante o descarregamento

  • Para criar IRPs para operações inerentemente síncronas, como criar, liberar, desligar, fechar e solicitações de controle de dispositivo

No entanto, é mais provável que um driver chame IoBuildDeviceIoControlRequest para alocar IRPs de controle de dispositivo do que IoBuildSynchronousFsdRequest.