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


Расположения стека ввода-вывода

Диспетчер ввода-вывода предоставляет каждому драйверу в цепочке многоуровневых драйверов расположение стека ввода-вывода для каждого настраиваемого IRP. Каждое расположение стека ввода-вывода состоит из структуры IO_STACK_LOCATION .

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

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

На рисунке "Обработка IRPs в многоуровневых драйверах" показаны два расположения стека ввода-вывода в исходном IRP, так как он показывает два драйвера: драйвер файловой системы и драйвер устройства массового хранения. Выделенные драйвером IRPs в обработчиках, показанных на рисунке Обработка IRP в многослойных драйверах, не содержат местоположения стека для FSD (драйвера файловой системы), который их создал. Любой драйвер более высокого уровня, который выделяет irPs для драйверов нижнего уровня, также определяет, сколько расположений стека ввода-вывода должны иметь новые irPs, в соответствии со значением StackSize объекта устройства следующего нижнего уровня драйвера.

На следующем рисунке показано содержимое IRP более подробно.

схема, иллюстрирующая содержимое расположения стека ввода-вывода в irp.

Как показано на рисунке, каждое расположение стека ввода-вывода для конкретного драйвера в IRP содержит следующие общие сведения:

  • Код основной функции (IRP_MJ_XXXX), указывающий базовую операцию, которой должен выполнять драйвер.

  • Для некоторых основных кодов функций, обрабатываемых FSD, более высокоуровневыми драйверами SCSI и всеми драйверами PnP, минорный код функции (IRP_MN_XXX) указывает, какой подслучай базовой операции следует выполнить.

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

  • Указатель на созданный драйвером объект устройства, представляющий целевое (физическое, логическое или виртуальное) устройство для запрошенной операции.

  • Указатель на объект файла, представляющий открытый файл, устройство, каталог или том

    Драйвер файловой системы обращается к объекту файла через его расположение в стеке IRP. Другие драйверы обычно игнорируют объект файла.

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

  • IRP_MJ_CREATE — откройте целевой объект устройства, указывающий, что он присутствует и доступен для операций ввода-вывода.

  • IRP_MJ_READ — передача данных с устройства

  • IRP_MJ_WRITE — передача данных на устройство

  • IRP_MJ_DEVICE_CONTROL — настройка (или сброс) устройства в соответствии с системно определенным, специфичным для типа устройства кодом управления ввода-вывода (IOCTL)

  • IRP_MJ_CLOSE — закройте объект целевого устройства

  • IRP_MJ_PNP — выполните операцию Plug and Play на устройстве. Запрос IRP_MJ_PNP отправляется менеджером PnP через диспетчер ввода-вывода.

  • IRP_MJ_POWER — выполнение операции питания на устройстве. Запрос IRP_MJ_POWER отправляется диспетчером питания через диспетчер ввода-вывода.

Дополнительные сведения о основных кодах функций IRP, необходимых для обработки драйверов, см. в разделе "Основные коды функций IRP".

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

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

Обратите внимание, что эта поддержка добавления новых драйверов в существующую цепочку подразумевает определенные ограничения на доступ любого конкретного драйвера к расположениям стека ввода-вывода в irPs:

  • Драйвер более высокого уровня в цепочке многоуровневых драйверов может безопасно получить доступ только к собственным и следующим расположениям стека ввода-вывода драйвера следующего уровня в любом IRP. Такой драйвер должен настроить расположение стека ввода-вывода для драйвера следующего нижнего уровня в IRPs. Однако при проектировании такого драйвера более высокого уровня нельзя предсказать, когда (или ли) новый драйвер будет добавлен в существующую цепочку чуть ниже драйвера.

    Поэтому следует предположить, что любой последующий добавленный драйвер будет обрабатывать те же основные коды функций IRP (IRP_MJ_XXXX), что и перемещенный драйвер следующего уровня.

  • Самый низкий уровень драйвера в цепочке многоуровневых драйверов может безопасно получить доступ только к собственному расположению стека ввода-вывода в любом IRP. При разработке такого драйвера невозможно предсказать, когда (или ли) новый драйвер будет добавлен в существующую цепочку над драйвером устройства.

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