Расположения стека ввода-вывода
Диспетчер ввода-вывода предоставляет каждому драйверу в цепочке многоуровневых драйверов расположение стека ввода-вывода для каждой настроенной им службы IRP. Каждое расположение стека ввода-вывода состоит из структуры IO_STACK_LOCATION .
Диспетчер ввода-вывода создает массив расположений стека ввода-вывода для каждой IRP с элементом массива, соответствующим каждому драйверу в цепочке многоуровневых драйверов. Каждый драйвер владеет одним из расположений стека в пакете и вызывает IoGetCurrentIrpStackLocation для получения сведений об операции ввода-вывода для конкретного драйвера.
Каждый драйвер в такой цепочке отвечает за вызов IoGetNextIrpStackLocation, а затем за настройку расположения стека ввода-вывода следующего драйвера ниже. Любое расположение стека ввода-вывода драйвера более высокого уровня также можно использовать для хранения контекста об операции, чтобы подпрограмма IoCompletion драйвера могли выполнять операции очистки.
На рисунке Обработка IRP в многоуровневых драйверах показаны два расположения стека ввода-вывода в исходной IRP, так как на нем показаны два драйвера: драйвер файловой системы и драйвер запоминающего устройства. Выделенные драйверами IRP на рисунке Обработка irPs на рисунке Многоуровневые драйверы не имеют расположения стека для FSD (драйвер файловой системы), который их создал. Любой драйвер более высокого уровня, который выделяет IRP для драйверов более низкого уровня, также определяет, сколько расположений стека ввода-вывода должно быть у новых IRP, в соответствии со значением StackSize объекта устройства следующего ниже драйвера.
На следующем рисунке более подробно показано содержимое IRP.
Как показано на рисунке, каждое расположение стека ввода-вывода для конкретного драйвера в IRP содержит следующие общие сведения:
Код основной функции (IRP_MJ_XXX), указывающий базовую операцию, выполняемую драйвером.
Для некоторых основных кодов функций, обрабатываемых FSD, драйверов SCSI более высокого уровня и всех драйверов PnP, дополнительный код функции (IRP_MN_XXX), указывающий, какой подкатауар базовой операции должен выполнять драйвер.
Набор аргументов для конкретных операций, таких как длина и начальное расположение буфера, в который или из которого драйвер передает данные.
Указатель на созданный драйвером объект устройства, представляющий целевое (физическое, логическое или виртуальное) устройство для запрошенной операции.
Указатель на объект file, представляющий открытый файл, устройство, каталог или том.
Драйвер файловой системы обращается к объекту файла через расположение стека ввода-вывода в IRP. Другие драйверы обычно игнорируют объект file.
Набор основных и дополнительных кодов функций 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" на рисунке "Многоуровневые драйверы ", также будет содержать другое расположение стека ввода-вывода для такого нового зеркального драйвера.
Обратите внимание, что эта поддержка добавления новых драйверов в существующую цепочку подразумевает определенные ограничения на доступ любого конкретного драйвера к расположениям стека ввода-вывода в IRP:
Драйвер более высокого уровня в цепочке многоуровневых драйверов может безопасно получать доступ только к расположениям стека ввода-вывода драйвера следующего и более низкого уровня в любом IRP. Такой драйвер должен настроить расположение стека ввода-вывода для драйвера следующего нижнего уровня в IRP. Однако при проектировании такого драйвера более высокого уровня невозможно предсказать, когда (или будет ли) добавлен новый драйвер в существующую цепочку сразу после драйвера.
Поэтому следует предположить, что любой добавленный впоследствии драйвер будет обрабатывать те же коды основных функций IRP (IRP_MJ_XXX), что и перемещенный драйвер следующего уровня.
Драйвер самого низкого уровня в цепочке многоуровневых драйверов может безопасно получать доступ только к собственному расположению стека ввода-вывода в любом IRP. При проектировании такого драйвера невозможно предсказать, когда (или будет ли) добавлен новый драйвер в существующую цепочку над драйвером устройства.
При проектировании драйвера самого низкого уровня предположим, что драйвер может продолжать обрабатывать IRP, используя информацию, передаваемую в его собственном расположении стека ввода-вывода, независимо от исходного источника данной IRP и сколько бы драйверов ни было наложено на него.