Использование буферизованного ввода-вывода

Драйвер, который обслуживает интерактивное или медленное устройство или который обычно передает относительно небольшие объемы данных за раз, должен использовать метод передачи буферизованного ввода-вывода . Использование буферизованного ввода-вывода для небольших интерактивных передач улучшает общее использование физической памяти, так как диспетчеру памяти не нужно блокировать полную физическую страницу для каждой передачи, как и для драйверов, запрашивающих прямой ввод-вывод. Как правило, видео, клавиатура, мышь, последовательные и параллельные драйверы запрашивают буферизованные операции ввода-вывода.

Диспетчер операций ввода-вывода определяет, что операция ввода-вывода использует буферизацию операций ввода-вывода следующим образом:

На следующем рисунке показано, как диспетчер операций ввода-вывода настраивает IRP_MJ_READ запрос на операцию передачи, которая использует буферные операции ввода-вывода.

схема, иллюстрирующая буферный ввод-вывод для пользовательских буферов.

На рисунке показан обзор того, как драйверы могут использовать указатель SystemBuffer в IRP для передачи данных для запроса на чтение, если драйвер обнажает флаги объекта устройства с помощью DO_BUFFERED_IO:

  1. Некоторый диапазон виртуальных адресов пользовательского пространства представляет буфер текущего потока, и содержимое этого буфера может храниться в диапазоне физических адресов на основе страниц (на предыдущем рисунке — темная заливка).

  2. Диспетчер ввода-вывода обслуживает запрос на чтение текущего потока, для которого поток передает диапазон виртуальных адресов пользовательского пространства, представляющих буфер.

  3. Диспетчер ввода-вывода проверяет предоставленный пользователем буфер на предмет доступности и вызывает ExAllocatePoolWithTag , чтобы создать буфер системного пространства (SystemBuffer) размера предоставленного пользователем буфера.

  4. Диспетчер ввода-вывода предоставляет доступ к вновь выделенному SystemBuffer в IRP, который он отправляет драйверу.

    Если на рисунке показан запрос на запись, диспетчер операций ввода-вывода копирует данные из пользовательского буфера в системный буфер, прежде чем отправлять IRP драйверу.

  5. Для запроса на чтение, показанного на предыдущем рисунке, драйвер считывает данные с устройства в буфер системного пространства. Память для этого буфера не загружена, и драйвер может безопасно получить доступ к буферу, не блокируя его. После выполнения запроса на чтение драйвер вызывает IoCompleteRequest с IRP.

  6. Когда исходный поток снова активен, диспетчер ввода-вывода копирует данные для чтения из системного буфера в буфер пользователя. Он также вызывает ExFreePool для освобождения системного буфера.

После того как диспетчер ввода-вывода создаст буфер системного пространства для драйвера, запрашивающий поток пользовательского режима можно переключить, а его физическую память может повторно использовать другой поток, возможно, поток, принадлежащий другому процессу. Однако диапазон виртуальных адресов системного пространства, указанный в IRP, остается действительным до тех пор, пока драйвер не вызовет IoCompleteRequest с IRP.

Драйверы, которые передают большие объемы данных за раз, в частности драйверы, которые выполняют многостранийную передачу, не должны пытаться использовать буферизированные операции ввода-вывода. По мере запуска системы непагрегированные пулы могут стать фрагментированы, поэтому диспетчер операций ввода-вывода не сможет выделить большие смежные буферы системного пространства для отправки в irP для такого драйвера.

Как правило, драйвер использует буферизированные операции ввода-вывода для некоторых типов IRP, таких как IRP_MJ_DEVICE_CONTROL запросы, даже если он также использует прямой ввод-вывод. Драйверы, использующие прямой ввод-вывод, обычно делают это только для запросов IRP_MJ_READ и IRP_MJ_WRITE и, возможно, определяемых драйвером IRP_MJ_INTERNAL_DEVICE_CONTROL запросов, требующих передачи больших данных.

Каждый запрос IRP_MJ_DEVICE_CONTROL и IRP_MJ_INTERNAL_DEVICE_CONTROL включает код элемента управления вводом-выводом. Если код элемента управления вводом-выводом указывает, что IRP должен поддерживаться с помощью буферизованного ввода-вывода, диспетчер ввода-вывода использует один системный буфер для представления входных и выходных буферов пользовательского приложения. Драйвер, поддерживающий такой код управления вводом-выводом, должен считывать входные данные (если таковые есть) из буфера, а затем предоставлять выходные данные (если таковые есть) путем перезаписи входных данных. Дополнительные сведения см. в разделе Определение кодов управления вводом-выводом.