Открыть сервис

Пакет запроса ввода-вывода

Пакет запроса ввода-вывода (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, которая:

  1. Записывает код результата в поле IoStatus.
  2. Уведомляет менеджер ввода-вывода о завершении.
  3. Выполняет действия по очистке (например, копирование данных из буфера ядра в буфер пользователя).
  4. Освобождает память, занятую 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 →