Пакет запроса ввода/вывода (IRP)
Характеристики подсистемы ввода/вывода
В предыдущем разделе мы рассмотрели схему использования системных сервисов, то есть прохождение запроса ввода/вывода от приложения к драйверу и обратно. Компонентом ОС, отвечающим за реализацию этой схемы, является Диспетчер ввода/ вывода. Диспетчер ввода/вывода является компонентом более общей модели – подсистемы ввода/вывода. Подсистема ввода/вывода включает в себя все компоненты, которые обеспечивают возможность осуществления ввода/вывода. В число этих компонент входит Диспетчер ввода/вывода и все драйверы режима ядра. В числе характеристик подсистемы ввода/вывода NT принято выделять следующие:
- согласованность и высокая структурированность;
- переносимость между процессорными архитектурами;
- конфигурируемость;
- вытесняемость и прерываемость;
- поддержка многопроцессорности;
- объектная базированность (но не объектная ориентированность);
- асинхронность;
- подсистема ввода/вывода управляется пакетами;
- подсистема ввода/вывода многоуровневая (послойная модель).
Как уже говорилось, подсистема ввода/вывода NT управляется пакетами. При таком подходе каждый запрос ввода/вывода описывается своим собственным пакетом запроса ввода/вывода (I/O Request Packet – IRP). При задействовании системного сервиса (например, при запросе на чтение или запись в файл) Диспетчер ввода/вывода обрабатывает этот запрос путем создания пакета IRP, Описывающего запрос, и затем передает указатель на этот пакет драйверу для обработки.
Структура пакета запроса ввода/вывода (IRP)
При осуществлении операции ввода/вывода диспетчер ввода/вывода создает специальный пакет, описывающий эту операцию – пакет запроса ввода/вывода (I/O Request Packet, IRP). Как будет показано ниже, обработка такого пакета может происходить поэтапно несколькими объектами-устройствами.
IRP содержит всю необходимую информацию для полного описания запроса Ввода – вывода Диспетчеру Ввода/вывода и драйверам устройств. IRP описывается стандартной структурой типа "IRP", показанной на рис. 10.
Структура IRP специально разработана для поддержки многоуровневой модели ввода/вывода, при которой запрос ввода/вывода последовательно обрабатывается стеком из нескольких драйверов.
Для обеспечения этого каждый пакет запроса ввода/вывода состоит из двух частей: "фиксированной" части и Стека Ввода/вывода. Фиксированная часть IRP содержит информацию относительно той части запроса, которая или не изменяется от драйвера к драйверу, или которую не надо сохранять при передаче IRP от одного драйвера к другому. Стек Ввода/вывода содержит набор Стеков Размещения Ввода/вывода, каждый из которых содержит информацию, специфическую для каждого драйвера, который может обрабатывать запрос.
В стеке размещения ввода/вывода для каждого устройства, которое должно принимать участие в обработке пакета, содержатся указатели на объект-устройство, которое будет обрабатывать запрос, и на объект-файл, для которого была инициирована операция ввода/вывода (см. рис. 10).
Пакеты IRP всегда выделяются из невыгружаемой системной памяти (nonpaged pool), поэтому к ним может осуществляться обращение из функций, работающих на любом уровне IRQL.
Как уже говорилось, драйверы подразделяются на три класса по их положению в стеке драйверов: драйверы высшего уровня, драйверы промежуточного уровня и драйверы низшего уровня.
Драйвер высшего уровня – это верхний драйвер в стеке драйверов, получающий запросы через Диспетчер ввода/вывода от компонентов прикладного уровня.
Драйвер высшего уровня (или, что более правильно, устройство высшего уровня) имеет один или несколько стеков размещения ввода/вывода.
Число стеков размещения ввода/вывода устанавливается Диспетчером ввода/вывода в поле StackSize объекта-устройства. По умолчанию это значение равно 1. Присваивание происходит при создании устройства функцией IoCreateDevice(). Если вы создаете многоуровневый драйвер, вы должны установить StackSize на 1 больше, чем StackSize объекта-устройства, над которым будете размещать свое устройство. В случае, если ваше устройство будет использовать больше одного устройства уровнем ниже, поле StackSize этого устройства должно быть на 1 больше максимального значения StackSize из всех устройств уровнем ниже.
Рис. 10. Указатели на объект-устройство и на объект-файл