Usando E/S em buffer

Um driver que atende a um dispositivo interativo ou lento, ou que geralmente transfere quantidades relativamente pequenas de dados por vez, deve usar o método de transferência de E/S em buffer . O uso de E/S em buffer para transferências pequenas e interativas melhora o uso geral de memória física, pois o gerenciador de memória não precisa bloquear uma página física completa para cada transferência, como faz para drivers que solicitam E/S direta. Em geral, os drivers de vídeo, teclado, mouse, serial e paralelo solicitam E/S em buffer.

O gerenciador de E/S determina que uma operação de E/S está usando E/S em buffer da seguinte maneira:

A figura a seguir ilustra como o gerenciador de E/S configura uma solicitação de IRP_MJ_READ para uma operação de transferência que usa E/S em buffer.

diagrama ilustrando uma e/s em buffer para buffers de usuário.

A figura mostra uma visão geral de como os drivers podem usar o ponteiro SystemBuffer no IRP para transferir dados para uma solicitação de leitura, quando um driver tem Sinalizadores do objeto de dispositivo com DO_BUFFERED_IO:

  1. Alguns intervalos de endereços virtuais de espaço do usuário representam o buffer do thread atual e o conteúdo desse buffer pode ser armazenado em algum lugar dentro de um intervalo de endereços físicos baseados em página (sombreamento escuro na figura anterior).

  2. O gerenciador de E/S atende à solicitação de leitura do thread atual, para a qual o thread passa um intervalo de endereços virtuais de espaço do usuário que representam um buffer.

  3. O gerenciador de E/S verifica a acessibilidade do buffer fornecido pelo usuário e chama ExAllocatePoolWithTag para criar um buffer de espaço do sistema nãopagado (SystemBuffer) do tamanho do buffer fornecido pelo usuário.

  4. O gerenciador de E/S fornece acesso ao SystemBuffer recém-alocado no IRP que ele envia para o driver.

    Se a figura mostrasse uma solicitação de gravação, o gerenciador de E/S copiaria dados do buffer do usuário para o buffer do sistema antes de enviar o IRP para o driver.

  5. Para a solicitação de leitura mostrada na figura anterior, o driver lê dados do dispositivo no buffer de espaço do sistema. A memória desse buffer não épagada e o driver pode acessar com segurança o buffer sem primeiro bloqueá-lo. Quando a solicitação de leitura for atendida, o driver chamará IoCompleteRequest com o IRP.

  6. Quando o thread original está novamente ativo, o gerenciador de E/S copia os dados de leitura do buffer do sistema para o buffer do usuário. Ele também chama ExFreePool para liberar o buffer do sistema.

Depois que o gerenciador de E/S tiver criado um buffer de espaço do sistema para o driver, o thread de modo de usuário solicitante poderá ser trocado e sua memória física poderá ser reutilizado por outro thread, possivelmente por um thread que pertença a outro processo. No entanto, o intervalo de endereços virtuais de espaço do sistema fornecido no IRP permanece válido até que o driver chame IoCompleteRequest com o IRP.

Os drivers que transferem grandes quantidades de dados por vez, em particular os drivers que fazem transferências de várias páginas, não devem tentar usar E/S em buffer. À medida que o sistema é executado, o pool nãopagado pode se fragmentar para que o gerenciador de E/S não possa alocar buffers de espaço de sistema grandes e contíguos para enviar IRPs para esse driver.

Normalmente, um driver usa E/S em buffer para alguns tipos de IRPs, como solicitações de IRP_MJ_DEVICE_CONTROL , mesmo que ele também use E/S direta. Os drivers que usam E/S direta normalmente só fazem isso para solicitações de IRP_MJ_READ e IRP_MJ_WRITE e possivelmente solicitações de IRP_MJ_INTERNAL_DEVICE_CONTROL definidas pelo driver que exigem grandes transferências de dados.

Cada solicitação de IRP_MJ_DEVICE_CONTROL e IRP_MJ_INTERNAL_DEVICE_CONTROL inclui um código de controle de E/S. Se o código de controle de E/S indicar que o IRP deve ter suporte usando E/S em buffer, o gerenciador de E/S usará um único buffer do sistema para representar os buffers de entrada e saída do aplicativo de usuário. Um driver que dá suporte a esse código de controle de E/S deve ler dados de entrada (se houver) do buffer e, em seguida, fornecer dados de saída (se houver) substituindo os dados de entrada. Para obter mais informações, consulte Definindo códigos de controle de E/S.