Пакет запроса ввода-вывода¶
Пакет запроса ввода-вывода (IRP, от англ. I/O Request Packet) — это структура данных в операционных системах семейства Windows, используемая для передачи запросов на операции ввода-вывода (I/O) между компонентами системы: приложениями, драйверами и устройствами. IRP является ключевым элементом модели ввода-вывода Windows, обеспечивая унифицированный механизм обработки всех типов операций — чтения, записи, управления устройством, создания и закрытия файлов.
¶История и происхождение
Концепция пакетов запросов ввода-вывода была разработана корпорацией Microsoft при создании операционной системы Windows NT, первая версия которой вышла в 1993 году. До этого, в MS-DOS и ранних версиях Windows, взаимодействие с устройствами было более примитивным и часто обходило системные механизмы, что приводило к проблемам с безопасностью и стабильностью. Архитектура Windows NT, основанная на микроядре и слоях драйверов, потребовала формализованного и иерархического подхода к управлению вводом-выводом. IRP стал стандартным контейнером для передачи команд и данных между менеджером ввода-вывода (I/O Manager), драйверами устройств и самими устройствами. С тех пор модель IRP остаётся основой подсистемы ввода-вывода во всех последующих версиях Windows, включая Windows 10 и Windows 11, а также в серверных редакциях (Windows Server).
¶Структура и компоненты
Пакет запроса ввода-вывода представляет собой сложную структуру данных, определённую в заголовочном файле wdm.h (Windows Driver Model). Она состоит из двух основных частей: фиксированного заголовка и переменной части, содержащей параметры, специфичные для типа операции.
¶Фиксированная часть
Фиксированная часть IRP содержит общие поля, необходимые для обработки любого запроса:
- Тип запроса (MajorFunctionCode) — определяет основную операцию (например, IRP_MJ_READ, IRP_MJ_WRITE, IRP_MJ_DEVICE_CONTROL).
- Размер и флаги — указывают на состояние пакета (например, ожидание завершения, возможность отмены).
- Указатели на связанные структуры — включают ссылки на объект файла (FileObject), устройство (DeviceObject) и драйвер, обрабатывающий запрос.
- Статус завершения (IoStatus) — поле, в которое драйвер записывает код результата (например, STATUS_SUCCESS, STATUS_PENDING, STATUS_ACCESS_DENIED).
- Пользовательский буфер — адрес в памяти пользовательского режима, куда или откуда передаются данные.
¶Переменная часть
Переменная часть IRP зависит от кода основной функции. Она содержит дополнительные параметры, такие как:
- Для чтения/записи: длина передаваемых данных, смещение в файле, ключ блокировки.
- Для управления устройством (IOCTL): код управляющей команды, размеры входного и выходного буферов.
- Для создания/закрытия: атрибуты доступа, режим создания.
Кроме того, IRP может содержать стековые ячейки (I/O Stack Locations) — массив структур, каждая из которых соответствует одному драйверу в цепочке обработки. Каждый драйвер в стеке драйверов использует свою ячейку для хранения локальных параметров и указателей.
¶Жизненный цикл
Процесс обработки IRP проходит несколько этапов, начиная с его создания и заканчивая освобождением памяти.
¶Создание
IRP создаётся менеджером ввода-вывода (I/O Manager) в ответ на запрос от пользовательского приложения (например, вызов функции ReadFile или WriteFile). Также IRP может быть создан драйвером для собственных нужд (например, для отправки запроса нижележащему драйверу). Создание происходит в невытесняемом контексте (IRQL = DISPATCH_LEVEL или ниже) и требует выделения памяти из пула ядра.
¶Отправка
После создания IRP передаётся в стек драйверов. Обычно первый драйвер в стеке — драйвер файловой системы (если операция связана с файлом), затем драйвер диспетчера томов и, наконец, драйвер устройства. Каждый драйвер обрабатывает запрос, выполняя необходимые действия (проверку прав, преобразование данных, взаимодействие с оборудованием) и либо завершает его, либо передаёт дальше.
¶Обработка
Драйвер может обработать IRP синхронно или асинхронно. При синхронной обработке драйвер сразу выполняет операцию и завершает IRP. При асинхронной — драйвер возвращает статус STATUS_PENDING, откладывая завершение на будущее (например, до получения прерывания от устройства). В этом случае IRP остаётся в памяти до момента завершения операции.
¶Завершение
Когда драйвер завершает обработку, он вызывает функцию IoCompleteRequest, которая:
- Записывает код результата в поле
IoStatus. - Уведомляет менеджер ввода-вывода о завершении.
- Выполняет действия по очистке (например, копирование данных из буфера ядра в буфер пользователя).
- Освобождает память, занятую IRP.
После этого управление возвращается к приложению, которое получает результат операции.
¶Типы и классификация
IRP классифицируются по нескольким признакам.
¶По основной функции
Наиболее распространённые коды основных функций:
- IRP_MJ_CREATE — открытие или создание файла/устройства.
- IRP_MJ_CLOSE — закрытие дескриптора.
- IRP_MJ_READ — чтение данных.
- IRP_MJ_WRITE — запись данных.
- IRP_MJ_DEVICE_CONTROL — выполнение управляющей команды (IOCTL).
- IRP_MJ_INTERNAL_DEVICE_CONTROL — внутренняя команда для драйверов.
- IRP_MJ_FLUSH_BUFFERS — сброс буферов на устройство.
- IRP_MJ_SHUTDOWN — завершение работы системы.
¶По способу передачи данных
- Буферизированный ввод-вывод (Buffered I/O) — данные копируются между пользовательским и системным буферами. Используется для небольших объёмов данных.
- Прямой ввод-вывод (Direct I/O) — данные передаются напрямую между пользовательской памятью и устройством с использованием DMA (Direct Memory Access). Требует блокировки страниц памяти.
- Ввод-вывод без буферизации (Neither I/O) — драйвер сам управляет доступом к пользовательской памяти. Используется редко, в основном в высокопроизводительных драйверах.
¶Роль в архитектуре Windows
IRP является центральным элементом модели ввода-вывода Windows. Он обеспечивает:
- Абстракцию устройств — приложения работают с унифицированными дескрипторами, а драйверы преобразуют IRP в команды для конкретного оборудования.
- Многоуровневую обработку — IRP может проходить через несколько драйверов, каждый из которых добавляет свою функциональность (например, шифрование, кэширование, фильтрацию).
- Асинхронность — поддержка отложенных операций без блокировки вызывающего потока.
- Безопасность — проверка прав доступа на этапе создания IRP.
¶Примеры использования
- Файловые операции: при вызове
ReadFileв приложении менеджер ввода-вывода создаёт IRP_MJ_READ, который передаётся драйверу файловой системы (например, NTFS), затем драйверу диспетчера томов и, наконец, драйверу жёсткого диска. - Управление устройствами: при отправке IOCTL (например, для изменения параметров USB-устройства) создаётся IRP_MJ_DEVICE_CONTROL.
- Сетевые операции: драйверы сетевых протоколов (TCP/IP) используют IRP для передачи пакетов между стеком протоколов и сетевым адаптером.
¶Критика и ограничения
Несмотря на гибкость, модель IRP имеет ряд недостатков:
- Сложность — разработка драйверов, корректно обрабатывающих IRP, требует глубоких знаний архитектуры Windows и управления памятью.
- Накладные расходы — создание и уничтожение IRP, а также копирование данных при буферизированном вводе-выводе могут снижать производительность.
- Ограниченная масштабируемость — в системах с большим числом одновременных запросов (например, высоконагруженные серверы) менеджер ввода-вывода может стать узким местом.
В современных версиях Windows Microsoft стремится оптимизировать обработку IRP, вводя новые механизмы, такие как I/O Ring (в Windows 10 версии 2004 и выше), которые позволяют группировать несколько запросов для снижения накладных расходов.
¶Источники
- Microsoft Docs: "I/O Request Packets" (Windows Driver Kit documentation)
- "Windows Internals, Part 1" by Pavel Yosifovich, Mark E. Russinovich, David A. Solomon, Alex Ionescu (7th edition, 2021)
- "Developing Windows Device Drivers" by Walter Oney (2003)
- MSDN Magazine: "Inside the Windows I/O System" (2008)
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →


