Поделиться через


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

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

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

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

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

На рисунке показан обзор того, как драйверы могут использовать указатель SystemBuffer в IRP для передачи данных при запросе на чтение, когда к флагам объекта устройства применено битовое OR с 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 должен поддерживаться с помощью буферизованного ввода-вывода, диспетчер ввода-вывода использует один системный буфер для представления входных и выходных буферов пользовательского приложения. Драйвер, поддерживающий такой код элемента управления ввода-вывода, должен считывать входные данные (если таковые) из буфера, а затем предоставлять выходные данные (если таковые есть), перезаписав входные данные. Дополнительные сведения см. в разделе Определение кодов управления ввода-вывода.