Solicitação de E/S de exemplo – Os detalhes
A figura que ilustra a abertura de um objeto de arquivo mostra um IRP com dois locais de pilha de E/S, mas um IRP pode ter qualquer número de locais de pilha de E/S, dependendo de quantos drivers em camadas manipularão uma determinada solicitação.
A figura a seguir ilustra mais detalhadamente como os drivers na figura Abrindo um objeto de arquivo usam rotinas de suporte de E/S (rotinas de IoXxx ) para processar o IRP para uma solicitação de leitura ou gravação.
O gerenciador de E/S chama o FSD (driver do sistema de arquivos) com o IRP alocado para a solicitação de leitura/gravação do subsistema. O FSD acessa seu local de pilha de E/S no IRP para determinar qual operação deve ser realizada.
O FSD pode dividir a solicitação original em solicitações menores (possivelmente para mais de um driver de dispositivo) chamando uma rotina de suporte de E/S (IoAllocateIrp) uma ou mais vezes para alocar IRPs adicionais. Os IRPs adicionais são retornados ao FSD com locais de pilha de E/S com preenchimento zero para drivers de nível inferior. A seu critério, o FSD pode reutilizar o IRP original, em vez de alocar IRPs adicionais, conforme mostrado na figura anterior, configurando o local da pilha de E/S do driver mais baixo no IRP original e passando-o para drivers inferiores.
Para cada IRP alocado por driver, o FSD na figura anterior chama uma rotina de suporte de E/S para registrar uma rotina de conclusão fornecida pelo FSD; na rotina de conclusão, o FSD pode determinar se os drivers inferiores atenderam à solicitação e podem liberar cada IRP alocado por driver quando drivers inferiores a tiverem concluído. O gerente de E/S chamará a rotina de conclusão fornecida pelo FSD se cada IRP alocado por driver foi concluído com êxito, concluído com um erro status ou cancelado. Um driver de nível superior é responsável por liberar todos os IRPs alocados e configurados em seu próprio nome para drivers de nível inferior. O gerente de E/S libera os IRPs alocados depois que todos os drivers os tiverem concluído.
Em seguida, o FSD chama uma rotina de suporte de E/S (IoGetNextIrpStackLocation) para acessar o local da pilha de E/S do driver de nível inferior para configurar a solicitação para o driver mais baixo. (Na figura anterior, o próximo driver inferior é o driver de nível mais baixo.) Em seguida, o FSD chama uma rotina de suporte de E/S (IoCallDriver) para passar esse IRP para o driver inferior seguinte.
Quando ele é chamado com o IRP, o driver de nível mais baixo verifica seu local de pilha de E/S para determinar qual operação (indicada pelo código de função IRP_MJ_XXX ) deve ser executada no dispositivo de destino. O dispositivo de destino é representado pelo objeto de dispositivo em seu local de pilha de E/S designado e é passado com o IRP para o driver. O driver de nível mais baixo pode assumir que o gerenciador de E/S roteou o IRP para um ponto de entrada que o driver definiu para a operação IRP_MJ_XXX (aqui IRP_MJ_READ ou IRP_MJ_WRITE) e que o driver de nível superior verificou a validade de outros parâmetros para a solicitação.
Se não houvesse nenhum driver de nível superior, o driver de nível mais baixo marcar se os parâmetros de entrada para uma operação IRP_MJ_XXX são válidos. Se estiverem, o driver geralmente chama rotinas de suporte de E/S para informar ao gerente de E/S que uma operação de dispositivo está pendente no IRP e para enfileirar o IRP ou passá-lo para outra rotina fornecida pelo driver que acessa o dispositivo de destino (aqui, um dispositivo físico ou lógico: o disco ou uma partição no disco).
O gerenciador de E/S determina se o driver já está ocupado processando outro IRP para o dispositivo de destino, enfileira o IRP se ele estiver e retorna. Caso contrário, o gerenciador de E/S roteia o IRP para uma rotina fornecida pelo driver que inicia a operação de E/S em seu dispositivo. (Nesta fase, os drivers na figura anterior e o controle de retorno do gerenciador de E/S.)
Quando o dispositivo interrompe, a ISR (rotina de serviço de interrupção) do driver faz apenas o máximo de trabalho necessário para impedir que o dispositivo interrompa e salve o contexto necessário sobre a operação. Em seguida, o ISR chama uma rotina de suporte de E/S (IoRequestDpc) com o IRP para enfileirar uma rotina DPC (Chamada de Procedimento Adiado) fornecida pelo driver para concluir a operação solicitada com uma prioridade de hardware menor do que o ISR.
Quando o DPC do driver obtém o controle, ele usa o contexto (passado na chamada do ISR para IoRequestDpc) para concluir a operação de E/S. O DPC chama uma rotina de suporte para remover a fila do próximo IRP (se houver) e passar esse IRP para a rotina fornecida pelo driver que inicia operações de E/S no dispositivo (consulte a Etapa 5). Em seguida, o DPC define status sobre a operação concluída no bloco de status de E/S do IRP e a retorna ao gerenciador de E/S com IoCompleteRequest.
O gerenciador de E/S zere o local de pilha de E/S do driver de nível mais baixo no IRP e chama a rotina de conclusão registrada do sistema de arquivos (consulte a Etapa 3) com o IRP alocado por FSD. Essa rotina de conclusão verifica o bloco de status de E/S para determinar se deseja repetir a solicitação ou atualizar qualquer estado interno mantido sobre a solicitação original e liberar seu IRP alocado por driver. O sistema de arquivos pode coletar status informações para todos os IRPs alocados por driver que ele envia para drivers de nível inferior para que ele possa definir status de E/S e concluir o IRP original. Quando o sistema de arquivos tiver concluído o IRP original, o gerenciador de E/S retornará e o valor NTSTATUS para o solicitante original (a função nativa do subsistema) da operação de E/S.
Assim como o driver do sistema de arquivos mostrado na figura Processando IRPs em drivers em camadas , qualquer novo driver adicionado a uma cadeia de drivers existentes pode fazer o seguinte:
Defina sua própria rotina de conclusão em um IRP. A rotina IoCompletion verifica o bloco de status de E/S para determinar se os drivers inferiores concluíram o IRP com êxito, cancelaram o IRP e/ou o concluíram com um erro. A rotina de conclusão também pode atualizar qualquer estado específico do IRP que o driver possa ter salvo, liberar todos os recursos específicos da operação que o driver possa ter alocado e assim por diante, antes de concluir o IRP. Além disso, a rotina de conclusão pode adiar a conclusão do IRP (informando ao gerente de E/S que mais processamento é necessário no IRP) e pode enviar outra solicitação para o próximo driver de nível inferior antes de permitir que o IRP seja concluído.
Configure o local da pilha de E/S do próximo driver de nível inferior nos IRPs que ele aloca e envia solicitações para o próximo driver de nível inferior.
Passe todas as solicitações de entrada para drivers inferiores configurando o local da pilha de E/S do próximo driver inferior em cada IRP e chamando IoCallDriver. (Observe que, para IRPs com código de função principal IRP_MJ_POWER, os drivers devem usar PoCallDriver.)
Cada objeto de dispositivo criado pelo driver representa um dispositivo físico, lógico ou virtual para o qual um determinado driver executa solicitações de E/S. Para obter informações detalhadas sobre como criar e configurar um objeto de dispositivo, consulte Device Objects and Device Stacks.
Como mostra também a figura Processando IRPs em drivers em camadas , a maioria dos drivers processa cada IRP em estágios por meio de um conjunto fornecido pelo driver de rotinas padrão definidas pelo sistema, mas os drivers em diferentes níveis em uma cadeia necessariamente têm rotinas padrão diferentes. Por exemplo, apenas drivers de nível mais baixo lidam com interrupções de um dispositivo físico, portanto, apenas um driver de nível mais baixo teria um ISR e um DPC que conclui operações de E/S controladas por interrupção. Por outro lado, como esse driver sabe que a E/S está concluída quando recebe uma interrupção de seu dispositivo, ele não precisa de uma rotina de conclusão. Somente um driver de nível superior teria uma ou mais rotinas de conclusão, como o FSD, nesta figura.